@eryxenx/fca 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/CHANGELOG.md +325 -0
  2. package/DOCS.md +2712 -0
  3. package/README.md +455 -0
  4. package/func/checkUpdate.js +7 -0
  5. package/func/logAdapter.js +33 -0
  6. package/func/logger.js +48 -0
  7. package/index.d.ts +751 -0
  8. package/index.js +22 -0
  9. package/module/config.js +40 -0
  10. package/module/login.js +133 -0
  11. package/module/loginHelper.js +1365 -0
  12. package/module/options.js +44 -0
  13. package/package.json +98 -0
  14. package/src/api/action/addExternalModule.js +25 -0
  15. package/src/api/action/changeAvatar.js +137 -0
  16. package/src/api/action/changeBio.js +75 -0
  17. package/src/api/action/enableAutoSaveAppState.js +73 -0
  18. package/src/api/action/getCurrentUserID.js +7 -0
  19. package/src/api/action/handleFriendRequest.js +57 -0
  20. package/src/api/action/logout.js +76 -0
  21. package/src/api/action/refreshFb_dtsg.js +48 -0
  22. package/src/api/action/setPostReaction.js +106 -0
  23. package/src/api/action/unfriend.js +54 -0
  24. package/src/api/http/httpGet.js +46 -0
  25. package/src/api/http/httpPost.js +52 -0
  26. package/src/api/http/postFormData.js +47 -0
  27. package/src/api/messaging/addUserToGroup.js +68 -0
  28. package/src/api/messaging/changeAdminStatus.js +126 -0
  29. package/src/api/messaging/changeArchivedStatus.js +55 -0
  30. package/src/api/messaging/changeBlockedStatus.js +48 -0
  31. package/src/api/messaging/changeGroupImage.js +91 -0
  32. package/src/api/messaging/changeNickname.js +70 -0
  33. package/src/api/messaging/changeThreadColor.js +79 -0
  34. package/src/api/messaging/changeThreadEmoji.js +111 -0
  35. package/src/api/messaging/createNewGroup.js +88 -0
  36. package/src/api/messaging/createPoll.js +46 -0
  37. package/src/api/messaging/createThemeAI.js +98 -0
  38. package/src/api/messaging/deleteMessage.js +136 -0
  39. package/src/api/messaging/deleteThread.js +56 -0
  40. package/src/api/messaging/editMessage.js +105 -0
  41. package/src/api/messaging/forwardAttachment.js +57 -0
  42. package/src/api/messaging/forwardMessage.js +134 -0
  43. package/src/api/messaging/getEmojiUrl.js +29 -0
  44. package/src/api/messaging/getFriendsList.js +82 -0
  45. package/src/api/messaging/getMessage.js +829 -0
  46. package/src/api/messaging/getThemePictures.js +62 -0
  47. package/src/api/messaging/handleMessageRequest.js +65 -0
  48. package/src/api/messaging/markAsDelivered.js +57 -0
  49. package/src/api/messaging/markAsRead.js +88 -0
  50. package/src/api/messaging/markAsReadAll.js +56 -0
  51. package/src/api/messaging/markAsSeen.js +68 -0
  52. package/src/api/messaging/muteThread.js +50 -0
  53. package/src/api/messaging/pinMessage.js +115 -0
  54. package/src/api/messaging/removeUserFromGroup.js +62 -0
  55. package/src/api/messaging/resolvePhotoUrl.js +43 -0
  56. package/src/api/messaging/scheduler.js +264 -0
  57. package/src/api/messaging/searchForThread.js +53 -0
  58. package/src/api/messaging/sendBroadcast.js +93 -0
  59. package/src/api/messaging/sendMessage.js +269 -0
  60. package/src/api/messaging/sendTypingIndicator.js +90 -0
  61. package/src/api/messaging/sessionGuard.js +130 -0
  62. package/src/api/messaging/setMessageReaction.js +109 -0
  63. package/src/api/messaging/setTitle.js +124 -0
  64. package/src/api/messaging/shareContact.js +98 -0
  65. package/src/api/messaging/threadColors.js +128 -0
  66. package/src/api/messaging/unsendMessage.js +105 -0
  67. package/src/api/messaging/uploadAttachment.js +492 -0
  68. package/src/api/socket/OldMessage.js +186 -0
  69. package/src/api/socket/core/connectMqtt.js +269 -0
  70. package/src/api/socket/core/emitAuth.js +103 -0
  71. package/src/api/socket/core/getSeqID.js +321 -0
  72. package/src/api/socket/core/getTaskResponseData.js +25 -0
  73. package/src/api/socket/core/parseDelta.js +387 -0
  74. package/src/api/socket/detail/buildStream.js +215 -0
  75. package/src/api/socket/detail/constants.js +28 -0
  76. package/src/api/socket/e2ee/crypto.js +173 -0
  77. package/src/api/socket/e2ee/index.js +925 -0
  78. package/src/api/socket/e2ee/localMediaServer.js +59 -0
  79. package/src/api/socket/e2ee/mediaDecode.js +155 -0
  80. package/src/api/socket/e2ee/native/NOTICE.md +29 -0
  81. package/src/api/socket/e2ee/native/build/messagix.dll +0 -0
  82. package/src/api/socket/e2ee/native/build/messagix.so +0 -0
  83. package/src/api/socket/e2ee/native/lib/index.mjs +1426 -0
  84. package/src/api/socket/e2ee/native/nativeMediaBridge.js +233 -0
  85. package/src/api/socket/e2ee/proto/ArmadilloApplication.proto +281 -0
  86. package/src/api/socket/e2ee/proto/ArmadilloICDC.proto +14 -0
  87. package/src/api/socket/e2ee/proto/ConsumerApplication.proto +232 -0
  88. package/src/api/socket/e2ee/proto/MessageApplication.proto +82 -0
  89. package/src/api/socket/e2ee/proto/MessageTransport.proto +77 -0
  90. package/src/api/socket/e2ee/proto/WACommon.proto +66 -0
  91. package/src/api/socket/e2ee/proto/WAMediaTransport.proto +176 -0
  92. package/src/api/socket/e2ee/proto/proto-writer.ts +76 -0
  93. package/src/api/socket/e2ee/protocol.js +196 -0
  94. package/src/api/socket/e2ee/ratchet.js +219 -0
  95. package/src/api/socket/e2ee/store.js +182 -0
  96. package/src/api/socket/e2ee/vendor/fme/dist/index.cjs +6477 -0
  97. package/src/api/socket/e2ee/vendor/fme/proto/ArmadilloApplication.proto +281 -0
  98. package/src/api/socket/e2ee/vendor/fme/proto/ArmadilloICDC.proto +14 -0
  99. package/src/api/socket/e2ee/vendor/fme/proto/ConsumerApplication.proto +232 -0
  100. package/src/api/socket/e2ee/vendor/fme/proto/MessageApplication.proto +82 -0
  101. package/src/api/socket/e2ee/vendor/fme/proto/MessageTransport.proto +77 -0
  102. package/src/api/socket/e2ee/vendor/fme/proto/WACommon.proto +66 -0
  103. package/src/api/socket/e2ee/vendor/fme/proto/WAMediaTransport.proto +176 -0
  104. package/src/api/socket/listenE2EE.js +75 -0
  105. package/src/api/socket/listenMqtt.js +436 -0
  106. package/src/api/socket/middleware/index.js +216 -0
  107. package/src/api/socket/sendMessage.js +314 -0
  108. package/src/api/socket/sendMessageMqtt.js +69 -0
  109. package/src/api/threads/getThreadHistory.js +664 -0
  110. package/src/api/threads/getThreadInfo.js +329 -0
  111. package/src/api/threads/getThreadList.js +293 -0
  112. package/src/api/threads/getThreadPictures.js +78 -0
  113. package/src/api/users/getUserID.js +65 -0
  114. package/src/api/users/getUserInfo.js +402 -0
  115. package/src/api/users/getUserInfoV2.js +134 -0
  116. package/src/app/MessengerBot.js +209 -0
  117. package/src/app/MessengerContext.js +32 -0
  118. package/src/app/createFcaClient.js +136 -0
  119. package/src/app/threadInfoRealtimeSync.js +284 -0
  120. package/src/core/sendReqMqtt.js +96 -0
  121. package/src/database/helpers.js +53 -0
  122. package/src/database/models/index.js +88 -0
  123. package/src/database/models/thread.js +50 -0
  124. package/src/database/models/user.js +46 -0
  125. package/src/database/threadData.js +94 -0
  126. package/src/database/userData.js +98 -0
  127. package/src/remote/remoteClient.js +123 -0
  128. package/src/utils/broadcast.js +51 -0
  129. package/src/utils/client.js +10 -0
  130. package/src/utils/constants.js +23 -0
  131. package/src/utils/cookies.js +68 -0
  132. package/src/utils/format/attachment.js +357 -0
  133. package/src/utils/format/cookie.js +9 -0
  134. package/src/utils/format/date.js +50 -0
  135. package/src/utils/format/decode.js +44 -0
  136. package/src/utils/format/delta.js +194 -0
  137. package/src/utils/format/ids.js +64 -0
  138. package/src/utils/format/index.js +64 -0
  139. package/src/utils/format/message.js +88 -0
  140. package/src/utils/format/presence.js +132 -0
  141. package/src/utils/format/readTyp.js +44 -0
  142. package/src/utils/format/thread.js +42 -0
  143. package/src/utils/format/utils.js +141 -0
  144. package/src/utils/headers.js +128 -0
  145. package/src/utils/loginParser/autoLogin.js +125 -0
  146. package/src/utils/loginParser/helpers.js +43 -0
  147. package/src/utils/loginParser/index.js +10 -0
  148. package/src/utils/loginParser/parseAndCheckLogin.js +220 -0
  149. package/src/utils/loginParser/textUtils.js +28 -0
  150. package/src/utils/nexca-logger.js +144 -0
  151. package/src/utils/nexca-utils.js +686 -0
  152. package/src/utils/request/client.js +26 -0
  153. package/src/utils/request/config.js +23 -0
  154. package/src/utils/request/defaults.js +46 -0
  155. package/src/utils/request/helpers.js +46 -0
  156. package/src/utils/request/index.js +17 -0
  157. package/src/utils/request/methods.js +163 -0
  158. package/src/utils/request/proxy.js +21 -0
  159. package/src/utils/request/retry.js +77 -0
  160. package/src/utils/request/sanitize.js +49 -0
  161. package/src/utils/versionCheck.js +47 -0
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+
3
+ function generateOfflineThreadingId() {
4
+ const now = Date.now();
5
+ const rand = Math.floor(Math.random() * 4294967295);
6
+ return String((BigInt(now) << BigInt(22)) | BigInt(rand & 0x3FFFFF));
7
+ }
8
+
9
+ module.exports = function (defaultFuncs, api, ctx) {
10
+ return function editMessage(text, messageID, callback) {
11
+ let resolveFunc = () => {};
12
+ let rejectFunc = () => {};
13
+ const returnPromise = new Promise((resolve, reject) => {
14
+ resolveFunc = resolve;
15
+ rejectFunc = reject;
16
+ });
17
+
18
+ if (!callback) {
19
+ callback = (err, data) => {
20
+ if (err) return rejectFunc(err);
21
+ resolveFunc(data);
22
+ };
23
+ }
24
+
25
+ if (!messageID || !text) {
26
+ callback({ error: "messageID and text are required." });
27
+ return returnPromise;
28
+ }
29
+
30
+ const threadID = api.e2ee && typeof api.e2ee.getThreadIdForMessage === "function"
31
+ ? api.e2ee.getThreadIdForMessage(messageID) : null;
32
+ const isE2EEDM = threadID && ctx.threadTypes && ctx.threadTypes[String(threadID)] === 'dm' &&
33
+ api.e2ee && typeof api.e2ee.isConnected === "function" && api.e2ee.isConnected();
34
+ const isE2EEGroup = threadID && typeof api.e2ee?.isKnownE2EEGroup === "function" && api.e2ee.isKnownE2EEGroup(String(threadID)) &&
35
+ api.e2ee && typeof api.e2ee.isConnected === "function" && api.e2ee.isConnected();
36
+ const isE2EEThread = isE2EEDM || isE2EEGroup;
37
+
38
+ if (isE2EEThread) {
39
+ api.e2ee.editMessage(String(threadID), messageID, text)
40
+ .then((result) => callback(undefined, result))
41
+ .catch((err) => callback(err));
42
+ return returnPromise;
43
+ }
44
+
45
+ if (!ctx.mqttClient) {
46
+ callback({ error: "Not connected to MQTT" });
47
+ return returnPromise;
48
+ }
49
+
50
+ ctx.wsReqNumber += 1;
51
+ ctx.wsTaskNumber += 1;
52
+
53
+ const reqID = ctx.wsReqNumber;
54
+
55
+ const context = {
56
+ app_id: "2220391788200892",
57
+ payload: JSON.stringify({
58
+ data_trace_id: null,
59
+ epoch_id: parseInt(generateOfflineThreadingId()),
60
+ tasks: [{
61
+ failure_count: null,
62
+ label: "742",
63
+ payload: JSON.stringify({
64
+ message_id: messageID,
65
+ text: text,
66
+ }),
67
+ queue_name: "edit_message",
68
+ task_id: ctx.wsTaskNumber,
69
+ }],
70
+ version_id: "6903494529735864",
71
+ }),
72
+ request_id: reqID,
73
+ type: 3
74
+ };
75
+
76
+ ctx.mqttClient.publish("/ls_req", JSON.stringify(context), { qos: 1, retain: false });
77
+
78
+ const timeout = setTimeout(() => {
79
+ ctx.mqttClient.removeListener("message", handleRes);
80
+ resolveFunc({ messageID, body: text });
81
+ }, 5000);
82
+
83
+ const handleRes = (topic, message) => {
84
+ if (topic !== "/ls_resp") return;
85
+ try {
86
+ let jsonMsg = JSON.parse(message.toString());
87
+ if (!jsonMsg.payload) return;
88
+ jsonMsg.payload = JSON.parse(jsonMsg.payload);
89
+ if (jsonMsg.request_id != reqID) return;
90
+
91
+ clearTimeout(timeout);
92
+ ctx.mqttClient.removeListener("message", handleRes);
93
+
94
+ callback(undefined, { messageID, body: text });
95
+ } catch (e) {
96
+ clearTimeout(timeout);
97
+ ctx.mqttClient.removeListener("message", handleRes);
98
+ callback(undefined, { messageID, body: text });
99
+ }
100
+ };
101
+
102
+ ctx.mqttClient.on("message", handleRes);
103
+ return returnPromise;
104
+ };
105
+ };
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+
3
+ const { generateOfflineThreadingID } = require("../../utils/format");
4
+
5
+ module.exports = function (defaultFuncs, api, ctx) {
6
+ return async function forwardMessage(threadID, forwardedMsgID, callback) {
7
+ let resolveFunc, rejectFunc;
8
+ const returnPromise = new Promise((resolve, reject) => {
9
+ resolveFunc = resolve;
10
+ rejectFunc = reject;
11
+ });
12
+ if (!callback) {
13
+ callback = (err, data) => {
14
+ if (err) return rejectFunc(err);
15
+ resolveFunc(data);
16
+ };
17
+ }
18
+ if (!ctx.mqttClient) {
19
+ const err = new Error("Not connected to MQTT");
20
+ callback?.(err);
21
+ rejectFunc(err);
22
+ return returnPromise;
23
+ }
24
+ let count_req = 0
25
+ const payload = {
26
+ epoch_id: generateOfflineThreadingID(),
27
+ tasks: [
28
+ {
29
+ failure_count: null,
30
+ label: "46",
31
+ payload: JSON.stringify({
32
+ thread_id: threadID,
33
+ otid: generateOfflineThreadingID(),
34
+ source: 65544,
35
+ send_type: 5,
36
+ sync_group: 1,
37
+ mark_thread_read: 0,
38
+ forwarded_msg_id: forwardedMsgID,
39
+ strip_forwarded_msg_caption: 0,
40
+ initiating_source: 1
41
+ }),
42
+ queue_name: threadID,
43
+ task_id: Math.floor(Math.random() * 1001)
44
+ }
45
+ ],
46
+ version_id: "8768858626531631"
47
+ };
48
+ const form = JSON.stringify({
49
+ app_id: "772021112871879",
50
+ payload: JSON.stringify(payload),
51
+ "request_id": ++count_req,
52
+ "type": 3
53
+ });
54
+ ctx.mqttClient.publish("/ls_req", form);
55
+ return returnPromise;
56
+ };
57
+ };
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+
3
+ const { generateOfflineThreadingID } = require("../../utils/format");
4
+
5
+ /**
6
+ * Forward a message to one or multiple threads.
7
+ * @param {string} messageID - The ID of the message to forward.
8
+ * @param {string|string[]} threadID - Thread ID or array of thread IDs to forward to.
9
+ * @param {function} [callback] - Optional callback(err, results).
10
+ * @returns {Promise}
11
+ */
12
+ module.exports = function (defaultFuncs, api, ctx) {
13
+ return async function forwardMessage(messageID, threadID, callback) {
14
+ let resolveFunc, rejectFunc;
15
+ const returnPromise = new Promise((resolve, reject) => {
16
+ resolveFunc = resolve;
17
+ rejectFunc = reject;
18
+ });
19
+
20
+ if (!callback) {
21
+ callback = (err, data) => {
22
+ if (err) return rejectFunc(err);
23
+ resolveFunc(data);
24
+ };
25
+ }
26
+
27
+ if (!messageID || !threadID) {
28
+ const err = { error: "messageID and threadID are required." };
29
+ callback(err);
30
+ return returnPromise;
31
+ }
32
+
33
+ if (!ctx.mqttClient || !ctx.mqttClient.connected) {
34
+ const err = { error: "Not connected to MQTT. Please try again later." };
35
+ callback(err);
36
+ return returnPromise;
37
+ }
38
+
39
+ // Support forwarding to multiple threads
40
+ const targets = Array.isArray(threadID) ? threadID : [threadID];
41
+
42
+ const results = [];
43
+ const errors = [];
44
+
45
+ for (const tid of targets) {
46
+ try {
47
+ await new Promise((res, rej) => {
48
+ const reqID = ++ctx.wsReqNumber;
49
+ const taskID = ++ctx.wsTaskNumber;
50
+
51
+ const taskPayload = {
52
+ thread_id: String(tid),
53
+ otid: generateOfflineThreadingID(),
54
+ source: 65544,
55
+ send_type: 5,
56
+ sync_group: 1,
57
+ mark_thread_read: 0,
58
+ forwarded_msg_id: String(messageID),
59
+ strip_forwarded_msg_caption: 0,
60
+ initiating_source: 1
61
+ };
62
+
63
+ const content = {
64
+ app_id: "2220391788200892",
65
+ payload: JSON.stringify({
66
+ data_trace_id: null,
67
+ epoch_id: String((BigInt(Date.now()) << 22n)),
68
+ tasks: [
69
+ {
70
+ failure_count: null,
71
+ label: "46",
72
+ payload: JSON.stringify(taskPayload),
73
+ queue_name: String(tid),
74
+ task_id: taskID
75
+ }
76
+ ],
77
+ version_id: "6903494529735864"
78
+ }),
79
+ request_id: reqID,
80
+ type: 3
81
+ };
82
+
83
+ try {
84
+ ctx.mqttClient.publish("/ls_req", JSON.stringify(content), { qos: 1, retain: false });
85
+ } catch (err) {
86
+ errors.push({ threadID: tid, error: err.message || String(err) });
87
+ return res(); // continue to next thread
88
+ }
89
+
90
+ const timeout = setTimeout(() => {
91
+ ctx.mqttClient.removeListener("message", handleRes);
92
+ errors.push({ threadID: tid, error: "forwardMessage timed out." });
93
+ res();
94
+ }, 15000);
95
+
96
+ const handleRes = (topic, message) => {
97
+ if (topic !== "/ls_resp") return;
98
+ try {
99
+ let jsonMsg = JSON.parse(message.toString());
100
+ if (!jsonMsg.payload) return;
101
+ jsonMsg.payload = JSON.parse(jsonMsg.payload);
102
+ if (jsonMsg.request_id !== reqID) return;
103
+
104
+ clearTimeout(timeout);
105
+ ctx.mqttClient.removeListener("message", handleRes);
106
+
107
+ results.push({ threadID: tid, messageID: String(messageID) });
108
+ res();
109
+ } catch (err) {
110
+ clearTimeout(timeout);
111
+ ctx.mqttClient.removeListener("message", handleRes);
112
+ errors.push({ threadID: tid, error: err.message || String(err) });
113
+ res();
114
+ }
115
+ };
116
+
117
+ ctx.mqttClient.on("message", handleRes);
118
+ });
119
+ } catch (err) {
120
+ errors.push({ threadID: tid, error: err.message || String(err) });
121
+ }
122
+ }
123
+
124
+ const finalResult = { success: results, failed: errors };
125
+
126
+ if (errors.length > 0 && results.length === 0) {
127
+ callback({ error: "All forwards failed.", details: errors });
128
+ } else {
129
+ callback(null, finalResult);
130
+ }
131
+
132
+ return returnPromise;
133
+ };
134
+ };
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ const util = require("util");
4
+
5
+ module.exports = function() {
6
+ return function getEmojiUrl(c, size, pixelRatio) {
7
+ /*
8
+ Resolves Facebook Messenger emoji image asset URL for an emoji character.
9
+ Supported sizes are 32, 64, and 128.
10
+ Supported pixel ratios are '1.0' and '1.5' (possibly more; haven't tested)
11
+ */
12
+ const baseUrl = "https://static.xx.fbcdn.net/images/emoji.php/v8/z%s/%s";
13
+ pixelRatio = pixelRatio || "1.0";
14
+
15
+ const ending = util.format(
16
+ "%s/%s/%s.png",
17
+ pixelRatio,
18
+ size,
19
+ c.codePointAt(0).toString(16)
20
+ );
21
+ let base = 317426846;
22
+ for (let i = 0; i < ending.length; i++) {
23
+ base = (base << 5) - base + ending.charCodeAt(i);
24
+ }
25
+
26
+ const hashed = (base & 255).toString(16);
27
+ return util.format(baseUrl, hashed, ending);
28
+ };
29
+ };
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+
3
+ const { formatID } = require("../../utils/format");
4
+ const log = require("../../../func/logAdapter");
5
+ const { parseAndCheckLogin } = require("../../utils/client");
6
+ const GENDERS = {
7
+ 0: "unknown",
8
+ 1: "female_singular",
9
+ 2: "male_singular",
10
+ 3: "female_singular_guess",
11
+ 4: "male_singular_guess",
12
+ 5: "mixed",
13
+ 6: "neuter_singular",
14
+ 7: "unknown_singular",
15
+ 8: "female_plural",
16
+ 9: "male_plural",
17
+ 10: "neuter_plural",
18
+ 11: "unknown_plural"
19
+ };
20
+
21
+ function formatData(obj) {
22
+ return Object.keys(obj).map(function(key) {
23
+ const user = obj[key];
24
+ return {
25
+ alternateName: user.alternateName,
26
+ firstName: user.firstName,
27
+ gender: GENDERS[user.gender],
28
+ userID: formatID(user.id.toString()),
29
+ isFriend: user.is_friend != null && user.is_friend ? true : false,
30
+ fullName: user.name,
31
+ profilePicture: user.thumbSrc,
32
+ type: user.type,
33
+ profileUrl: user.uri,
34
+ vanity: user.vanity,
35
+ isBirthday: !!user.is_birthday
36
+ };
37
+ });
38
+ }
39
+
40
+ module.exports = function(defaultFuncs, api, ctx) {
41
+ return function getFriendsList(callback) {
42
+ let resolveFunc = function() {};
43
+ let rejectFunc = function() {};
44
+ const returnPromise = new Promise(function(resolve, reject) {
45
+ resolveFunc = resolve;
46
+ rejectFunc = reject;
47
+ });
48
+
49
+ if (!callback) {
50
+ callback = function(err, friendList) {
51
+ if (err) {
52
+ return rejectFunc(err);
53
+ }
54
+ resolveFunc(friendList);
55
+ };
56
+ }
57
+
58
+ defaultFuncs
59
+ .postFormData(
60
+ "https://www.facebook.com/chat/user_info_all",
61
+ ctx.jar,
62
+ {},
63
+ { viewer: ctx.userID }
64
+ )
65
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
66
+ .then(function(resData) {
67
+ if (!resData) {
68
+ throw { error: "getFriendsList returned empty object." };
69
+ }
70
+ if (resData.error) {
71
+ throw resData;
72
+ }
73
+ callback(null, formatData(resData.payload));
74
+ })
75
+ .catch(function(err) {
76
+ log.error("getFriendsList", err);
77
+ return callback(err);
78
+ });
79
+
80
+ return returnPromise;
81
+ };
82
+ };