@cexy/hoonfca 1.0.0 → 1.0.2

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 (98) hide show
  1. package/.travis.yml +6 -0
  2. package/LICENSE-MIT +21 -0
  3. package/index.d.ts +620 -0
  4. package/index.js +745 -433
  5. package/package.json +45 -6
  6. package/src/addExternalModule.js +14 -16
  7. package/src/addUserToGroup.js +45 -30
  8. package/src/changeAdminStatus.js +39 -42
  9. package/src/changeApprovalMode.js +79 -0
  10. package/src/changeArchivedStatus.js +19 -15
  11. package/src/changeBio.js +18 -16
  12. package/src/changeBlockedStatus.js +14 -12
  13. package/src/changeBlockedStatusMqtt.js +38 -17
  14. package/src/changeGroupImage.js +100 -77
  15. package/src/changeNickname.js +12 -11
  16. package/src/changeThreadColor.js +25 -16
  17. package/src/changeThreadEmoji.js +11 -10
  18. package/src/createNewGroup.js +21 -14
  19. package/src/createPoll.js +87 -21
  20. package/src/deleteMessage.js +18 -17
  21. package/src/deleteThread.js +18 -17
  22. package/src/editMessage.js +28 -31
  23. package/src/forwardAttachment.js +22 -19
  24. package/src/forwardMessage.js +63 -0
  25. package/src/getCurrentUserID.js +4 -2
  26. package/src/getEmojiUrl.js +20 -9
  27. package/src/getFriendsList.js +21 -18
  28. package/src/getGroupsList.js +83 -0
  29. package/src/getMarketplace.js +84 -0
  30. package/src/getNotifications.js +86 -0
  31. package/src/getPagesList.js +83 -0
  32. package/src/getStories.js +88 -0
  33. package/src/getThreadHistory.js +277 -126
  34. package/src/getThreadInfo.js +143 -115
  35. package/src/getThreadList.js +216 -143
  36. package/src/getThreadPictures.js +26 -32
  37. package/src/getUserID.js +13 -14
  38. package/src/getUserInfo.js +107 -68
  39. package/src/handleFriendRequest.js +16 -15
  40. package/src/handleMessageRequest.js +15 -15
  41. package/src/httpGet.js +36 -31
  42. package/src/httpPost.js +36 -31
  43. package/src/listenMqtt.js +705 -370
  44. package/src/logout.js +26 -28
  45. package/src/markAsDelivered.js +22 -17
  46. package/src/markAsRead.js +63 -49
  47. package/src/markAsReadAll.js +17 -13
  48. package/src/markAsSeen.js +23 -19
  49. package/src/muteThread.js +17 -14
  50. package/src/pinMessage.js +23 -22
  51. package/src/removeUserFromGroup.js +42 -22
  52. package/src/resolvePhotoUrl.js +15 -17
  53. package/src/searchForThread.js +18 -20
  54. package/src/searchUsers.js +89 -0
  55. package/src/sendComment.js +161 -0
  56. package/src/sendMessage.js +65 -52
  57. package/src/sendTypingIndicator.js +173 -48
  58. package/src/setBio.js +86 -0
  59. package/src/setMessageReaction.js +76 -16
  60. package/src/setPostReaction.js +29 -61
  61. package/src/setTheme.js +313 -0
  62. package/src/setTitle.js +27 -37
  63. package/src/shareContact.js +34 -82
  64. package/src/shareLink.js +56 -99
  65. package/src/threadColors.js +35 -97
  66. package/src/unfriend.js +15 -20
  67. package/src/unsendMessage.js +71 -18
  68. package/utils.js +1000 -472
  69. package/README.md +0 -83
  70. package/replit.nix +0 -3
  71. package/src/changeAvatar.js +0 -89
  72. package/src/changeCover.js +0 -92
  73. package/src/changeName.js +0 -106
  74. package/src/changeUsername.js +0 -80
  75. package/src/createCommentPost.js +0 -196
  76. package/src/createPost.js +0 -285
  77. package/src/data/getThreadInfo.json +0 -1
  78. package/src/follow.js +0 -71
  79. package/src/getAccess.js +0 -130
  80. package/src/getAvatarUser.js +0 -88
  81. package/src/getBotInitialData.js +0 -59
  82. package/src/getCtx.js +0 -5
  83. package/src/getMessage.js +0 -827
  84. package/src/getOptions.js +0 -5
  85. package/src/getRegion.js +0 -7
  86. package/src/getThreadHistoryDeprecated.js +0 -95
  87. package/src/getThreadInfoDeprecated.js +0 -77
  88. package/src/getThreadListDeprecated.js +0 -86
  89. package/src/httpPostFormData.js +0 -58
  90. package/src/listenNotification.js +0 -96
  91. package/src/refreshFb_dtsg.js +0 -75
  92. package/src/searchStickers.js +0 -59
  93. package/src/sendMessageMqtt.js +0 -326
  94. package/src/setMessageReactionMqtt.js +0 -74
  95. package/src/setProfileGuard.js +0 -66
  96. package/src/setStoryReaction.js +0 -97
  97. package/src/stopListenMqtt.js +0 -47
  98. package/src/uploadAttachment.js +0 -98
@@ -1,54 +1,179 @@
1
1
  "use strict";
2
2
 
3
3
  var utils = require("../utils");
4
- // @NethWs3Dev
4
+ var log = require("npmlog");
5
5
 
6
6
  module.exports = function (defaultFuncs, api, ctx) {
7
- let count_req = 0;
8
-
9
- return async function sendTypingIndicatorV2(sendTyping, threadID, callback) {
10
- if (typeof callback !== "function") {
11
- callback = function () {};
12
- }
13
-
14
- if (!threadID) {
15
- return callback({ error: "ThreadID is required." });
16
- }
17
-
18
- if (!ctx.mqttClient) {
19
- return callback({ error: "MQTT Client is not initialized." });
20
- }
21
-
22
- var wsContent = {
23
- app_id: 2220391788200892,
24
- payload: JSON.stringify({
25
- label: 3,
26
- payload: JSON.stringify({
27
- thread_key: threadID.toString(),
28
- is_group_thread: +(threadID.toString().length >= 16),
29
- is_typing: +sendTyping,
30
- attribution: 0
31
- }),
32
- version: 5849951561777440
33
- }),
34
- request_id: ++count_req,
35
- type: 4
36
- };
37
-
38
- try {
39
- await new Promise((resolve, reject) => {
40
- ctx.mqttClient.publish('/ls_req', JSON.stringify(wsContent), { qos: 1, retain: false }, (err, _packet) => {
41
- if (err) {
42
- reject(err);
43
- } else {
44
- resolve();
45
- }
46
- });
47
- });
48
- callback(null);
49
- } catch (err) {
50
- utils.error("sendTypingIndicatorV2", err);
51
- callback(err);
52
- }
53
- };
7
+ function makeTypingIndicator(typ, threadID, callback, isGroup) {
8
+ var form = {
9
+ typ: +typ,
10
+ to: "",
11
+ source: "mercury-chat",
12
+ thread: threadID,
13
+ };
14
+
15
+ // Check if thread is a single person chat or a group chat
16
+ // More info on this is in api.sendMessage
17
+ if (utils.getType(isGroup) == "Boolean") {
18
+ if (!isGroup) {
19
+ form.to = threadID;
20
+ }
21
+ defaultFuncs
22
+ .post("https://www.facebook.com/ajax/messaging/typ.php", ctx.jar, form)
23
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
24
+ .then(function (resData) {
25
+ if (resData.error) {
26
+ throw resData;
27
+ }
28
+
29
+ return callback();
30
+ })
31
+ .catch(function (err) {
32
+ log.error("sendTypingIndicator", err);
33
+ if (utils.getType(err) == "Object" && err.error === "Not logged in") {
34
+ ctx.loggedIn = false;
35
+ }
36
+ return callback(err);
37
+ });
38
+ } else {
39
+ api.getUserInfo(threadID, function (err, res) {
40
+ if (err) {
41
+ return callback(err);
42
+ }
43
+
44
+ // If id is single person chat
45
+ if (Object.keys(res).length > 0) {
46
+ form.to = threadID;
47
+ }
48
+
49
+ defaultFuncs
50
+ .post(
51
+ "https://www.facebook.com/ajax/messaging/typ.php",
52
+ ctx.jar,
53
+ form,
54
+ )
55
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
56
+ .then(function (resData) {
57
+ if (resData.error) {
58
+ throw resData;
59
+ }
60
+
61
+ return callback();
62
+ })
63
+ .catch(function (err) {
64
+ log.error("sendTypingIndicator", err);
65
+ if (
66
+ utils.getType(err) == "Object" &&
67
+ err.error === "Not logged in."
68
+ ) {
69
+ ctx.loggedIn = false;
70
+ }
71
+ return callback(err);
72
+ });
73
+ });
74
+ }
75
+ }
76
+
77
+ function sendTypingIndicatorNoMqtt(threadID, callback, isGroup) {
78
+ if (
79
+ utils.getType(callback) !== "Function" &&
80
+ utils.getType(callback) !== "AsyncFunction"
81
+ ) {
82
+ if (callback) {
83
+ log.warn(
84
+ "sendTypingIndicator",
85
+ "callback is not a function - ignoring.",
86
+ );
87
+ }
88
+ callback = () => {};
89
+ }
90
+
91
+ makeTypingIndicator(true, threadID, callback, isGroup);
92
+
93
+ return function end(cb) {
94
+ if (
95
+ utils.getType(cb) !== "Function" &&
96
+ utils.getType(cb) !== "AsyncFunction"
97
+ ) {
98
+ if (cb) {
99
+ log.warn(
100
+ "sendTypingIndicator",
101
+ "callback is not a function - ignoring.",
102
+ );
103
+ }
104
+ cb = () => {};
105
+ }
106
+
107
+ makeTypingIndicator(false, threadID, cb, isGroup);
108
+ };
109
+ }
110
+
111
+ function sendTypingIndicatorMqtt(isTyping, threadID, callback) {
112
+ if (!ctx.mqttClient) {
113
+ throw new Error("Not connected to MQTT");
114
+ }
115
+
116
+ ctx.wsReqNumber += 1;
117
+
118
+ api
119
+ .getThreadInfo(threadID)
120
+ .then((threadData) => {
121
+ const label = "3";
122
+ const isGroupThread = threadData.isGroup ? 1 : 0;
123
+ const attribution = 0;
124
+
125
+ const taskPayload = {
126
+ thread_key: threadID,
127
+ is_group_thread: isGroupThread,
128
+ is_typing: isTyping ? 1 : 0,
129
+ attribution: attribution,
130
+ };
131
+
132
+ const payload = JSON.stringify(taskPayload);
133
+ const version = "25393437286970779";
134
+
135
+ const content = {
136
+ app_id: "2220391788200892",
137
+ payload: JSON.stringify({
138
+ label: label,
139
+ payload: payload,
140
+ version: version,
141
+ }),
142
+ request_id: ctx.wsReqNumber,
143
+ type: 4,
144
+ };
145
+
146
+ if (typeof callback == "function") {
147
+ // to be implemented
148
+ }
149
+
150
+ ctx.mqttClient.publish("/ls_req", JSON.stringify(content), {
151
+ qos: 1,
152
+ retain: false,
153
+ });
154
+ })
155
+ .catch((error) => {
156
+ // console.error(error);
157
+ // throw new Error("Failed to get thread info");
158
+ });
159
+ }
160
+
161
+ return function sendTypingIndicator(threadID, callback, delay, isGroup) {
162
+ if (ctx.mqttClient) {
163
+ if (typeof callback !== "function") delay = callback;
164
+ try {
165
+ sendTypingIndicatorMqtt(true, threadID, callback);
166
+ setTimeout(
167
+ function () {
168
+ sendTypingIndicatorMqtt(false, threadID, () => {});
169
+ },
170
+ delay ? delay : 30 * 1000,
171
+ );
172
+ callback();
173
+ } catch (e) {
174
+ // console.error(e);
175
+ sendTypingIndicatorNoMqtt(threadID, callback, isGroup);
176
+ }
177
+ } else sendTypingIndicatorNoMqtt(threadID, callback, isGroup);
178
+ };
54
179
  };
package/src/setBio.js ADDED
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+
3
+ var utils = require("../utils");
4
+ var log = require("npmlog");
5
+
6
+ module.exports = function (defaultFuncs, api, ctx) {
7
+ /**
8
+ * Set user bio with enhanced options
9
+ * @param {string} bio - Bio text
10
+ * @param {object} options - Optional settings
11
+ * @param {function} callback - Callback function
12
+ */
13
+ return function setBio(bio, options, callback) {
14
+ var resolveFunc = function () {};
15
+ var rejectFunc = function () {};
16
+ var returnPromise = new Promise(function (resolve, reject) {
17
+ resolveFunc = resolve;
18
+ rejectFunc = reject;
19
+ });
20
+
21
+ if (!callback) {
22
+ if (
23
+ utils.getType(options) == "Function" ||
24
+ utils.getType(options) == "AsyncFunction"
25
+ ) {
26
+ callback = options;
27
+ options = {};
28
+ } else {
29
+ callback = function (err) {
30
+ if (err) {
31
+ return rejectFunc(err);
32
+ }
33
+ resolveFunc();
34
+ };
35
+ }
36
+ }
37
+
38
+ options = options || {};
39
+
40
+ if (utils.getType(bio) != "String") {
41
+ return callback({ error: "Bio must be a string" });
42
+ }
43
+
44
+ var form = {
45
+ av: ctx.userID,
46
+ fb_api_caller_class: "RelayModern",
47
+ fb_api_req_friendly_name: "ProfileCometSetBioMutation",
48
+ doc_id: "2725043627607610",
49
+ variables: JSON.stringify({
50
+ input: {
51
+ bio: bio,
52
+ change_type: options.changeType || "ADD",
53
+ should_update_bio_in_basic_info: true,
54
+ source: "profile_comet",
55
+ },
56
+ }),
57
+ };
58
+
59
+ defaultFuncs
60
+ .post("https://www.facebook.com/api/graphql/", ctx.jar, form)
61
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
62
+ .then(function (resData) {
63
+ if (resData.errors) {
64
+ throw resData;
65
+ }
66
+
67
+ var bioData = null;
68
+ if (
69
+ resData.data &&
70
+ resData.data.profile_intro_card_set &&
71
+ resData.data.profile_intro_card_set.profile_intro_card
72
+ ) {
73
+ bioData = resData.data.profile_intro_card_set.profile_intro_card;
74
+ }
75
+
76
+ log.info("setBio", "Bio updated successfully");
77
+ return callback(null, bioData);
78
+ })
79
+ .catch(function (err) {
80
+ log.error("setBio", err);
81
+ return callback(err);
82
+ });
83
+
84
+ return returnPromise;
85
+ };
86
+ };
@@ -1,35 +1,32 @@
1
1
  "use strict";
2
2
 
3
- const utils = require("../utils");
4
- // @NethWs3Dev
3
+ var utils = require("../utils");
4
+ var log = require("npmlog");
5
+ const { generateOfflineThreadingID } = require("../utils");
5
6
 
6
7
  module.exports = function (defaultFuncs, api, ctx) {
7
- return function setMessageReaction(
8
+ function setMessageReactionNoMqtt(
8
9
  reaction,
9
10
  messageID,
10
11
  callback,
11
12
  forceCustomReaction,
12
13
  ) {
13
- let resolveFunc = function () {};
14
- let rejectFunc = function () {};
15
- const returnPromise = new Promise(function (resolve, reject) {
14
+ var resolveFunc = function () {};
15
+ var rejectFunc = function () {};
16
+ var returnPromise = new Promise(function (resolve, reject) {
16
17
  resolveFunc = resolve;
17
18
  rejectFunc = reject;
18
19
  });
19
20
 
20
21
  if (!callback) {
21
- callback = function (err, data) {
22
+ callback = function (err, friendList) {
22
23
  if (err) {
23
24
  return rejectFunc(err);
24
25
  }
25
- resolveFunc(data);
26
+ resolveFunc(friendList);
26
27
  };
27
28
  }
28
29
 
29
- if (!messageID) {
30
- return callback({ error: "MessageID is required." });
31
- }
32
-
33
30
  switch (reaction) {
34
31
  case "\uD83D\uDE0D": //:heart_eyes:
35
32
  case "\uD83D\uDE06": //:laughing:
@@ -83,7 +80,7 @@ module.exports = function (defaultFuncs, api, ctx) {
83
80
  return callback({ error: "Reaction is not a valid emoji." });
84
81
  }
85
82
 
86
- const variables = {
83
+ var variables = {
87
84
  data: {
88
85
  client_mutation_id: ctx.clientMutationId++,
89
86
  actor_id: ctx.userID,
@@ -93,7 +90,7 @@ module.exports = function (defaultFuncs, api, ctx) {
93
90
  },
94
91
  };
95
92
 
96
- const qs = {
93
+ var qs = {
97
94
  doc_id: "1491398900900362",
98
95
  variables: JSON.stringify(variables),
99
96
  dpr: 1,
@@ -106,7 +103,7 @@ module.exports = function (defaultFuncs, api, ctx) {
106
103
  {},
107
104
  qs,
108
105
  )
109
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
106
+ .then(utils.parseAndCheckLogin(ctx.jar, defaultFuncs))
110
107
  .then(function (resData) {
111
108
  if (!resData) {
112
109
  throw { error: "setReaction returned empty object." };
@@ -117,10 +114,73 @@ module.exports = function (defaultFuncs, api, ctx) {
117
114
  callback(null);
118
115
  })
119
116
  .catch(function (err) {
120
- utils.error("setReaction", err);
117
+ log.error("setReaction", err);
121
118
  return callback(err);
122
119
  });
123
120
 
124
121
  return returnPromise;
122
+ }
123
+ function setMessageReactionMqtt(reaction, messageID, threadID, callback) {
124
+ if (!ctx.mqttClient) {
125
+ throw new Error("Not connected to MQTT");
126
+ }
127
+
128
+ ctx.wsReqNumber += 1;
129
+ let taskNumber = ++ctx.wsTaskNumber;
130
+
131
+ const taskPayload = {
132
+ thread_key: threadID,
133
+ timestamp_ms: getCurrentTimestamp(),
134
+ message_id: messageID,
135
+ reaction: reaction,
136
+ actor_id: ctx.userID,
137
+ reaction_style: null,
138
+ sync_group: 1,
139
+ send_attribution: Math.random() < 0.5 ? 65537 : 524289,
140
+ };
141
+
142
+ const task = {
143
+ failure_count: null,
144
+ label: "29",
145
+ payload: JSON.stringify(taskPayload),
146
+ queue_name: JSON.stringify(["reaction", messageID]),
147
+ task_id: taskNumber,
148
+ };
149
+
150
+ const content = {
151
+ app_id: "2220391788200892",
152
+ payload: JSON.stringify({
153
+ data_trace_id: null,
154
+ epoch_id: parseInt(generateOfflineThreadingID()),
155
+ tasks: [task],
156
+ version_id: "7158486590867448",
157
+ }),
158
+ request_id: ctx.wsReqNumber,
159
+ type: 3,
160
+ };
161
+
162
+ if (typeof callback === "function") {
163
+ ctx["tasks"].set(taskNumber, {
164
+ type: "set_message_reaction",
165
+ callback: callback,
166
+ });
167
+ }
168
+ ctx.mqttClient.publish("/ls_req", JSON.stringify(content), {
169
+ qos: 1,
170
+ retain: false,
171
+ });
172
+ }
173
+
174
+ return function setMessageReaction(reaction, messageID, threadID, callback) {
175
+ if (ctx.mqttClient) {
176
+ try {
177
+ setMessageReactionMqtt(reaction, messageID, threadID, callback);
178
+ callback();
179
+ } catch (e) {
180
+ setMessageReactionNoMqtt(reaction, messageID, callback, true);
181
+ }
182
+ } else {
183
+ setMessageReactionNoMqtt(reaction, messageID, callback, true);
184
+ }
125
185
  };
126
186
  };
@@ -1,83 +1,53 @@
1
1
  "use strict";
2
2
 
3
- const utils = require("../utils");
4
-
5
- function formatData(resData) {
6
- return {
7
- viewer_feedback_reaction_info: resData.feedback_react.feedback.viewer_feedback_reaction_info,
8
- supported_reactions: resData.feedback_react.feedback.supported_reactions,
9
- top_reactions: resData.feedback_react.feedback.top_reactions.edges,
10
- reaction_count: resData.feedback_react.feedback.reaction_count,
11
- };
12
- }
3
+ var utils = require("../utils");
4
+ var log = require("npmlog");
13
5
 
14
6
  module.exports = function (defaultFuncs, api, ctx) {
15
- return function setPostReaction(postID, type, callback) {
16
- let resolveFunc = function () {};
17
- let rejectFunc = function () {};
18
- const returnPromise = new Promise(function (resolve, reject) {
7
+ return function unsendMessage(postID, type, callback) {
8
+ var resolveFunc = function () {};
9
+ var rejectFunc = function () {};
10
+ var returnPromise = new Promise(function (resolve, reject) {
19
11
  resolveFunc = resolve;
20
12
  rejectFunc = reject;
21
13
  });
22
14
 
23
15
  if (!callback) {
24
- if (utils.getType(type) === "Function" || utils.getType(type) === "AsyncFunction") {
25
- callback = type;
26
- type = 0;
27
- } else {
28
- callback = function (err, data) {
29
- if (err) {
30
- return rejectFunc(err);
31
- }
32
- resolveFunc(data);
33
- };
34
- }
35
- }
36
-
37
- if (!postID) {
38
- return callback({ error: "setPostReaction: postID is required" });
16
+ callback = function (err, friendList) {
17
+ if (err) {
18
+ return rejectFunc(err);
19
+ }
20
+ resolveFunc(friendList);
21
+ };
39
22
  }
40
23
 
41
- const map = {
42
- unlike: 0,
24
+ var map = {
43
25
  like: 1,
44
26
  heart: 2,
45
- love: 16,
46
- haha: 4,
47
27
  wow: 3,
28
+ haha: 4,
48
29
  sad: 7,
49
30
  angry: 8,
50
31
  };
51
-
52
- const originalType = type;
53
- if (utils.getType(type) === "String") {
54
- type = map[type.toLowerCase()];
55
- }
56
-
57
- if (type === undefined || (utils.getType(type) !== "Number" && utils.getType(type) !== "String")) {
58
- return callback({
59
- error: "setPostReaction: Invalid reaction type (" + originalType + ")",
60
- });
32
+ if (typeof type != "number") {
33
+ type = map[type.toLocaleLowerCase()];
34
+ if (!type) {
35
+ type = 1;
36
+ }
61
37
  }
62
-
63
- const form = {
38
+ var form = {
64
39
  av: ctx.userID,
65
40
  fb_api_caller_class: "RelayModern",
66
- fb_api_req_friendly_name: "CometUFIFeedbackReactMutation",
67
- doc_id: "4769042373179384",
41
+ fb_api_req_friendly_name: "UFI2FeedbackReactMutation",
42
+ //This doc_id is valid as of January 17th, 2020
43
+ doc_id: "2580813318646067",
68
44
  variables: JSON.stringify({
69
45
  input: {
46
+ client_mutation_id: "7",
70
47
  actor_id: ctx.userID,
71
- feedback_id: Buffer.from("feedback:" + postID).toString("base64"),
72
48
  feedback_reaction: type,
73
- feedback_source: "OBJECT",
74
- is_tracking_encrypted: true,
75
- tracking: [],
76
- session_id: "f7dd50dd-db6e-4598-8cd9-561d5002b423",
77
- client_mutation_id: Math.round(Math.random() * 19).toString(),
78
49
  },
79
- useDefaultActor: false,
80
- scale: 3,
50
+ useDefaultActor: true,
81
51
  }),
82
52
  };
83
53
 
@@ -85,16 +55,14 @@ module.exports = function (defaultFuncs, api, ctx) {
85
55
  .post("https://www.facebook.com/api/graphql/", ctx.jar, form)
86
56
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
87
57
  .then(function (resData) {
88
- if (!resData) {
89
- throw { error: "setPostReaction returned empty response." };
90
- }
91
- if (resData.errors) {
58
+ if (resData.error) {
92
59
  throw resData;
93
60
  }
94
- return callback(null, formatData(resData.data));
61
+
62
+ return callback();
95
63
  })
96
64
  .catch(function (err) {
97
- utils.error("setPostReaction", err);
65
+ log.error("setPostReaction", err);
98
66
  return callback(err);
99
67
  });
100
68