@dongdev/fca-unofficial 2.0.7 → 2.0.10

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 (80) hide show
  1. package/DOCS.md +1699 -1434
  2. package/README.md +250 -168
  3. package/package.json +54 -28
  4. package/src/api/action/addExternalModule.js +5 -5
  5. package/src/api/action/changeAvatar.js +11 -10
  6. package/src/api/action/changeBio.js +7 -8
  7. package/src/api/action/getCurrentUserID.js +1 -1
  8. package/src/api/action/handleFriendRequest.js +5 -5
  9. package/src/api/action/logout.js +9 -8
  10. package/src/api/action/refreshFb_dtsg.js +17 -12
  11. package/src/api/action/setPostReaction.js +10 -11
  12. package/src/api/action/unfriend.js +3 -4
  13. package/src/api/http/httpGet.js +7 -8
  14. package/src/api/http/httpPost.js +7 -8
  15. package/src/api/http/postFormData.js +6 -5
  16. package/src/api/messaging/addUserToGroup.js +0 -1
  17. package/src/api/messaging/changeAdminStatus.js +108 -89
  18. package/src/api/messaging/changeArchivedStatus.js +6 -6
  19. package/src/api/messaging/changeBlockedStatus.js +3 -4
  20. package/src/api/messaging/changeGroupImage.js +72 -117
  21. package/src/api/messaging/changeNickname.js +59 -48
  22. package/src/api/messaging/changeThreadColor.js +61 -47
  23. package/src/api/messaging/changeThreadEmoji.js +106 -0
  24. package/src/api/messaging/createNewGroup.js +5 -5
  25. package/src/api/messaging/createPoll.js +36 -63
  26. package/src/api/messaging/deleteMessage.js +4 -4
  27. package/src/api/messaging/deleteThread.js +4 -4
  28. package/src/api/messaging/forwardAttachment.js +38 -47
  29. package/src/api/messaging/getFriendsList.js +5 -6
  30. package/src/api/messaging/getMessage.js +4 -9
  31. package/src/api/messaging/handleMessageRequest.js +5 -5
  32. package/src/api/messaging/markAsDelivered.js +5 -5
  33. package/src/api/messaging/markAsRead.js +7 -7
  34. package/src/api/messaging/markAsReadAll.js +3 -4
  35. package/src/api/messaging/markAsSeen.js +7 -7
  36. package/src/api/messaging/muteThread.js +3 -4
  37. package/src/api/messaging/removeUserFromGroup.js +82 -56
  38. package/src/api/messaging/resolvePhotoUrl.js +2 -3
  39. package/src/api/messaging/searchForThread.js +2 -3
  40. package/src/api/messaging/sendMessage.js +171 -101
  41. package/src/api/messaging/sendMessageMqtt.js +14 -12
  42. package/src/api/messaging/sendTypingIndicator.js +11 -11
  43. package/src/api/messaging/setMessageReaction.js +68 -82
  44. package/src/api/messaging/setTitle.js +77 -48
  45. package/src/api/messaging/shareContact.js +2 -4
  46. package/src/api/messaging/threadColors.js +0 -3
  47. package/src/api/messaging/unsendMessage.js +74 -37
  48. package/src/api/messaging/uploadAttachment.js +11 -9
  49. package/src/api/socket/core/connectMqtt.js +180 -0
  50. package/src/api/socket/core/getSeqID.js +25 -0
  51. package/src/api/socket/core/getTaskResponseData.js +22 -0
  52. package/src/api/socket/core/markDelivery.js +12 -0
  53. package/src/api/socket/core/parseDelta.js +351 -0
  54. package/src/api/socket/detail/buildStream.js +176 -68
  55. package/src/api/socket/detail/constants.js +24 -0
  56. package/src/api/socket/listenMqtt.js +80 -1005
  57. package/src/api/{messaging → threads}/getThreadHistory.js +5 -22
  58. package/src/api/threads/getThreadInfo.js +35 -248
  59. package/src/api/threads/getThreadList.js +20 -20
  60. package/src/api/threads/getThreadPictures.js +3 -4
  61. package/src/api/users/getUserID.js +5 -6
  62. package/src/api/users/getUserInfo.js +305 -73
  63. package/src/api/users/getUserInfoV2.js +134 -0
  64. package/src/database/models/user.js +32 -0
  65. package/src/database/userData.js +89 -0
  66. package/src/utils/constants.js +12 -2
  67. package/src/utils/format.js +1051 -0
  68. package/src/utils/request.js +75 -7
  69. package/CHANGELOG.md +0 -52
  70. package/LICENSE-MIT +0 -21
  71. package/func/checkUpdate.js +0 -58
  72. package/func/logger.js +0 -112
  73. package/func/login.js +0 -0
  74. package/index.d.ts +0 -618
  75. package/module/config.js +0 -34
  76. package/module/login.js +0 -47
  77. package/module/loginHelper.js +0 -635
  78. package/module/options.js +0 -49
  79. package/src/api/threads/changeThreadEmoji.js +0 -55
  80. package/src/utils/index.js +0 -1497
@@ -1,9 +1,6 @@
1
- "use strict";
2
-
3
1
  const fs = require("fs");
4
2
  const path = require("path");
5
3
  const { Readable } = require("stream");
6
- const utils = require("../../utils");
7
4
  const log = require("npmlog");
8
5
  const allowedProperties = {
9
6
  attachment: true,
@@ -16,38 +13,27 @@ const allowedProperties = {
16
13
  location: true,
17
14
  asPage: true
18
15
  };
16
+ const { isReadableStream } = require("../../utils/constants");
17
+ const { parseAndCheckLogin } = require("../../utils/client");
18
+ const { getType, generateThreadingID, generateTimestampRelative, generateOfflineThreadingID, getSignatureID } = require("../../utils/format");
19
+
19
20
  module.exports = function (defaultFuncs, api, ctx) {
20
21
  function toReadable(input) {
21
- if (utils.isReadableStream(input)) return input;
22
+ if (isReadableStream(input)) return input;
22
23
  if (Buffer.isBuffer(input)) return Readable.from(input);
23
24
  if (typeof input === "string" && fs.existsSync(input) && fs.statSync(input).isFile()) return fs.createReadStream(path.resolve(input));
24
25
  throw { error: "Unsupported attachment input. Use stream/buffer/filepath." };
25
26
  }
26
- function normalizeAttachments(list) {
27
- if (!Array.isArray(list)) list = [list];
28
- return list.map(a => {
29
- if (Array.isArray(a) && /_id$/.test(a[0])) return a;
30
- if (a && typeof a === "object") {
31
- if (a.id && a.type && /_id$/.test(a.type)) return [a.type, a.id];
32
- if (a.image_id || a.file_id || a.video_id || a.audio_id || a.gif_id) {
33
- const k = Object.keys(a).find(x => /_id$/.test(x));
34
- return [k, a[k]];
35
- }
36
- }
37
- return toReadable(a);
38
- });
39
- }
27
+
40
28
  function uploadAttachment(attachments, callback) {
41
29
  const uploads = [];
42
30
  for (let i = 0; i < attachments.length; i++) {
43
- if (!utils.isReadableStream(attachments[i])) {
44
- throw { error: "Attachment should be a readable stream and not " + utils.getType(attachments[i]) + "." };
45
- }
31
+ if (!isReadableStream(attachments[i])) throw { error: "Attachment should be a readable stream and not " + getType(attachments[i]) + "." };
46
32
  const form = { upload_1024: attachments[i], voice_clip: "true" };
47
33
  uploads.push(
48
34
  defaultFuncs
49
35
  .postFormData("https://upload.facebook.com/ajax/mercury/upload.php", ctx.jar, form, {}, {})
50
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
36
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
51
37
  .then(resData => {
52
38
  if (resData.error) throw resData;
53
39
  return resData.payload.metadata[0];
@@ -61,11 +47,12 @@ module.exports = function (defaultFuncs, api, ctx) {
61
47
  callback(err);
62
48
  });
63
49
  }
50
+
64
51
  function getUrl(url, callback) {
65
52
  const form = { image_height: 960, image_width: 960, uri: url };
66
53
  defaultFuncs
67
54
  .post("https://www.facebook.com/message_share_attachment/fromURI/", ctx.jar, form)
68
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
55
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
69
56
  .then(resData => {
70
57
  if (resData.error) return callback(resData);
71
58
  if (!resData.payload) return callback({ error: "Invalid url" });
@@ -76,12 +63,16 @@ module.exports = function (defaultFuncs, api, ctx) {
76
63
  callback(err);
77
64
  });
78
65
  }
79
- function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
66
+
67
+ function sleep(ms) {
68
+ return new Promise(r => setTimeout(r, ms));
69
+ }
70
+
80
71
  async function postWithRetry(url, jar, form, tries = 3) {
81
72
  let lastErr;
82
73
  for (let i = 0; i < tries; i++) {
83
74
  try {
84
- const res = await defaultFuncs.post(url, jar, form).then(utils.parseAndCheckLogin(ctx, defaultFuncs));
75
+ const res = await defaultFuncs.post(url, jar, form).then(parseAndCheckLogin(ctx, defaultFuncs));
85
76
  if (res && !res.error) return res;
86
77
  lastErr = res;
87
78
  if (res && (res.error === 1545003 || res.error === 368)) await sleep(500 * (i + 1));
@@ -93,6 +84,7 @@ module.exports = function (defaultFuncs, api, ctx) {
93
84
  }
94
85
  throw lastErr || { error: "Send failed" };
95
86
  }
87
+
96
88
  function applyPageAuthor(form, msg) {
97
89
  const pageID = msg && msg.asPage ? msg.asPage : ctx.globalOptions.pageID;
98
90
  if (!pageID) return;
@@ -105,9 +97,16 @@ module.exports = function (defaultFuncs, api, ctx) {
105
97
  form["request_user_id"] = pageID;
106
98
  form["creator_info[profileURI]"] = "https://www.facebook.com/profile.php?id=" + ctx.userID;
107
99
  }
100
+
108
101
  function applyMentions(msg, form) {
109
102
  if (!msg.mentions || !msg.mentions.length) return;
110
- const body = typeof msg.body === "string" ? msg.body : "";
103
+ let body = typeof msg.body === "string" ? msg.body : "";
104
+ const need = [];
105
+ for (const m of msg.mentions) {
106
+ const tag = String(m.tag || "");
107
+ if (tag && !body.includes(tag)) need.push(tag);
108
+ }
109
+ if (need.length) body = (body ? body + " " : "") + need.join(" ");
111
110
  const emptyChar = "\u200E";
112
111
  form["body"] = emptyChar + body;
113
112
  let searchFrom = 0;
@@ -122,16 +121,35 @@ module.exports = function (defaultFuncs, api, ctx) {
122
121
  searchFrom = off + tag.length;
123
122
  });
124
123
  }
124
+
125
125
  function finalizeHasAttachment(form) {
126
126
  const keys = ["image_ids", "gif_ids", "file_ids", "video_ids", "audio_ids", "sticker_id", "shareable_attachment[share_params]"];
127
127
  form.has_attachment = keys.some(k => k in form && (Array.isArray(form[k]) ? form[k].length > 0 : !!form[k]));
128
128
  }
129
+
130
+ function extractMessageInfo(resData, fallbackThreadID) {
131
+ let messageID = null;
132
+ let threadFBID = null;
133
+ let timestamp = null;
134
+ const actions = resData && resData.payload && Array.isArray(resData.payload.actions) ? resData.payload.actions : null;
135
+ if (actions && actions.length) {
136
+ const v = actions.find(x => x && x.message_id) || actions[0];
137
+ messageID = v && v.message_id ? v.message_id : null;
138
+ threadFBID = (v && (v.thread_fbid || v.thread_id)) || fallbackThreadID || null;
139
+ timestamp = v && v.timestamp ? v.timestamp : null;
140
+ }
141
+ if (!messageID) messageID = (resData && resData.payload && resData.payload.message_id) || resData.message_id || null;
142
+ if (!threadFBID) threadFBID = (resData && resData.payload && resData.payload.thread_id) || fallbackThreadID || null;
143
+ if (!timestamp) timestamp = (resData && resData.timestamp) || Date.now();
144
+ if (!messageID) return null;
145
+ return { threadID: threadFBID, messageID, timestamp };
146
+ }
147
+
129
148
  function sendContent(form, threadID, isSingleUser, messageAndOTID, callback) {
130
- if (utils.getType(threadID) === "Array") {
149
+ if (getType(threadID) === "Array") {
131
150
  for (let i = 0; i < threadID.length; i++) form["specific_to_list[" + i + "]"] = "fbid:" + threadID[i];
132
151
  form["specific_to_list[" + threadID.length + "]"] = "fbid:" + ctx.userID;
133
152
  form["client_thread_id"] = "root:" + messageAndOTID;
134
- log.verbose("sendMessage", "Sending message to multiple users: " + threadID);
135
153
  } else {
136
154
  if (isSingleUser) {
137
155
  form["specific_to_list[0]"] = "fbid:" + threadID;
@@ -149,25 +167,23 @@ module.exports = function (defaultFuncs, api, ctx) {
149
167
  else log.error("sendMessage", resData);
150
168
  return callback(resData);
151
169
  }
152
- let messageInfo = null;
153
- if (resData.payload && Array.isArray(resData.payload.actions)) {
154
- for (const v of resData.payload.actions) {
155
- if (v && v.message_id) messageInfo = { threadID: v.thread_fbid, messageID: v.message_id, timestamp: v.timestamp };
156
- }
157
- }
158
- callback(null, messageInfo);
170
+ const info = extractMessageInfo(resData, getType(threadID) === "Array" ? null : String(threadID));
171
+ if (!info) return callback({ error: "Cannot parse message info." });
172
+ callback(null, info);
159
173
  })
160
174
  .catch(err => {
161
175
  log.error("sendMessage", err);
162
- if (utils.getType(err) === "Object" && err.error === "Not logged in.") ctx.loggedIn = false;
176
+ if (getType(err) === "Object" && err.error === "Not logged in.") ctx.loggedIn = false;
163
177
  callback(err);
164
178
  });
165
179
  }
180
+
166
181
  function send(form, threadID, messageAndOTID, callback, isGroup) {
167
- if (utils.getType(threadID) === "Array") return sendContent(form, threadID, false, messageAndOTID, callback);
168
- if (utils.getType(isGroup) !== "Boolean") return sendContent(form, threadID, String(threadID).length === 15, messageAndOTID, callback);
182
+ if (getType(threadID) === "Array") return sendContent(form, threadID, false, messageAndOTID, callback);
183
+ if (getType(isGroup) !== "Boolean") return sendContent(form, threadID, String(threadID).length === 15, messageAndOTID, callback);
169
184
  return sendContent(form, threadID, !isGroup, messageAndOTID, callback);
170
185
  }
186
+
171
187
  function handleUrl(msg, form, callback, cb) {
172
188
  if (msg.url) {
173
189
  form["shareable_attachment[share_type]"] = "100";
@@ -178,6 +194,7 @@ module.exports = function (defaultFuncs, api, ctx) {
178
194
  });
179
195
  } else cb();
180
196
  }
197
+
181
198
  function handleLocation(msg, form, callback, cb) {
182
199
  if (msg.location) {
183
200
  if (msg.location.latitude == null || msg.location.longitude == null) return callback({ error: "location property needs both latitude and longitude" });
@@ -187,10 +204,12 @@ module.exports = function (defaultFuncs, api, ctx) {
187
204
  }
188
205
  cb();
189
206
  }
207
+
190
208
  function handleSticker(msg, form, callback, cb) {
191
209
  if (msg.sticker) form["sticker_id"] = msg.sticker;
192
210
  cb();
193
211
  }
212
+
194
213
  function handleEmoji(msg, form, callback, cb) {
195
214
  if (msg.emojiSize != null && msg.emoji == null) return callback({ error: "emoji property is empty" });
196
215
  if (msg.emoji) {
@@ -202,6 +221,32 @@ module.exports = function (defaultFuncs, api, ctx) {
202
221
  }
203
222
  cb();
204
223
  }
224
+
225
+ function splitAttachments(list) {
226
+ if (!Array.isArray(list)) list = [list];
227
+ const ids = [];
228
+ const streams = [];
229
+ for (const a of list) {
230
+ if (Array.isArray(a) && /_id$/.test(a[0])) {
231
+ ids.push([a[0], String(a[1])]);
232
+ continue;
233
+ }
234
+ if (a && typeof a === "object") {
235
+ if (a.id && a.type && /_id$/.test(a.type)) {
236
+ ids.push([a.type, String(a.id)]);
237
+ continue;
238
+ }
239
+ const k = Object.keys(a || {}).find(x => /_id$/.test(x));
240
+ if (k) {
241
+ ids.push([k, String(a[k])]);
242
+ continue;
243
+ }
244
+ }
245
+ streams.push(toReadable(a));
246
+ }
247
+ return { ids, streams };
248
+ }
249
+
205
250
  function handleAttachment(msg, form, callback, cb) {
206
251
  if (!msg.attachment) return cb();
207
252
  form["image_ids"] = [];
@@ -209,12 +254,10 @@ module.exports = function (defaultFuncs, api, ctx) {
209
254
  form["file_ids"] = [];
210
255
  form["video_ids"] = [];
211
256
  form["audio_ids"] = [];
212
- const items = normalizeAttachments(msg.attachment);
213
- if (items.every(e => Array.isArray(e) && /_id$/.test(e[0]))) {
214
- items.forEach(e => form[`${e[0]}s`].push(e[1]));
215
- return cb();
216
- }
217
- uploadAttachment(items, function (err, files) {
257
+ const { ids, streams } = splitAttachments(msg.attachment);
258
+ for (const [type, id] of ids) form[`${type}s`].push(id);
259
+ if (!streams.length) return cb();
260
+ uploadAttachment(streams, function (err, files) {
218
261
  if (err) return callback(err);
219
262
  files.forEach(function (file) {
220
263
  const type = Object.keys(file)[0];
@@ -223,16 +266,32 @@ module.exports = function (defaultFuncs, api, ctx) {
223
266
  cb();
224
267
  });
225
268
  }
269
+
226
270
  function handleMention(msg, form, callback, cb) {
227
- try { applyMentions(msg, form); cb(); } catch (e) { callback(e); }
271
+ try {
272
+ applyMentions(msg, form);
273
+ cb();
274
+ } catch (e) {
275
+ callback(e);
276
+ }
228
277
  }
278
+
229
279
  return function sendMessage(msg, threadID, callback, replyToMessage, isGroup) {
280
+ const isFn = v => typeof v === "function";
281
+ const isStr = v => typeof v === "string";
282
+
230
283
  if (typeof isGroup === "undefined") isGroup = null;
231
- if (!callback && (utils.getType(threadID) === "Function" || utils.getType(threadID) === "AsyncFunction")) return threadID({ error: "Pass a threadID as a second argument." });
232
- if (!replyToMessage && utils.getType(callback) === "String") {
284
+ if (!callback && (getType(threadID) === "Function" || getType(threadID) === "AsyncFunction")) return threadID({ error: "Pass a threadID as a second argument." });
285
+
286
+ if (isStr(callback) && isFn(replyToMessage)) {
287
+ const t = callback;
288
+ callback = replyToMessage;
289
+ replyToMessage = t;
290
+ } else if (!replyToMessage && isStr(callback)) {
233
291
  replyToMessage = callback;
234
- callback = function () { };
292
+ callback = null;
235
293
  }
294
+
236
295
  let resolveFunc = function () { };
237
296
  let rejectFunc = function () { };
238
297
  const returnPromise = new Promise(function (resolve, reject) {
@@ -245,62 +304,73 @@ module.exports = function (defaultFuncs, api, ctx) {
245
304
  resolveFunc(data);
246
305
  };
247
306
  }
248
- const msgType = utils.getType(msg);
249
- const threadIDType = utils.getType(threadID);
250
- const messageIDType = utils.getType(replyToMessage);
251
- if (msgType !== "String" && msgType !== "Object") return callback({ error: "Message should be of type string or object and not " + msgType + "." });
252
- if (threadIDType !== "Array" && threadIDType !== "Number" && threadIDType !== "String") return callback({ error: "ThreadID should be of type number, string, or array and not " + threadIDType + "." });
253
- if (replyToMessage && messageIDType !== "String") return callback({ error: "MessageID should be of type string and not " + threadIDType + "." });
254
- if (msgType === "String") msg = { body: msg };
255
- const disallowedProperties = Object.keys(msg).filter(prop => !allowedProperties[prop]);
256
- if (disallowedProperties.length > 0) return callback({ error: "Disallowed props: `" + disallowedProperties.join(", ") + "`" });
257
- const messageAndOTID = utils.generateOfflineThreadingID();
258
- const form = {
259
- client: "mercury",
260
- action_type: "ma-type:user-generated-message",
261
- author: "fbid:" + ctx.userID,
262
- timestamp: Date.now(),
263
- timestamp_absolute: "Today",
264
- timestamp_relative: utils.generateTimestampRelative(),
265
- timestamp_time_passed: "0",
266
- is_unread: false,
267
- is_cleared: false,
268
- is_forward: false,
269
- is_filtered_content: false,
270
- is_filtered_content_bh: false,
271
- is_filtered_content_account: false,
272
- is_filtered_content_quasar: false,
273
- is_filtered_content_invalid_app: false,
274
- is_spoof_warning: false,
275
- source: "source:chat:web",
276
- "source_tags[0]": "source:chat",
277
- body: msg.body ? msg.body.toString() : "",
278
- html_body: false,
279
- ui_push_phase: "V3",
280
- status: "0",
281
- offline_threading_id: messageAndOTID,
282
- message_id: messageAndOTID,
283
- threading_id: utils.generateThreadingID(ctx.clientID),
284
- ephemeral_ttl_mode: "0",
285
- manual_retry_cnt: "0",
286
- signatureID: utils.getSignatureID(),
287
- replied_to_message_id: replyToMessage
288
- };
289
- applyPageAuthor(form, msg);
290
- handleLocation(msg, form, callback, () =>
291
- handleSticker(msg, form, callback, () =>
292
- handleAttachment(msg, form, callback, () =>
293
- handleUrl(msg, form, callback, () =>
294
- handleEmoji(msg, form, callback, () =>
295
- handleMention(msg, form, callback, () => {
296
- finalizeHasAttachment(form);
297
- send(form, threadID, messageAndOTID, callback, isGroup);
298
- })
307
+
308
+ try {
309
+ const msgType = getType(msg);
310
+ const threadIDType = getType(threadID);
311
+ const messageIDType = getType(replyToMessage);
312
+ if (msgType !== "String" && msgType !== "Object") return callback({ error: "Message should be of type string or object and not " + msgType + "." });
313
+ if (threadIDType !== "Array" && threadIDType !== "Number" && threadIDType !== "String") return callback({ error: "ThreadID should be of type number, string, or array and not " + threadIDType + "." });
314
+ if (replyToMessage && messageIDType !== "String") return callback({ error: "MessageID should be of type string and not " + threadIDType + "." });
315
+ if (msgType === "String") msg = { body: msg };
316
+
317
+ const disallowedProperties = Object.keys(msg).filter(prop => !allowedProperties[prop]);
318
+ if (disallowedProperties.length > 0) return callback({ error: "Disallowed props: `" + disallowedProperties.join(", ") + "`" });
319
+
320
+ const messageAndOTID = generateOfflineThreadingID();
321
+ const form = {
322
+ client: "mercury",
323
+ action_type: "ma-type:user-generated-message",
324
+ author: "fbid:" + ctx.userID,
325
+ timestamp: Date.now(),
326
+ timestamp_absolute: "Today",
327
+ timestamp_relative: generateTimestampRelative(),
328
+ timestamp_time_passed: "0",
329
+ is_unread: false,
330
+ is_cleared: false,
331
+ is_forward: false,
332
+ is_filtered_content: false,
333
+ is_filtered_content_bh: false,
334
+ is_filtered_content_account: false,
335
+ is_filtered_content_quasar: false,
336
+ is_filtered_content_invalid_app: false,
337
+ is_spoof_warning: false,
338
+ source: "source:chat:web",
339
+ "source_tags[0]": "source:chat",
340
+ body: msg.body ? msg.body.toString() : "",
341
+ html_body: false,
342
+ ui_push_phase: "V3",
343
+ status: "0",
344
+ offline_threading_id: messageAndOTID,
345
+ message_id: messageAndOTID,
346
+ threading_id: generateThreadingID(ctx.clientID),
347
+ ephemeral_ttl_mode: "0",
348
+ manual_retry_cnt: "0",
349
+ signatureID: getSignatureID(),
350
+ replied_to_message_id: replyToMessage ? replyToMessage.toString() : ""
351
+ };
352
+ applyPageAuthor(form, msg);
353
+ handleLocation(msg, form, callback, () =>
354
+ handleSticker(msg, form, callback, () =>
355
+ handleAttachment(msg, form, callback, () =>
356
+ handleUrl(msg, form, callback, () =>
357
+ handleEmoji(msg, form, callback, () =>
358
+ handleMention(msg, form, callback, () => {
359
+ finalizeHasAttachment(form);
360
+ send(form, threadID, messageAndOTID, callback, isGroup);
361
+ })
362
+ )
299
363
  )
300
364
  )
301
365
  )
302
- )
303
- );
366
+ );
367
+ } catch (e) {
368
+ log.error("sendMessage", e);
369
+ if (getType(e) === "Object" && e.error === "Not logged in.") ctx.loggedIn = false;
370
+ return callback(e);
371
+ }
372
+
304
373
  return returnPromise;
305
374
  };
375
+
306
376
  };
@@ -1,7 +1,9 @@
1
- const utils = require("../../utils");
1
+
2
2
  var log = require("npmlog");
3
3
  var bluebird = require("bluebird");
4
-
4
+ const { parseAndCheckLogin } = require("../../utils/client");
5
+ const { getType } = require("../../utils/format");
6
+ const { isReadableStream } = require("../../utils/constants");
5
7
  module.exports = function(defaultFuncs, api, ctx) {
6
8
  function uploadAttachment(attachments, callback) {
7
9
  callback = callback || function() {};
@@ -9,11 +11,11 @@ module.exports = function(defaultFuncs, api, ctx) {
9
11
 
10
12
  // create an array of promises
11
13
  for (var i = 0; i < attachments.length; i++) {
12
- if (!utils.isReadableStream(attachments[i])) {
14
+ if (!isReadableStream(attachments[i])) {
13
15
  throw {
14
16
  error:
15
17
  "Attachment should be a readable stream and not " +
16
- utils.getType(attachments[i]) +
18
+ getType(attachments[i]) +
17
19
  "."
18
20
  };
19
21
  }
@@ -31,7 +33,7 @@ module.exports = function(defaultFuncs, api, ctx) {
31
33
  form,
32
34
  {}
33
35
  )
34
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
36
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
35
37
  .then(function(resData) {
36
38
  if (resData.error) {
37
39
  throw resData;
@@ -105,7 +107,7 @@ module.exports = function(defaultFuncs, api, ctx) {
105
107
  form.payload.tasks[0].payload.attachment_fbids = [];
106
108
  if (form.payload.tasks[0].payload.text == "")
107
109
  form.payload.tasks[0].payload.text = null;
108
- if (utils.getType(msg.attachment) !== "Array") {
110
+ if (getType(msg.attachment) !== "Array") {
109
111
  msg.attachment = [msg.attachment];
110
112
  }
111
113
 
@@ -228,12 +230,12 @@ module.exports = function(defaultFuncs, api, ctx) {
228
230
  return function sendMessageMqtt(msg, threadID, callback, replyToMessage) {
229
231
  if (
230
232
  !callback &&
231
- (utils.getType(threadID) === "Function" ||
232
- utils.getType(threadID) === "AsyncFunction")
233
+ (getType(threadID) === "Function" ||
234
+ getType(threadID) === "AsyncFunction")
233
235
  ) {
234
236
  return threadID({ error: "Pass a threadID as a second argument." });
235
237
  }
236
- if (!replyToMessage && utils.getType(callback) === "String") {
238
+ if (!replyToMessage && getType(callback) === "String") {
237
239
  replyToMessage = callback;
238
240
  callback = function() {};
239
241
  }
@@ -242,9 +244,9 @@ module.exports = function(defaultFuncs, api, ctx) {
242
244
  callback = function(err, friendList) {};
243
245
  }
244
246
 
245
- var msgType = utils.getType(msg);
246
- var threadIDType = utils.getType(threadID);
247
- var messageIDType = utils.getType(replyToMessage);
247
+ var msgType = getType(msg);
248
+ var threadIDType = getType(threadID);
249
+ var messageIDType = getType(replyToMessage);
248
250
 
249
251
  if (msgType !== "String" && msgType !== "Object") {
250
252
  return callback({
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
 
3
- const utils = require("../../utils");
4
3
  const log = require("npmlog");
5
-
4
+ const { getType } = require("../../utils/format");
5
+ const { parseAndCheckLogin } = require("../../utils/client");
6
6
  module.exports = function(defaultFuncs, api, ctx) {
7
7
  function makeTypingIndicator(typ, threadID, callback, isGroup) {
8
8
  const form = {
@@ -14,13 +14,13 @@ module.exports = function(defaultFuncs, api, ctx) {
14
14
 
15
15
  // Check if thread is a single person chat or a group chat
16
16
  // More info on this is in api.sendMessage
17
- if (utils.getType(isGroup) == "Boolean") {
17
+ if (getType(isGroup) == "Boolean") {
18
18
  if (!isGroup) {
19
19
  form.to = threadID;
20
20
  }
21
21
  defaultFuncs
22
22
  .post("https://www.facebook.com/ajax/messaging/typ.php", ctx.jar, form)
23
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
23
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
24
24
  .then(function(resData) {
25
25
  if (resData.error) {
26
26
  throw resData;
@@ -30,7 +30,7 @@ module.exports = function(defaultFuncs, api, ctx) {
30
30
  })
31
31
  .catch(function(err) {
32
32
  log.error("sendTypingIndicator", err);
33
- if (utils.getType(err) == "Object" && err.error === "Not logged in") {
33
+ if (getType(err) == "Object" && err.error === "Not logged in") {
34
34
  ctx.loggedIn = false;
35
35
  }
36
36
  return callback(err);
@@ -52,7 +52,7 @@ module.exports = function(defaultFuncs, api, ctx) {
52
52
  ctx.jar,
53
53
  form
54
54
  )
55
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
55
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
56
56
  .then(function(resData) {
57
57
  if (resData.error) {
58
58
  throw resData;
@@ -63,7 +63,7 @@ module.exports = function(defaultFuncs, api, ctx) {
63
63
  .catch(function(err) {
64
64
  log.error("sendTypingIndicator", err);
65
65
  if (
66
- utils.getType(err) == "Object" &&
66
+ getType(err) == "Object" &&
67
67
  err.error === "Not logged in."
68
68
  ) {
69
69
  ctx.loggedIn = false;
@@ -76,8 +76,8 @@ module.exports = function(defaultFuncs, api, ctx) {
76
76
 
77
77
  return function sendTypingIndicator(threadID, callback, isGroup) {
78
78
  if (
79
- utils.getType(callback) !== "Function" &&
80
- utils.getType(callback) !== "AsyncFunction"
79
+ getType(callback) !== "Function" &&
80
+ getType(callback) !== "AsyncFunction"
81
81
  ) {
82
82
  if (callback) {
83
83
  log.warn(
@@ -92,8 +92,8 @@ module.exports = function(defaultFuncs, api, ctx) {
92
92
 
93
93
  return function end(cb) {
94
94
  if (
95
- utils.getType(cb) !== "Function" &&
96
- utils.getType(cb) !== "AsyncFunction"
95
+ getType(cb) !== "Function" &&
96
+ getType(cb) !== "AsyncFunction"
97
97
  ) {
98
98
  if (cb) {
99
99
  log.warn(