fca-umaru-v1 40.1.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. package/.travis.yml +6 -0
  2. package/CHANGELOG.md +2 -0
  3. package/DOCS.md +1947 -0
  4. package/LICENSE-MIT +21 -0
  5. package/README.md +219 -0
  6. package/index.js +1 -0
  7. package/package.json +67 -0
  8. package/src/addExternalModule.js +1 -0
  9. package/src/addUserToGroup.js +1 -0
  10. package/src/changeAdminStatus.js +1 -0
  11. package/src/changeArchivedStatus.js +1 -0
  12. package/src/changeAvatar.js +1 -0
  13. package/src/changeBio.js +1 -0
  14. package/src/changeBlockedStatus.js +1 -0
  15. package/src/changeGroupImage.js +1 -0
  16. package/src/changeNickname.js +1 -0
  17. package/src/changeThreadColor.js +1 -0
  18. package/src/changeThreadEmoji.js +1 -0
  19. package/src/createNewGroup.js +1 -0
  20. package/src/createPoll.js +1 -0
  21. package/src/deleteMessage.js +1 -0
  22. package/src/deleteThread.js +1 -0
  23. package/src/forwardAttachment.js +1 -0
  24. package/src/getAccessToken.js +1 -0
  25. package/src/getCurrentUserID.js +1 -0
  26. package/src/getEmojiUrl.js +1 -0
  27. package/src/getFriendsList.js +1 -0
  28. package/src/getMessage.js +1 -0
  29. package/src/getThreadHistory.js +1 -0
  30. package/src/getThreadInfo.js +1 -0
  31. package/src/getThreadList.js +1 -0
  32. package/src/getThreadPictures.js +1 -0
  33. package/src/getUserID.js +1 -0
  34. package/src/getUserInfo.js +1 -0
  35. package/src/handleFriendRequest.js +1 -0
  36. package/src/handleMessageRequest.js +1 -0
  37. package/src/httpGet.js +1 -0
  38. package/src/httpPost.js +1 -0
  39. package/src/httpPostFormData.js +1 -0
  40. package/src/listenMqtt.js +1 -0
  41. package/src/logout.js +1 -0
  42. package/src/markAsDelivered.js +1 -0
  43. package/src/markAsRead.js +1 -0
  44. package/src/markAsReadAll.js +1 -0
  45. package/src/markAsSeen.js +1 -0
  46. package/src/muteThread.js +1 -0
  47. package/src/removeUserFromGroup.js +1 -0
  48. package/src/resolvePhotoUrl.js +1 -0
  49. package/src/searchForThread.js +1 -0
  50. package/src/sendMessage.js +1 -0
  51. package/src/sendTypingIndicator.js +1 -0
  52. package/src/setMessageReaction.js +1 -0
  53. package/src/setPostReaction.js +1 -0
  54. package/src/setTitle.js +1 -0
  55. package/src/threadColors.js +1 -0
  56. package/src/unfriend.js +1 -0
  57. package/src/unsendMessage.js +1 -0
  58. package/src/uploadAttachment.js +1 -0
  59. package/utils.js +1 -0
package/DOCS.md ADDED
@@ -0,0 +1,1947 @@
1
+ # Documentation
2
+ ### You can use callback or .then() .catch() or async/await
3
+
4
+ * [`login(credentials, options, [callback])`](#logincredentials-options-callback) ⇒ <code>Promise</code>
5
+ * [`api.addExternalModule(moduleObj)`](#apiaddexternalmodulemoduleobj)
6
+ * [`api.addUserToGroup(userID, threadID, [callback])`](#apiaddusertogroupuserid-threadid-callback) ⇒ <code>Promise</code>
7
+ * [`api.changeAdminStatus(threadID, adminIDs, adminStatus, [callback])`](#apichangeadminstatusthreadid-adminids-adminstatus-callback) ⇒ <code>Promise</code>
8
+ * [`api.changeArchivedStatus(threadOrThreads, archive, [callback])`](#apichangearchivedstatusthreadorthreads-archive-callback) ⇒ <code>Promise</code>
9
+ * [`api.changeBlockedStatus(userID, block, [callback])`](#apichangeblockedstatususerid-block-callback) ⇒ <code>Promise</code>
10
+ * [`api.changeGroupImage(image, threadID, [callback])`](#apichangegroupimageimage-threadid-callback) ⇒ <code>Promise</code>
11
+ * [`api.changeNickname(nickname, threadID, participantID, [callback])`](#apichangenicknamenickname-threadid-participantid-callback) ⇒ <code>Promise</code>
12
+ * [`api.changeThreadColor(color, threadID, [callback])`](#apichangethreadcolorcolor-threadid-callback) ⇒ <code>Promise</code>
13
+ * [`api.changeThreadEmoji(emoji, threadID, [callback])`](#apichangethreademojiemoji-threadid-callback) ⇒ <code>Promise</code>
14
+ * [`api.createNewGroup(participantIDs, groupTitle, [callback])`](#apicreatenewgroupparticipantids-grouptitle-callback) ⇒ <code>Promise</code>
15
+ * [`api.createPoll(title, threadID, options, [callback]) (*temporary deprecated because Facebook is updating this feature*)`](#apicreatepolltitle-threadid-options-callback-temporary-deprecated-because-facebook-is-updating-this-feature) ⇒ <code>Promise</code>
16
+ * [`api.deleteMessage(messageOrMessages, [callback])`](#apideletemessagemessageormessages-callback) ⇒ <code>Promise</code>
17
+ * [`api.deleteThread(threadOrThreads, [callback])`](#apideletethreadthreadorthreads-callback) ⇒ <code>Promise</code>
18
+ * [`api.forwardAttachment(attachmentID, userOrUsers, [callback])`](#apiforwardattachmentattachmentid-userorusers-callback) ⇒ <code>Promise</code>
19
+ * [`api.getAppState()`](#apigetappstate) ⇒ <code>Array</code>
20
+ * [`api.getCurrentUserID()`](#apigetcurrentuserid) ⇒ <code>string</code>
21
+ * [`api.getEmojiUrl(c, size, pixelRatio)`](#apigetemojiurlc-size-pixelratio) ⇒ <code>string</code>
22
+ * [`api.getFriendsList([callback])`](#apigetfriendslistcallback) ⇒ <code>Promise</code>
23
+ * [`api.getMessage(threadID, messageID, [callback])`](#apigetmessagethreadid-messageid-callback) ⇒ <code>Promise</code>
24
+ * [`api.getThreadHistory(threadID, amount, timestamp, [callback])`](#apigetthreadhistorythreadid-amount-timestamp-callback) ⇒ <code>Promise</code>
25
+ * [`api.getThreadInfo(threadIDs, [callback])`](#apigetthreadinfothreadids-callback) ⇒ <code>Promise</code>
26
+ * [`api.getThreadList(limit, timestamp, tags, [callback])`](#apigetthreadlistlimit-timestamp-tags-callback) ⇒ <code>Promise</code>
27
+ * [`api.getThreadPictures(threadID, offset, limit, [callback])`](#apigetthreadpicturesthreadid-offset-limit-callback) ⇒ <code>Promise</code>
28
+ * [`api.getUserID(name, [callback])`](#apigetuseridname-callback) ⇒ <code>Promise</code>
29
+ * [`api.getUserInfo(ids, [callback])`](#apigetuserinfoids-callback) ⇒ <code>Promise</code>
30
+ * [`api.handleMessageRequest(threadID, accept, [callback])`](#apihandlemessagerequestthreadid-accept-callback) ⇒ <code>Promise</code>
31
+ * [`api.httpGet(url, form, [customHeader], [callback], [notAPI])`](#apihttpgeturl-form-customheader-callback-notapi) ⇒ <code>Promise</code>
32
+ * [`api.httpPost(url, form, [customHeader], [callback], [notAPI])`](#apihttpposturl-form-customheader-callback-notapi) ⇒ <code>Promise</code>
33
+ * [`api.httpPostFormData(url, form, [customHeader], [callback], [notAPI])`](#apihttppostformdataurl-form-customheader-callback-notapi) ⇒ <code>Promise</code>
34
+ * [~~`api.listen([callback])`~~](#apilistencallback) ⇒ <code>Promise</code>
35
+ * [`api.listenMqtt([callback])`](#apilistenmqttcallback) ⇒ <code>Promise</code>
36
+ * [`api.logout([callback])`](#apilogoutcallback) ⇒ <code>Promise</code>
37
+ * [`api.markAsDelivered(threadID, messageID, [callback]`](#apimarkasdeliveredthreadid-messageid-callback) ⇒ <code>Promise</code>
38
+ * [`api.markAsRead(threadID, [read, [callback]])`](#apimarkasreadthreadid-read-callback) ⇒ <code>Promise</code>
39
+ * [`api.markAsReadAll([callback])`](#apimarkasreadallcallback) ⇒ <code>Promise</code>
40
+ * [`api.markAsSeen([seenTimestamp], [callback])`](#apimarkasseenseentimestamp-callback) ⇒ <code>Promise</code>
41
+ * [`api.muteThread(threadID, muteSeconds, [callback])`](#apimutethreadthreadid-muteseconds-callback) ⇒ <code>Promise</code>
42
+ * [`api.removeUserFromGroup(userID, threadID, [callback])`](#apiremoveuserfromgroupuserid-threadid-callback) ⇒ <code>Promise</code>
43
+ * [`api.resolvePhotoUrl(photoID, [callback])`](#apiresolvephotourlphotoid-callback) ⇒ <code>Promise</code>
44
+ * [`api.searchForThread(name, [callback])`](#apisearchforthreadname-callback)
45
+ * [`api.sendMessage(message, threadID, [callback], messageID)`](#apisendmessagemessage-threadid-callback-messageid) ⇒ <code>Promise</code>
46
+ * [`api.sendTypingIndicator(threadID, [callback])`](#apisendtypingindicatorthreadid-callback) ⇒ <code>Promise</code>
47
+ * [`api.setMessageReaction(reaction, messageID, [callback], [forceCustomReaction])`](#apisetmessagereactionreaction-messageid-callback-forcecustomreaction) ⇒ <code>Promise</code>
48
+ * [`api.setOptions(options)`](#apisetoptionsoptions) ⇒ <code>Promise</code>
49
+ * [`api.setPostReaction(postID, type, [callback])`](#apisetpostreactionpostid-type-callback) ⇒ <code>Promise</code>
50
+ * [`api.setTitle(newTitle, threadID, [callback])`](#apisettitlenewtitle-threadid-callback) ⇒ <code>Promise</code>
51
+ * [`api.threadColors`](#apithreadcolors) ⇒ <code>Object</code>
52
+ * [`api.unsendMessage(messageID, [callback])`](#apiunsendmessagemessageid-callback) ⇒ <code>Promise</code>
53
+ * [`api.uploadAttachment(attachments, [callback])`](#apiuploadattachmentattachments-callback) ⇒ <code>Promise</code>
54
+
55
+ ---------------------------------------
56
+
57
+ ### Password safety
58
+
59
+ **Read this** before you _copy+paste_ examples from below.
60
+
61
+ You should not store Facebook password in your scripts.
62
+ There are few good reasons:
63
+ * People who are standing behind you may look at your "code" and get your password if it is on the screen
64
+ * Backups of source files may be readable by someone else. "_There is nothing secret in my code, why should I ever password protect my backups_"
65
+ * You can't push your code to Github (or any onther service) without removing your password from the file. Remember: Even if you undo your accidential commit with password, Git doesn't delete it, that commit is just not used but is still readable by everybody.
66
+ * If you change your password in the future (maybe it leaked because _someone_ stored password in source file… oh… well…) you will have to change every occurrence in your scripts
67
+
68
+ Preferred method is to have `login.js` that saves `AppState` to a file and then use that file from all your scripts.
69
+ This way you can put password in your code for a minute, login to facebook and then remove it.
70
+
71
+ If you want to be even more safe: _login.js_ can get password with `require("readline")` or with environment variables like this:
72
+ ```js
73
+ var credentials = {
74
+ email: process.env.FB_EMAIL,
75
+ password: process.env.FB_PASSWORD
76
+ }
77
+ ```
78
+ ```bash
79
+ FB_EMAIL="john.doe@example.com"
80
+ FB_PASSWORD="MySuperHardP@ssw0rd"
81
+ nodejs login.js
82
+ ```
83
+
84
+ ---------------------------------------
85
+
86
+ <a name="login"></a>
87
+ ### login(credentials, options, [callback])
88
+
89
+ This function is returned by `require(...)` and is the main entry point to the API.
90
+
91
+ It allows the user to log into facebook given the right credentials.
92
+
93
+ Return a Promise that will resolve if logged in successfully, or reject if failed to login. (will not resolve or reject if callback is supplied!)
94
+
95
+ If `callback` is supplied:
96
+
97
+ * `callback` will be called with a `null` object (for potential errors) and with an object containing all the available functions if logged in successfully.
98
+
99
+ * `callback` will be called with an error object if failed to login.
100
+
101
+ If `login-approval` error was thrown: Inside error object is `continue` function, you can call that function with 2FA code. The behaviour of this function depends on how you call `login` with:
102
+
103
+ * If `callback` is not supplied (using `Promise`), this function will return a `Promise` that behaves like `Promise` received from `login`.
104
+
105
+ * If `callback` is supplied, this function will still return a `Promise`, but it will not resolve. Instead, the result is called to `callback`.
106
+
107
+ __Arguments__
108
+
109
+ * `credentials`: An object containing the fields `email` and `password` used to login, __*or*__ an object containing the field `appState`.
110
+ * `options`: An object representing options to use when logging in (as described in [api.setOptions](#setOptions)).
111
+ * `callback(err, api)`: A callback called when login is done (successful or not). `err` is an object containing a field `error`.
112
+ ---
113
+
114
+ <h1><b>Now login with account and password is no longer available, <a href="#loginWithAppstate">use appState</a> login instead.</b></h1>
115
+
116
+
117
+ ~~__Example (Email & Password)__: (it is no longer usable, please use [this](#loginWithAppstate) alternative method)~~
118
+
119
+ ```js
120
+ const login = require("fb-chat-api");
121
+
122
+ login({email: "FB_EMAIL", password: "FB_PASSWORD"}, (err, api) => {
123
+ if(err) return console.error(err);
124
+ // Here you can use the api
125
+ });
126
+ ```
127
+
128
+ ~~__Example (Email & Password then save appState to file)__: (it is no longer usable, please use [this](#loginWithAppstate) alternative method)~~
129
+
130
+ ```js
131
+ const fs = require("fs-extra");
132
+ const login = require("fb-chat-api");
133
+
134
+ login({email: "FB_EMAIL", password: "FB_PASSWORD"}, (err, api) => {
135
+ if(err) return console.error(err);
136
+
137
+ fs.writeFileSync('appstate.json', JSON.stringify(api.getAppState()));
138
+ });
139
+ ```
140
+
141
+
142
+ ~~__Login Approvals (2-Factor Auth)__: When you try to login with Login Approvals enabled, your callback will be called with an error `'login-approval'` that has a `continue` function that accepts the approval code as a `string` or a `number`. (it is no longer usable, please use [this](#loginWithAppstate) alternative method)~~
143
+
144
+ __Example__:
145
+
146
+ ```js
147
+ const login = require("fb-chat-api");
148
+ const readline = require("readline");
149
+
150
+ var rl = readline.createInterface({
151
+ input: process.stdin,
152
+ output: process.stdout
153
+ });
154
+
155
+ const obj = {email: "FB_EMAIL", password: "FB_PASSWORD"};
156
+ login(obj, (err, api) => {
157
+ if(err) {
158
+ switch (err.error) {
159
+ case 'login-approval':
160
+ console.log('Enter code > ');
161
+ rl.on('line', (line) => {
162
+ err.continue(line);
163
+ rl.close();
164
+ });
165
+ break;
166
+ default:
167
+ console.error(err);
168
+ }
169
+ return;
170
+ }
171
+
172
+ // Logged in!
173
+ });
174
+ ```
175
+
176
+ __Review Recent Login__: Sometimes Facebook will ask you to review your recent logins. This means you've recently logged in from a unrecognized location. This will will result in the callback being called with an error `'review-recent-login'` by default. If you wish to automatically approve all recent logins, you can set the option `forceLogin` to `true` in the `loginOptions`.
177
+
178
+
179
+
180
+ <a name="loginWithAppstate"></a>
181
+ #### __Example (AppState loaded from file)__: You can get fbstate using [this](https://github.com/ntkhang03/c3c-fbstate) extension
182
+
183
+ ```js
184
+ const fs = require("fs-extra");
185
+ const login = require("fb-chat-api");
186
+
187
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
188
+ if(err) return console.error(err);
189
+ // Here you can use the api
190
+ });
191
+ ```
192
+
193
+
194
+ ---------------------------------------
195
+
196
+ <a name="apiaddexternalmodulemoduleobj"></a>
197
+ ### api.addExternalModule(moduleObj)
198
+
199
+ This function is used to add external modules to the api object, each module is a function that takes 3 arguments: `defaultFuncs`, `api`, `ctx` and returns a function that will be added to the api object.
200
+
201
+ Example:
202
+ ```js
203
+ api.addExternalModule({
204
+ "example": function(defaultFuncs, api, ctx) {
205
+ return function () {
206
+ console.log("globalOptions", ctx.globalOptions);
207
+ };
208
+ }
209
+ });
210
+ ```
211
+
212
+ ---------------------------------------
213
+
214
+ <a name="addUserToGroup"></a>
215
+ ### api.addUserToGroup(userID, threadID, [callback])
216
+
217
+ Adds a user (or array of users) to a group chat.
218
+
219
+ __Arguments__
220
+
221
+ * `userID`: User ID or array of user IDs.
222
+ * `threadID`: Group chat ID.
223
+ * `callback(err)`: A callback called when the query is done (either with an error or with no arguments).
224
+
225
+ __Example__
226
+
227
+ ```js
228
+ api.addUserToGroup("1234567890", "0987654321", (err) => {
229
+ if(err)
230
+ return console.error(err);
231
+ console.log("Added user to group.");
232
+ });
233
+ ```
234
+
235
+ ---------------------------------------
236
+
237
+ <a name="changeAdminStatus"></a>
238
+ ### api.changeAdminStatus(threadID, adminIDs, adminStatus, [callback])
239
+
240
+ Given a adminID, or an array of adminIDs, will set the admin status of the user(s) to `adminStatus`.
241
+
242
+ __Arguments__
243
+ * `threadID`: ID of a group chat (can't use in one-to-one conversations)
244
+ * `adminIDs`: The id(s) of users you wish to admin/unadmin (string or an array).
245
+ * `adminStatus`: Boolean indicating whether the user(s) should be promoted to admin (`true`) or demoted to a regular user (`false`).
246
+ * `callback(err)`: A callback called when the query is done (either with an error or null).
247
+
248
+ __Example__
249
+
250
+ ```js
251
+ const fs = require("fs-extra");
252
+ const login = require("fb-chat-api");
253
+
254
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
255
+ if (err) return console.error(err);
256
+
257
+ let threadID = "0000000000000000";
258
+ let newAdmins = ["111111111111111", "222222222222222"];
259
+ api.changeAdminStatus(threadID, newAdmins, true, editAdminsCallback);
260
+
261
+ let adminToRemove = "333333333333333";
262
+ api.changeAdminStatus(threadID, adminToRemove, false, editAdminsCallback);
263
+
264
+ });
265
+
266
+ function editAdminsCallback(err) {
267
+ if (err) return console.error(err);
268
+ }
269
+
270
+ ```
271
+
272
+ ---------------------------------------
273
+
274
+ <a name="changeArchivedStatus"></a>
275
+ ### api.changeArchivedStatus(threadOrThreads, archive, [callback])
276
+
277
+ Given a threadID, or an array of threadIDs, will set the archive status of the threads to `archive`. Archiving a thread will hide it from the logged-in user's inbox until the next time a message is sent or received.
278
+
279
+ __Arguments__
280
+ * `threadOrThreads`: The id(s) of the threads you wish to archive/unarchive.
281
+ * `archive`: Boolean indicating the new archive status to assign to the thread(s).
282
+ * `callback(err)`: A callback called when the query is done (either with an error or null).
283
+
284
+ __Example__
285
+
286
+ ```js
287
+ const fs = require("fs-extra");
288
+ const login = require("fb-chat-api");
289
+
290
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
291
+ if(err) return console.error(err);
292
+
293
+ api.changeArchivedStatus("000000000000000", true, (err) => {
294
+ if(err) return console.error(err);
295
+ });
296
+ });
297
+ ```
298
+
299
+ ---------------------------------------
300
+
301
+ <a name="changeBlockedStatus"></a>
302
+ ### api.changeBlockedStatus(userID, block, [callback])
303
+
304
+ Prevents a user from privately contacting you. (Messages in a group chat will still be seen by both parties).
305
+
306
+ __Arguments__
307
+
308
+ * `userID`: User ID.
309
+ * `block`: Boolean indicating whether to block or unblock the user (true for block).
310
+ * `callback(err)`: A callback called when the query is done (either with an error or with no arguments).
311
+
312
+ ---------------------------------------
313
+
314
+ <a name="changeGroupImage"></a>
315
+ ### api.changeGroupImage(image, threadID, [callback])
316
+
317
+ Will change the group chat's image to the given image.
318
+
319
+ __Arguments__
320
+ * `image`: File stream of image.
321
+ * `threadID`: String representing the ID of the thread.
322
+ * `callback(err)`: A callback called when the change is done (either with an error or null).
323
+
324
+ __Example__
325
+
326
+ ```js
327
+ const fs = require("fs-extra");
328
+ const login = require("fb-chat-api");
329
+
330
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
331
+ if(err) return console.error(err);
332
+
333
+ api.changeGroupImage(fs.createReadStream("./avatar.png"), "000000000000000", (err) => {
334
+ if(err) return console.error(err);
335
+ });
336
+ });
337
+ ```
338
+
339
+ ---------------------------------------
340
+
341
+ <a name="changeNickname"></a>
342
+ ### api.changeNickname(nickname, threadID, participantID, [callback])
343
+
344
+ Will change the thread user nickname to the one provided.
345
+
346
+ __Arguments__
347
+ * `nickname`: String containing a nickname. Leave empty to reset nickname.
348
+ * `threadID`: String representing the ID of the thread.
349
+ * `participantID`: String representing the ID of the user.
350
+ * `callback(err)`: An optional callback called when the change is done (either with an error or null).
351
+
352
+ __Example__
353
+
354
+ ```js
355
+ const fs = require("fs-extra");
356
+ const login = require("fb-chat-api");
357
+
358
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
359
+ if(err) return console.error(err);
360
+
361
+ api.changeNickname("Example", "000000000000000", "000000000000000", (err) => {
362
+ if(err) return console.error(err);
363
+ });
364
+ });
365
+ ```
366
+
367
+ ---------------------------------------
368
+
369
+ <a name="changeThreadColor"></a>
370
+ ### api.changeThreadColor(color, threadID, [callback])
371
+
372
+ Will change the thread color to the given hex string color ("#0000ff"). Set it
373
+ to empty string if you want the default.
374
+
375
+ Note: the color needs to start with a "#".
376
+
377
+ __Arguments__
378
+ * `color`: String representing a theme ID (a list of theme ID can be found at `api.threadColors`).
379
+ * `threadID`: String representing the ID of the thread.
380
+ * `callback(err)`: A callback called when the change is done (either with an error or null).
381
+
382
+ __Example__
383
+
384
+ ```js
385
+ const fs = require("fs-extra");
386
+ const login = require("fb-chat-api");
387
+
388
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
389
+ if(err) return console.error(err);
390
+
391
+ api.changeThreadColor("#0000ff", "000000000000000", (err) => {
392
+ if(err) return console.error(err);
393
+ });
394
+ });
395
+ ```
396
+
397
+ ---------------------------------------
398
+
399
+ <a name="changeThreadEmoji"></a>
400
+ ### api.changeThreadEmoji(emoji, threadID, [callback])
401
+
402
+ Will change the thread emoji to the one provided.
403
+
404
+ Note: The UI doesn't play nice with all emoji.
405
+
406
+ __Arguments__
407
+ * `emoji`: String containing a single emoji character.
408
+ * `threadID`: String representing the ID of the thread.
409
+ * `callback(err)`: A callback called when the change is done (either with an error or null).
410
+
411
+ __Example__
412
+
413
+ ```js
414
+ const fs = require("fs-extra");
415
+ const login = require("fb-chat-api");
416
+
417
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
418
+ if(err) return console.error(err);
419
+
420
+ api.changeThreadEmoji("💯", "000000000000000", (err) => {
421
+ if(err) return console.error(err);
422
+ });
423
+ });
424
+ ```
425
+
426
+ ---------------------------------------
427
+
428
+ <a name="createNewGroup"></a>
429
+ ### api.createNewGroup(participantIDs, groupTitle, [callback])
430
+
431
+ Create a new group chat.
432
+
433
+ __Arguments__
434
+ * `participantIDs`: An array containing participant IDs. (*Length must be >= 2*)
435
+ * `groupTitle`: The title of the new group chat.
436
+ * `callback(err, threadID)`: A callback called when created.
437
+
438
+ ---------------------------------------
439
+
440
+ <a name="createPoll"></a>
441
+ ### api.createPoll(title, threadID, options, [callback]) (*temporary deprecated because Facebook is updating this feature*)
442
+
443
+ Creates a poll with the specified title and optional poll options, which can also be initially selected by the logged-in user.
444
+
445
+ __Arguments__
446
+ * `title`: String containing a title for the poll.
447
+ * `threadID`: String representing the ID of the thread.
448
+ * `options`: An optional `string : bool` dictionary to specify initial poll options and their initial states (selected/not selected), respectively.
449
+ * `callback(err)`: An optional callback called when the poll is posted (either with an error or null) - can omit the `options` parameter and use this as the third parameter if desired.
450
+
451
+ __Example__
452
+
453
+ ```js
454
+ const fs = require("fs-extra");
455
+ const login = require("fb-chat-api");
456
+
457
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
458
+ if(err) return console.error(err);
459
+
460
+ api.createPoll("Example Poll", "000000000000000", {
461
+ "Option 1": false,
462
+ "Option 2": true
463
+ }, (err) => {
464
+ if(err) return console.error(err);
465
+ });
466
+ });
467
+ ```
468
+
469
+ ---------------------------------------
470
+
471
+ <a name="deleteMessage"></a>
472
+ ### api.deleteMessage(messageOrMessages, [callback])
473
+
474
+ Takes a messageID or an array of messageIDs and deletes the corresponding message.
475
+
476
+ __Arguments__
477
+ * `messageOrMessages`: A messageID string or messageID string array
478
+ * `callback(err)`: A callback called when the query is done (either with an error or null).
479
+
480
+ __Example__
481
+ ```js
482
+ const fs = require("fs-extra");
483
+ const login = require("fb-chat-api");
484
+
485
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
486
+ if(err) return console.error(err);
487
+
488
+ api.listen((err, message) => {
489
+ if(message.body) {
490
+ api.sendMessage(message.body, message.threadID, (err, messageInfo) => {
491
+ if(err) return console.error(err);
492
+
493
+ api.deleteMessage(messageInfo.messageID);
494
+ });
495
+ }
496
+ });
497
+ });
498
+ ```
499
+
500
+ ---------------------------------------
501
+
502
+ <a name="deleteThread"></a>
503
+ ### api.deleteThread(threadOrThreads, [callback])
504
+
505
+ Given a threadID, or an array of threadIDs, will delete the threads from your account. Note that this does *not* remove the messages from Facebook's servers - anyone who hasn't deleted the thread can still view all of the messages.
506
+
507
+ __Arguments__
508
+
509
+ * `threadOrThreads` - The id(s) of the threads you wish to remove from your account.
510
+ * `callback(err)` - A callback called when the operation is done, maybe with an object representing an error.
511
+
512
+ __Example__
513
+
514
+ ```js
515
+ const fs = require("fs-extra");
516
+ const login = require("fb-chat-api");
517
+
518
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
519
+ if(err) return console.error(err);
520
+
521
+ api.deleteThread("000000000000000", (err) => {
522
+ if(err) return console.error(err);
523
+ });
524
+ });
525
+ ```
526
+
527
+ ---------------------------------------
528
+
529
+ <a name="forwardAttachment"></a>
530
+ ### api.forwardAttachment(attachmentID, userOrUsers, [callback])
531
+
532
+ Forwards corresponding attachment to given userID or to every user from an array of userIDs
533
+
534
+ __Arguments__
535
+ * `attachmentID`: The ID field in the attachment object. Recorded audio cannot be forwarded.
536
+ * `userOrUsers`: A userID string or usersID string array
537
+ * `callback(err)`: A callback called when the query is done (either with an error or null).
538
+
539
+ ---------------------------------------
540
+
541
+ <a name="getAppState"></a>
542
+ ### api.getAppState()
543
+
544
+ Returns current appState which can be saved to a file or stored in a variable.
545
+
546
+ ---------------------------------------
547
+
548
+ <a name="getCurrentUserID"></a>
549
+ ### api.getCurrentUserID()
550
+
551
+ Returns the currently logged-in user's Facebook user ID.
552
+
553
+ ---------------------------------------
554
+
555
+ <a name="getEmojiUrl"></a>
556
+ ### api.getEmojiUrl(c, size, pixelRatio)
557
+
558
+ Returns the URL to a Facebook Messenger-style emoji image asset.
559
+
560
+ __note__: This function will return a URL regardless of whether the image at the URL actually exists.
561
+ This can happen if, for example, Messenger does not have an image asset for the requested emoji.
562
+
563
+ __Arguments__
564
+
565
+ * `c` - The emoji character
566
+ * `size` - The width and height of the emoji image; supported sizes are 32, 64, and 128
567
+ * `pixelRatio` - The pixel ratio of the emoji image; supported ratios are '1.0' and '1.5' (default is '1.0')
568
+
569
+ __Example__
570
+
571
+ ```js
572
+ const fs = require("fs-extra");
573
+ const login = require("fb-chat-api");
574
+
575
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
576
+ if(err) return console.error(err);
577
+
578
+ // Prints https://static.xx.fbcdn.net/images/emoji.php/v8/z9c/1.0/128/1f40d.png
579
+ console.log('Snake emoji, 128px (128x128 with pixel ratio of 1.0');
580
+ console.log(api.getEmojiUrl('\ud83d\udc0d', 128));
581
+
582
+ // Prints https://static.xx.fbcdn.net/images/emoji.php/v8/ze1/1.5/128/1f40d.png
583
+ console.log('Snake emoji, 192px (128x128 with pixel ratio of 1.5');
584
+ console.log(api.getEmojiUrl('\ud83d\udc0d', 128, '1.5'));
585
+ });
586
+ ```
587
+
588
+ ---------------------------------------
589
+
590
+ <a name="getFriendsList"></a>
591
+ ### api.getFriendsList([callback])
592
+
593
+ Returns an array of objects with some information about your friends.
594
+
595
+ __Arguments__
596
+
597
+ * `callback(err, arr)` - A callback called when the query is done (either with an error or with an confirmation object). `arr` is an array of objects with the following fields: `alternateName`, `firstName`, `gender`, `userID`, `isFriend`, `fullName`, `profilePicture`, `type`, `profileUrl`, `vanity`, `isBirthday`.
598
+
599
+ __Example__
600
+
601
+ ```js
602
+ const fs = require("fs-extra");
603
+ const login = require("fb-chat-api");
604
+
605
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
606
+ if(err) return console.error(err);
607
+
608
+ api.getFriendsList((err, data) => {
609
+ if(err) return console.error(err);
610
+
611
+ console.log(data.length);
612
+ });
613
+ });
614
+ ```
615
+
616
+ ---------------------------------------
617
+
618
+ <a name="getMessage"></a>
619
+ ### api.getMessage(threadID, messageID, [callback])
620
+
621
+ Returns message data from messageID
622
+
623
+ __Arguments__
624
+
625
+ * `threadID`: The ID of the thread you want to get the message from.
626
+ * `messageID`: The ID of the message you want to get.
627
+ * `callback(err, data)` - A callback called when the query is done.
628
+
629
+ ---------------------------------------
630
+ <a name="getThreadHistory"></a>
631
+ ### api.getThreadHistory(threadID, amount, timestamp, [callback])
632
+
633
+ Takes a threadID, number of messages, a timestamp, and a callback.
634
+
635
+ __note__: if you're getting a 500 error, it's possible that you're requesting too many messages. Try reducing that number and see if that works.
636
+
637
+ __Arguments__
638
+ * `threadID`: A threadID corresponding to the target chat
639
+ * `amount`: The amount of messages to *request*
640
+ * `timestamp`: Used to described the time of the most recent message to load. If timestamp is `undefined`, facebook will load the most recent messages.
641
+ * `callback(error, history)`: If error is null, history will contain an array of message objects.
642
+
643
+ __Example__
644
+
645
+ To load 50 messages at a time, we can use `undefined` as the timestamp to retrieve the most recent messages and use the timestamp of the earliest message to load the next 50.
646
+
647
+ ```js
648
+ var timestamp = undefined;
649
+
650
+ function loadNextThreadHistory(api){
651
+ api.getThreadHistory(threadID, 50, timestamp, (err, history) => {
652
+ if(err) return console.error(err);
653
+
654
+ /*
655
+ Since the timestamp is from a previous loaded message,
656
+ that message will be included in this history so we can discard it unless it is the first load.
657
+ */
658
+ if(timestamp != undefined) history.pop();
659
+
660
+ /*
661
+ Handle message history
662
+ */
663
+
664
+ timestamp = history[0].timestamp;
665
+ });
666
+ }
667
+ ```
668
+
669
+ ---------------------------------------
670
+
671
+ <a name="getThreadInfo"></a>
672
+ ### api.getThreadInfo(threadIDs, [callback])
673
+
674
+ Takes a threadID and a callback. Works for both single-user and group threads.
675
+
676
+ __Arguments__
677
+ * `threadIDs`: Either a string/number for one ID or an array of strings/numbers for a batched query.
678
+ * `callback(err, info)`: If `err` is `null`, `info` will return
679
+ <!-- * in nghiêng chữ -->
680
+ *if `threadIDs` is an array of IDs, `info` will be an array of objects with the following fields:*
681
+ ```js
682
+ {
683
+ "4000000000000000": {
684
+ threadID: "4000000000000000",
685
+ threadName: "Thread Name",
686
+ // ...
687
+ // thread info
688
+ },
689
+ "5000000000000000": {
690
+ threadID: "5000000000000000",
691
+ threadName: "Thread Name",
692
+ // ...
693
+ // thread info
694
+ },
695
+ // ...
696
+ }
697
+ ```
698
+
699
+ *if `threadIDs` is a single ID, `info` will be an object with the following fields:*
700
+ ```js
701
+ {
702
+ threadID: "4000000000000000",
703
+ threadName: "Thread Name",
704
+ // ...
705
+ // thread info
706
+ }
707
+ ```
708
+
709
+ `info` will contain the following fields:
710
+
711
+ | Key | Description |
712
+ | :---------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
713
+ | threadID | ID of the thread |
714
+ | participantIDs | Array of user IDs in the thread |
715
+ | threadName | Name of the thread. Usually the name of the user. In group chats, this will be empty if the name of the group chat is unset. |
716
+ | userInfo | An array contains info of members, which has the same structure as [`getUserInfo`](#getUserInfo), but add a key `id`, contain ID of member currently at. |
717
+ | nicknames | Map of nicknames for members of the thread. If there are no nicknames set, this will be `null`. Can be of the form: <ul><li>`{'123456789': "nickname"}`</ul></li> |
718
+ | unreadCount | Number of unread messages |
719
+ | messageCount | Number of messages |
720
+ | imageSrc | URL to the group chat photo. `null` if unset or a 1-1 thread. |
721
+ | timestamp | Timestamp of last activity |
722
+ | muteUntil | Timestamp at which the thread will no longer be muted. The timestamp will be -1 if the thread is muted indefinitely or null if the thread is not muted. |
723
+ | isGroup | boolean, true if this thread is a group thread (more than 2 participants). |
724
+ | isSubscribed | |
725
+ | folder | The folder that the thread is in. Can be one of: `INBOX`, `ARCHIVED`, `PENDING` or `OTHER` |
726
+ | isArchived | True if the thread is archived, false if not |
727
+ | cannotReplyReason | If you cannot reply to this thread, this will be a string stating why. Otherwise it will be null. |
728
+ | lastReadTimestamp | Timestamp of the last message that is marked as 'read' by the current user. |
729
+ | emoji | Object with key 'emoji' whose value is the emoji unicode character. Null if unset. |
730
+ | color | String form of the custom color in hexadecimal form. |
731
+ | adminIDs | Array of user IDs of the admins of the thread. Empty array if unset. Can be of the form:<ul><li>`[{ id: '123456789' }]`</li></ul> |
732
+ | approvalMode | `true` or `false`, used to check if this group requires admin approval to add users |
733
+ | approvalQueue | Array of object that has the following keys: <ul><li>`inviterID`: ID of the user invited the person to the group</li><li>`requesterID`: ID of the person waiting to be approved</li><li>`timestamp`: Request timestamp</li></ul> |
734
+ | inviteLink | Invite link for the thread. <ul><li>`enable`: `true` if the invite link is enabled, `false` if it is disabled</li> <li>`link`: Invite link</li></ul> |
735
+
736
+ `accountType` is one of the following:
737
+ - `"User"`
738
+ - `"Page"`
739
+ - `"UnavailableMessagingActor"`
740
+ - `"ReducedMessagingActor"`
741
+
742
+ ---------------------------------------
743
+
744
+ <a name="getThreadList"></a>
745
+ ### api.getThreadList(limit, timestamp, tags, [callback])
746
+
747
+ Returns information about the user's threads.
748
+
749
+ __Arguments__
750
+
751
+ * `limit`: Limit the number of threads to fetch.
752
+ * `timestamp`: Request threads *before* this date. `null` means *now*
753
+ * `tags`: An array describing which folder to fetch. It should be one of these:
754
+ - `["INBOX"]` *(same as `[]`)*
755
+ - `["ARCHIVED"]`
756
+ - `["PENDING"]`
757
+ - `["OTHER"]`
758
+ - `["INBOX", "unread"]`
759
+ - `["ARCHIVED", "unread"]`
760
+ - `["PENDING", "unread"]`
761
+ - `["OTHER", "unread"]`
762
+
763
+ *if you find something new, let us know*
764
+
765
+ * `callback(err, list)`: Callback called when the query is done (either with an error or with a proper result). `list` is an *array* with objects with the following properties same structure as [`getThreadInfo`](#getThreadInfo)
766
+
767
+ `accountType` is one of the following:
768
+ - `"User"`
769
+ - `"Page"`
770
+ - `"UnavailableMessagingActor"`
771
+ - `"ReducedMessagingActor"`
772
+
773
+ (*there might be more*)
774
+
775
+ <table>
776
+ <tr>
777
+ <th>Account type</th>
778
+ <th>Key</th>
779
+ <th>Description</th>
780
+ </tr>
781
+ <tr>
782
+ <td rowspan="12"><code>"User"</code></td>
783
+ <td>userID</td>
784
+ <td>ID of user</td>
785
+ </tr>
786
+ <tr>
787
+ <td>name</td>
788
+ <td>Full name of user</td>
789
+ </tr>
790
+ <tr>
791
+ <td>shortName</td>
792
+ <td>Short name of user (most likely first name)</td>
793
+ </tr>
794
+ <tr>
795
+ <td>gender</td>
796
+ <td>Either
797
+ <code>"MALE"</code>,
798
+ <code>"FEMALE"</code>,
799
+ <code>"NEUTER"</code> or
800
+ <code>"UNKNOWN"</code>
801
+ </td>
802
+ </tr>
803
+ <tr>
804
+ <td>url</td>
805
+ <td>URL of the user's Facebook profile</td>
806
+ </tr>
807
+ <tr>
808
+ <td>profilePicture</td>
809
+ <td>URL of the profile picture</td>
810
+ </tr>
811
+ <tr>
812
+ <td>username</td>
813
+ <td>Username of user or
814
+ <code>null</code>
815
+ </td>
816
+ </tr>
817
+ <tr>
818
+ <td>isViewerFriend</td>
819
+ <td>Is the user a friend of you?</td>
820
+ </tr>
821
+ <tr>
822
+ <td>isMessengerUser</td>
823
+ <td>Does the user use Messenger?</td>
824
+ </tr>
825
+ <tr>
826
+ <td>isVerified</td>
827
+ <td>Is the user verified? (Little blue tick mark)</td>
828
+ </tr>
829
+ <tr>
830
+ <td>isMessageBlockedByViewer</td>
831
+ <td>Is the user blocking messages from you?</td>
832
+ </tr>
833
+ <tr>
834
+ <td>isViewerCoworker</td>
835
+ <td>Is the user your coworker?
836
+ </td>
837
+ </tr>
838
+
839
+ <tr>
840
+ <td rowspan="10"><code>"Page"</code></td>
841
+ <td>userID</td>
842
+ <td>ID of the page</td>
843
+ </tr>
844
+ <tr>
845
+ <td>name</td>
846
+ <td>Name of the fanpage</td>
847
+ </tr>
848
+ <tr>
849
+ <td>url</td>
850
+ <td>URL of the fanpage</td>
851
+ </tr>
852
+ <tr>
853
+ <td>profilePicture</td>
854
+ <td>URL of the profile picture</td>
855
+ </tr>
856
+ <tr>
857
+ <td>username</td>
858
+ <td>Username of user or
859
+ <code>null</code>
860
+ </td>
861
+ </tr>
862
+ <tr>
863
+ <td>acceptsMessengerUserFeedback</td>
864
+ <td></td>
865
+ </tr>
866
+ <tr>
867
+ <td>isMessengerUser</td>
868
+ <td>Does the fanpage use Messenger?</td>
869
+ </tr>
870
+ <tr>
871
+ <td>isVerified</td>
872
+ <td>Is the fanpage verified? (Little blue tick mark)</td>
873
+ </tr>
874
+ <tr>
875
+ <td>isMessengerPlatformBot</td>
876
+ <td>Is the fanpage a bot</td>
877
+ </tr>
878
+ <tr>
879
+ <td>isMessageBlockedByViewer</td>
880
+ <td>Is the fanpage blocking messages from you?</td>
881
+ </tr>
882
+
883
+ <tr>
884
+ <td rowspan="7"><code>"ReducedMessagingActor"</code><br />(account requres verification,<br />messages are hidden)</td>
885
+ <td>userID</td>
886
+ <td>ID of the user</td>
887
+ </tr>
888
+ <tr>
889
+ <td>name</td>
890
+ <td>Name of the user</td>
891
+ </tr>
892
+ <tr>
893
+ <td>url</td>
894
+ <td>
895
+ <code>null</code>
896
+ </td>
897
+ </tr>
898
+ <tr>
899
+ <td>profilePicture</td>
900
+ <td>URL of the default Facebook profile picture</td>
901
+ </tr>
902
+ <tr>
903
+ <td>username</td>
904
+ <td>Username of user</td>
905
+ </td>
906
+ </tr>
907
+ <tr>
908
+ <td>acceptsMessengerUserFeedback</td>
909
+ <td></td>
910
+ </tr>
911
+ <tr>
912
+ <td>isMessageBlockedByViewer</td>
913
+ <td>Is the user blocking messages from you?</td>
914
+ </tr>
915
+ <tr>
916
+ <td rowspan="7"><code>"UnavailableMessagingActor"</code><br />(account disabled/removed)</td>
917
+ <td>userID</td>
918
+ <td>ID of the user</td>
919
+ </tr>
920
+ <tr>
921
+ <td>name</td>
922
+ <td><em>Facebook User</em> in user's language</td>
923
+ </tr>
924
+ <tr>
925
+ <td>url</td>
926
+ <td><code>null</code></td>
927
+ </tr>
928
+ <tr>
929
+ <td>profilePicture</td>
930
+ <td>URL of the default **male** Facebook profile picture</td>
931
+ </tr>
932
+ <tr>
933
+ <td>username</td>
934
+ <td><code>null</code></td>
935
+ </tr>
936
+ <tr>
937
+ <td>acceptsMessengerUserFeedback</td>
938
+ <td></td>
939
+ </tr>
940
+ <tr>
941
+ <td>isMessageBlockedByViewer</td>
942
+ <td>Is the user blocking messages from you?</td>
943
+ </tr>
944
+ </table>
945
+
946
+
947
+ In a case that some account type is not supported, we return just this *(but you can't rely on it)* and log a warning to the console:
948
+
949
+ | Key | Description |
950
+ | ----------- | --------------------- |
951
+ | accountType | type, can be anything |
952
+ | userID | ID of the account |
953
+ | name | Name of the account |
954
+
955
+
956
+ ---------------------------------------
957
+
958
+ <a name="getThreadPictures"></a>
959
+ ### api.getThreadPictures(threadID, offset, limit, [callback])
960
+
961
+ Returns pictures sent in the thread.
962
+
963
+ __Arguments__
964
+
965
+ * `threadID`: A threadID corresponding to the target chat
966
+ * `offset`: Start index of picture to retrieve, where 0 is the most recent picture
967
+ * `limit`: Number of pictures to get, incrementing from the offset index
968
+ * `callback(err, arr)`: A callback called when the query is done (either with an error or with an confirmation object). `arr` is an array of objects with `uri`, `width`, and `height`.
969
+
970
+ ---------------------------------------
971
+
972
+ <a name="getUserID"></a>
973
+ ### api.getUserID(name, [callback])
974
+
975
+ Given the full name or vanity name of a Facebook user, event, page, group or app, the call will perform a Facebook Graph search and return all corresponding IDs (order determined by Facebook).
976
+
977
+ __Arguments__
978
+
979
+ * `name` - A string being the name of the item you're looking for.
980
+ * `callback(err, obj)` - A callback called when the search is done (either with an error or with the resulting object). `obj` is an array which contains all of the items that facebook graph search found, ordered by "importance". Each item in the array has the following properties: `userID`,`photoUrl`,`indexRank`, `name`, `isVerified`, `profileUrl`, `category`, `score`, `type` (type is generally user, group, page, event or app).
981
+
982
+ __Example__
983
+
984
+ ```js
985
+ const fs = require("fs-extra");
986
+ const login = require("fb-chat-api");
987
+
988
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
989
+ if(err) return console.error(err);
990
+
991
+ api.getUserID("Marc Zuckerbot", (err, data) => {
992
+ if(err) return console.error(err);
993
+
994
+ // Send the message to the best match (best by Facebook's criteria)
995
+ var msg = "Hello!"
996
+ var threadID = data[0].userID;
997
+ api.sendMessage(msg, threadID);
998
+ });
999
+ });
1000
+ ```
1001
+
1002
+ ---------------------------------------
1003
+
1004
+ <a name="getUserInfo"></a>
1005
+ ### api.getUserInfo(ids, [callback])
1006
+
1007
+ Will get some information about the given users.
1008
+
1009
+ __Arguments__
1010
+
1011
+ * `ids` - Either a string/number for one ID or an array of strings/numbers for a batched query.
1012
+ * `callback(err, obj)` - A callback called when the query is done (either with an error or with an confirmation object). `obj` is a mapping from userId to another object containing the following properties:
1013
+
1014
+ | Key | Description |
1015
+ | ------------- | ------------------------------------------------------------------ |
1016
+ | name | Name of the user |
1017
+ | firstName | First name of the user |
1018
+ | vanity | the username of the user if any |
1019
+ | thumbSrc | URL of the profile picture |
1020
+ | profileUrl | URL of the profile |
1021
+ | gender | the gender of the user, with 1 is Female, 2 is Male, 0 is unknown |
1022
+ | type | type is generally user, group, page, event or app |
1023
+ | isFriend | is the user a friend of the current user, either `true` or `false` |
1024
+ | isBirthday | is the user having a birthday today, either `true` or `false` |
1025
+ | searchTokens | an array of strings that can be used to search for the user |
1026
+ | alternateName | |
1027
+
1028
+ __Example__
1029
+
1030
+ ```js
1031
+ const fs = require("fs-extra");
1032
+ const login = require("fb-chat-api");
1033
+
1034
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1035
+ if(err) return console.error(err);
1036
+
1037
+ api.getUserInfo([1, 2, 3, 4], (err, ret) => {
1038
+ if(err) return console.error(err);
1039
+
1040
+ for(var prop in ret) {
1041
+ if(ret.hasOwnProperty(prop) && ret[prop].isBirthday) {
1042
+ api.sendMessage("Happy birthday :)", prop);
1043
+ }
1044
+ }
1045
+ });
1046
+ });
1047
+ ```
1048
+
1049
+ ---------------------------------------
1050
+
1051
+ <a name="threadColors"></a>
1052
+ ### api.threadColors
1053
+
1054
+ A dictionary mapping names of all currently valid thread themes to their theme ID that are accepted by [`api.changeThreadColor`](#changeThreadColor). These themes, listed below, are the ones present in the palette UI used for selecting thread themes on the Messenger client.
1055
+ <details>
1056
+ <summary><b>List of colors:</b></summary>
1057
+ <br>
1058
+
1059
+ - MessengerBlue: `196241301102133`
1060
+ - Viking: `1928399724138152`
1061
+ - GoldenPoppy: `174636906462322`
1062
+ - RadicalRed: `2129984390566328`
1063
+ - Shocking: `2058653964378557`
1064
+ - FreeSpeechGreen: `2136751179887052`
1065
+ - Pumpkin: `175615189761153`
1066
+ - LightCoral: `980963458735625`
1067
+ - MediumSlateBlue: `234137870477637`
1068
+ - DeepSkyBlue: `2442142322678320`
1069
+ - BrilliantRose: `169463077092846`
1070
+ - DefaultBlue: `196241301102133`
1071
+ - HotPink: `169463077092846`
1072
+ - AquaBlue: `2442142322678320`
1073
+ - BrightPurple: `234137870477637`
1074
+ - CoralPink: `980963458735625`
1075
+ - Orange: `175615189761153`
1076
+ - Green: `2136751179887052`
1077
+ - LavenderPurple: `2058653964378557`
1078
+ - Red: `2129984390566328`
1079
+ - Yellow: `174636906462322`
1080
+ - TealBlue: `1928399724138152`
1081
+ - Aqua: `417639218648241`
1082
+ - Mango: `930060997172551`
1083
+ - Berry: `164535220883264`
1084
+ - Citrus: `370940413392601`
1085
+ - Candy: `205488546921017`
1086
+ - Earth: `1833559466821043`
1087
+ - Support: `365557122117011`
1088
+ - Music: `339021464972092`
1089
+ - Pride: `1652456634878319`
1090
+ - DoctorStrange: `538280997628317`
1091
+ - LoFi: `1060619084701625`
1092
+ - Sky: `3190514984517598`
1093
+ - LunarNewYear: `357833546030778`
1094
+ - Celebration: `627144732056021`
1095
+ - Chill: `390127158985345`
1096
+ - StrangerThings: `1059859811490132`
1097
+ - Dune: `1455149831518874`
1098
+ - Care: `275041734441112`
1099
+ - Astrology: `3082966625307060`
1100
+ - JBalvin: `184305226956268`
1101
+ - Birthday: `621630955405500`
1102
+ - Cottagecore: `539927563794799`
1103
+ - Ocean: `736591620215564`
1104
+ - Love: `741311439775765`
1105
+ - TieDye: `230032715012014`
1106
+ - Monochrome: `788274591712841`
1107
+ - Default: `3259963564026002`
1108
+ - Rocket: `582065306070020`
1109
+ - Berry2: `724096885023603`
1110
+ - Candy2: `624266884847972`
1111
+ - Unicorn: `273728810607574`
1112
+ - Tropical: `262191918210707`
1113
+ - Maple: `2533652183614000`
1114
+ - Sushi: `909695489504566`
1115
+ - Citrus2: `557344741607350`
1116
+ - Lollipop: `280333826736184`
1117
+ - Shadow: `271607034185782`
1118
+ - Rose: `1257453361255152`
1119
+ - Lavender: `571193503540759`
1120
+ - Tulip: `2873642949430623`
1121
+ - Classic: `3273938616164733`
1122
+ - Peach: `3022526817824329`
1123
+ - Honey: `672058580051520`
1124
+ - Kiwi: `3151463484918004`
1125
+ - Grape: `193497045377796`
1126
+ - NonBinary: `737761000603635`
1127
+ - ~~StarWars: `809305022860427`~~ (Facebook removed it.)
1128
+ </details>
1129
+
1130
+ ---------------------------------------
1131
+
1132
+ <a name="handleMessageRequest"></a>
1133
+ ### api.handleMessageRequest(threadID, accept, [callback])
1134
+
1135
+ Accept or ignore message request(s) with thread id `threadID`.
1136
+
1137
+ __Arguments__
1138
+
1139
+ * `threadID`: A threadID or array of threadIDs corresponding to the target thread(s). Can be numbers or strings.
1140
+ * `accept`: Boolean indicating the new status to assign to the message request(s); true for inbox, false to others.
1141
+ * `callback(err)`: A callback called when the query is done (with an error or with null).
1142
+
1143
+ ---------------------------------------
1144
+
1145
+ <a name="httpGet"></a>
1146
+ ### api.httpGet(url, form, [customHeader], [callback], [notAPI])
1147
+
1148
+ Get data from a URL with method GET.
1149
+
1150
+ __Arguments__
1151
+
1152
+ * `url`: A string being the URL to get data from.
1153
+ * `form`: An object containing the form data to send.
1154
+ * `customHeader`: An object containing custom headers to send.
1155
+ * `callback(err, data)`: A callback called when the query is done (either with an error or with the resulting data).
1156
+ * `notAPI`: A boolean indicating whether the request is made from the API or not (default: false, meaning it's from the API).
1157
+
1158
+ ---------------------------------------
1159
+
1160
+ <a name="httpPost"></a>
1161
+ ### api.httpPost(url, form, [customHeader], [callback], [notAPI])
1162
+
1163
+ Get data from a URL with method POST.
1164
+
1165
+ __Arguments__
1166
+
1167
+ * Similar to [`api.httpGet`](#httpGet).
1168
+
1169
+ ---------------------------------------
1170
+
1171
+ <a name="httpPostFormData"></a>
1172
+ ### api.httpPostFormData(url, form, [customHeader], [callback], [notAPI])
1173
+
1174
+ Post form data to a URL.
1175
+
1176
+ __Arguments__
1177
+
1178
+ * Similar to [`api.httpGet`](#httpGet).
1179
+
1180
+ ---------------------------------------
1181
+
1182
+ <a name="listen"></a>
1183
+ ### ~~api.listen([callback])~~
1184
+ <a name="listenMqtt"></a>
1185
+ ### api.listenMqtt([callback])
1186
+
1187
+ Will call `callback` when a new message is received on this account.
1188
+ By default this won't receive events (joining/leaving a chat, title change etc...) but it can be activated with `api.setOptions({listenEvents: true})`. This will by default ignore messages sent by the current account, you can enable listening to your own messages with `api.setOptions({selfListen: true})`. This returns an `EventEmitter` that contains function `stopListening` that will stop the `listen` loop and is guaranteed to prevent any future calls to the callback given to `listen`. An immediate call to `stopListening` when an error occurs will prevent the listen function to continue.
1189
+
1190
+ If `callback` is not defined, or isn't a `Function`, you can listen to messages with event `message` and `error` from `EventEmitter` returned by this function.
1191
+
1192
+ __Arguments__
1193
+
1194
+ - `callback(error, message)`: A callback called every time the logged-in account receives a new message.
1195
+
1196
+ <a name="message"></a>
1197
+ __Message__
1198
+
1199
+ The message object will contain different fields based on its type (as determined by its `type` field). By default, the only type that will be listened for is `message`. If enabled through [setOptions](#setOptions), the message object may alternatively represent an event e.g. a read receipt. The available event types are as follows:
1200
+
1201
+ <table>
1202
+ <tr>
1203
+ <th>Event Type</th>
1204
+ <th>Field</th>
1205
+ <th>Description</th>
1206
+ </tr>
1207
+ <tr>
1208
+ <td rowspan="9">
1209
+ <code>"message"</code><br />
1210
+ A message was sent to a thread.
1211
+ </td>
1212
+ <td><code>attachments</code></td>
1213
+ <td>An array of attachments to the message. Attachments vary in type, see the attachments table below.</td>
1214
+ </tr>
1215
+ <tr>
1216
+ <td><code>body</code></td>
1217
+ <td>The string corresponding to the message that was just received.</td>
1218
+ </tr>
1219
+ <tr>
1220
+ <td><code>isGroup</code></td>
1221
+ <td>boolean, true if this thread is a group thread (more than 2 participants).</td>
1222
+ </tr>
1223
+ <tr>
1224
+ <td><code>mentions</code></td>
1225
+ <td>An object containing people mentioned/tagged in the message in the format { id: name }</td>
1226
+ </tr>
1227
+ <tr>
1228
+ <td><code>messageID</code></td>
1229
+ <td>A string representing the message ID.</td>
1230
+ </tr>
1231
+ <tr>
1232
+ <td><code>senderID</code></td>
1233
+ <td>The id of the person who sent the message in the chat with threadID.</td>
1234
+ </tr>
1235
+ <tr>
1236
+ <td><code>threadID</code></td>
1237
+ <td>The threadID representing the thread in which the message was sent.</td>
1238
+ </tr>
1239
+ <tr>
1240
+ <td><code>isUnread</code></td>
1241
+ <td>Boolean representing whether or not the message was read.</td>
1242
+ </tr>
1243
+ <tr>
1244
+ <td><code>type</code></td>
1245
+ <td>For this event type, this will always be the string <code>"message"</code>.</td>
1246
+ </tr>
1247
+ <tr>
1248
+ <td rowspan="6">
1249
+ <code>"event"</code><br />
1250
+ An event occurred within a thread. Note that receiving this event type needs to be enabled with `api.setOptions({ listenEvents: true })`
1251
+ </td>
1252
+ <td><code>author</code></td>
1253
+ <td>The person who performed the event.</td>
1254
+ </tr>
1255
+ <tr>
1256
+ <td><code>logMessageBody</code></td>
1257
+ <td>String printed in the chat.</td>
1258
+ </tr>
1259
+ <tr>
1260
+ <td><code>logMessageData</code></td>
1261
+ <td>Data relevant to the event.</td>
1262
+ </tr>
1263
+ <tr>
1264
+ <td><code>logMessageType</code></td>
1265
+ <td>String representing the type of event (<code>log:subscribe</code>, <code>log:unsubscribe</code>, <code>log:thread-name</code>, <code>log:thread-color</code>, <code>log:thread-icon</code>, <code>log:user-nickname</code>)</td>
1266
+ </tr>
1267
+ <tr>
1268
+ <td><code>threadID</code></td>
1269
+ <td>The threadID representing the thread in which the message was sent.</td>
1270
+ </tr>
1271
+ <tr>
1272
+ <td><code>type</code></td>
1273
+ <td>For this event type, this will always be the string <code>"event"</code>.</td>
1274
+ </tr>
1275
+ <tr>
1276
+ <td rowspan="5">
1277
+ <code>"typ"</code><br />
1278
+ A user in a thread is typing. Note that receiving this event type needs to be enabled with `api.setOptions({ listenTyping: true })`
1279
+ </td>
1280
+ <td><code>from</code></td>
1281
+ <td>ID of the user who started/stopped typing.</td>
1282
+ </tr>
1283
+ <tr>
1284
+ <td><code>fromMobile</code></td>
1285
+ <td>Boolean representing whether or not the person's using a mobile device to type.</td>
1286
+ </tr>
1287
+ <tr>
1288
+ <td><code>isTyping</code></td>
1289
+ <td>Boolean representing whether or not a person started typing.</td>
1290
+ </tr>
1291
+ <tr>
1292
+ <td><code>threadID</code></td>
1293
+ <td>The threadID representing the thread in which a user is typing.</td>
1294
+ </tr>
1295
+ <tr>
1296
+ <td><code>type</code></td>
1297
+ <td>For this event type, this will always be the string <code>"typ"</code>.</td>
1298
+ </tr>
1299
+ <tr>
1300
+ <td rowspan="3">
1301
+ <code>"read"</code><br />
1302
+ The current API user has read a message.
1303
+ </td>
1304
+ <td><code>threadID</code></td>
1305
+ <td>The threadID representing the thread in which the message was sent.</td>
1306
+ </tr>
1307
+ <tr>
1308
+ <td><code>time</code></td>
1309
+ <td>The time at which the user read the message.</td>
1310
+ </tr>
1311
+ <tr>
1312
+ <td><code>type</code></td>
1313
+ <td>For this event type, this will always be the string <code>"read"</code>.</td>
1314
+ </tr>
1315
+ <tr>
1316
+ <td rowspan="4">
1317
+ <code>"read_receipt"</code><br />
1318
+ A user within a thread has seen a message sent by the API user.
1319
+ </td>
1320
+ <td><code>reader</code></td>
1321
+ <td>ID of the user who just read the message.</td>
1322
+ </tr>
1323
+ <tr>
1324
+ <td><code>threadID</code></td>
1325
+ <td>The thread in which the message was read.</td>
1326
+ </tr>
1327
+ <tr>
1328
+ <td><code>time</code></td>
1329
+ <td>The time at which the reader read the message.</td>
1330
+ </tr>
1331
+ <tr>
1332
+ <td><code>type</code></td>
1333
+ <td>For this event type, this will always be the string <code>"read_receipt"</code>.</td>
1334
+ </tr>
1335
+ <tr>
1336
+ <td rowspan="8">
1337
+ <code>"message_reaction"</code><br />
1338
+ A user has sent a reaction to a message.
1339
+ </td>
1340
+ <td><code>messageID</code></td>
1341
+ <td>The ID of the message</td>
1342
+ </tr>
1343
+ <tr>
1344
+ <td><code>offlineThreadingID</code></td>
1345
+ <td>The offline message ID</td>
1346
+ </tr>
1347
+ <tr>
1348
+ <td><code>reaction</code></td>
1349
+ <td>Contains reaction emoji</td>
1350
+ </tr>
1351
+ <tr>
1352
+ <td><code>senderID</code></td>
1353
+ <td>ID of the author the message, where has been reaction added</td>
1354
+ </tr>
1355
+ <tr>
1356
+ <td><code>threadID</code></td>
1357
+ <td>ID of the thread where the message has been sent</td>
1358
+ </tr>
1359
+ <tr>
1360
+ <td><code>timestamp</code></td>
1361
+ <td>Unix Timestamp (in miliseconds) when the reaction was sent</td>
1362
+ </tr>
1363
+ <tr>
1364
+ <td><code>type</code></td>
1365
+ <td>For this event type, this will always be the string <code>"message_reaction"</code>.</td>
1366
+ </tr>
1367
+ <tr>
1368
+ <td><code>userID</code></td>
1369
+ <td>ID of the reaction sender</td>
1370
+ </tr>
1371
+ <tr>
1372
+ <td rowspan="4"><a name="presence"></a>
1373
+ <code>"presence"</code><br />
1374
+ The online status of the user's friends. Note that receiving this event type needs to be enabled with <code>api.setOptions({ updatePresence: true })</code>
1375
+ </td>
1376
+ <td><code>statuses</code></td>
1377
+ <td>The online status of the user. <code>0</code> means the user is idle (away for 2 minutes) and <code>2</code> means the user is online (we don't know what 1 or above 2 means...).</td>
1378
+ </tr>
1379
+ <tr>
1380
+ <td><code>timestamp</code></td>
1381
+ <td>The time when the user was last online.</td>
1382
+ </tr>
1383
+ <tr>
1384
+ <td><code>type</code></td>
1385
+ <td>For this event type, this will always be the string <code>"presence"</code>.</td>
1386
+ </tr>
1387
+ <tr>
1388
+ <td><code>userID</code></td>
1389
+ <td>The ID of the user whose status this packet is describing.</td>
1390
+ </tr>
1391
+ <tr>
1392
+ <td rowspan="5">
1393
+ <code>"message_unsend"</code><br />
1394
+ A revoke message request for a message from a thread was received.
1395
+ </td>
1396
+ <td><code>threadID</code></td>
1397
+ <td>The threadID representing the thread in which the revoke message request was received.</td>
1398
+ </tr>
1399
+ <tr>
1400
+ <td><code>senderID</code></td>
1401
+ <td>The id of the person who request to revoke message on threadID.</td>
1402
+ </tr>
1403
+ <tr>
1404
+ <td><code>messageID</code></td>
1405
+ <td>A string representing the message ID that the person request to revoke message want to.</td>
1406
+ </tr>
1407
+ <tr>
1408
+ <td><code>deletionTimestamp</code></td>
1409
+ <td>The time when the request was sent.</td>
1410
+ </tr>
1411
+ <tr>
1412
+ <td><code>type</code></td>
1413
+ <td>For this event type, this will always be the string <code>"message_unsend"</code>.</td>
1414
+ </tr>
1415
+ <tr>
1416
+ <td rowspan="10">
1417
+ <code>"message_reply"</code><br />
1418
+ A reply message was sent to a thread.
1419
+ </td>
1420
+ <td><code>attachments</code></td>
1421
+ <td>An array of attachments to the message. Attachments vary in type, see the attachments table below.</td>
1422
+ </tr>
1423
+ <tr>
1424
+ <td><code>body</code></td>
1425
+ <td>The string corresponding to the message that was just received.</td>
1426
+ </tr>
1427
+ <tr>
1428
+ <td><code>isGroup</code></td>
1429
+ <td>boolean, true if this thread is a group thread (more than 2 participants).</td>
1430
+ </tr>
1431
+ <tr>
1432
+ <td><code>mentions</code></td>
1433
+ <td>An object containing people mentioned/tagged in the message in the format { id: name }</td>
1434
+ </tr>
1435
+ <tr>
1436
+ <td><code>messageID</code></td>
1437
+ <td>A string representing the message ID.</td>
1438
+ </tr>
1439
+ <tr>
1440
+ <td><code>senderID</code></td>
1441
+ <td>The id of the person who sent the message in the chat with threadID.</td>
1442
+ </tr>
1443
+ <tr>
1444
+ <td><code>threadID</code></td>
1445
+ <td>The threadID representing the thread in which the message was sent.</td>
1446
+ </tr>
1447
+ <tr>
1448
+ <td><code>isUnread</code></td>
1449
+ <td>Boolean representing whether or not the message was read.</td>
1450
+ </tr>
1451
+ <tr>
1452
+ <td><code>type</code></td>
1453
+ <td>For this event type, this will always be the string <code>"message_reply"</code>.</td>
1454
+ </tr>
1455
+ <tr>
1456
+ <td><code>messageReply</code></td>
1457
+ <td>An object represent a message being replied. Content inside is the same like a normal <code>"message"</code> event.</td>
1458
+ </tr>
1459
+ </table>
1460
+
1461
+ __Attachments__
1462
+
1463
+ Similar to how messages can vary based on their `type`, so too can the `attachments` within `"message"` events. Each attachment will consist of an object of one of the following types:
1464
+
1465
+ | Attachment Type | Fields |
1466
+ | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
1467
+ | `"sticker"` | `ID`, `url`, `packID`, `spriteUrl`, `spriteUrl2x`, `width`, `height`, `caption`, `description`, `frameCount`, `frameRate`, `framesPerRow`, `framesPerCol` |
1468
+ | `"file"` | `ID`, `filename`, `url`, `isMalicious`, `contentType` |
1469
+ | `"photo"` | `ID`, `filename`, `thumbnailUrl`, `previewUrl`, `previewWidth`, `previewHeight`, `largePreviewUrl`, `largePreviewWidth`, `largePreviewHeight` |
1470
+ | `"animated_image"` | `ID`, `filename`, `previewUrl`, `previewWidth`, `previewHeight`, `url`, `width`, `height` |
1471
+ | `"video"` | `ID`, `filename`, `previewUrl`, `previewWidth`, `previewHeight`, `url`, `width`, `height`, `duration`, `videoType` |
1472
+ | `"audio"` | `ID`, `filename`, `audioType`, `duration`, `url`, `isVoiceMail` |
1473
+ | `"location"` | `ID`, `latitude`, `longitude`, `image`, `width`, `height`, `url`, `address` |
1474
+ | `"share"` | `ID`, `url`, `title`, `description`, `source`, `image`, `width`, `height`, `playable`, `duration`, `playableUrl`, `subattachments`, `properties` |
1475
+
1476
+ __Example__
1477
+
1478
+ ```js
1479
+ const fs = require("fs-extra");
1480
+ const login = require("fb-chat-api");
1481
+
1482
+ // Simple echo bot. He'll repeat anything that you say.
1483
+ // Will stop when you say '/stop'
1484
+
1485
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1486
+ if(err) return console.error(err);
1487
+
1488
+ api.setOptions({listenEvents: true});
1489
+
1490
+ var listenEmitter = api.listen((err, event) => {
1491
+ if(err) return console.error(err);
1492
+
1493
+ switch (event.type) {
1494
+ case "message":
1495
+ if(event.body === '/stop') {
1496
+ api.sendMessage("Goodbye...", event.threadID);
1497
+ return listenEmitter.stopListening();
1498
+ }
1499
+ api.markAsRead(event.threadID, (err) => {
1500
+ if(err) console.log(err);
1501
+ });
1502
+ api.sendMessage("TEST BOT: " + event.body, event.threadID);
1503
+ break;
1504
+ case "event":
1505
+ console.log(event);
1506
+ break;
1507
+ }
1508
+ });
1509
+ });
1510
+ ```
1511
+
1512
+ ---------------------------------------
1513
+
1514
+ <a name="logout"></a>
1515
+ ### api.logout([callback])
1516
+
1517
+ Logs out the current user.
1518
+
1519
+ __Arguments__
1520
+
1521
+ * `callback(err)`: A callback called when the query is done (either with an error or with null).
1522
+
1523
+ ---------------------------------------
1524
+
1525
+ <a name="markAsDelivered"></a>
1526
+ ### api.markAsDelivered(threadID, messageID, [callback]])
1527
+
1528
+ Given a threadID and a messageID will mark that message as delivered. If a message is marked as delivered that tells facebook servers that it was recieved.
1529
+
1530
+ You can also mark new messages as delivered automatically. This is enabled by default. See [api.setOptions](#setOptions).
1531
+
1532
+ __Arguments__
1533
+
1534
+ * `threadID` - The id of the thread in which you want to mark the message as delivered.
1535
+ * `messageID` - The id of the message want to mark as delivered.
1536
+ * `callback(err)` - A callback called when the operation is done maybe with an object representing an error.
1537
+
1538
+ __Example__
1539
+
1540
+ ```js
1541
+ const fs = require("fs-extra");
1542
+ const login = require("facebook-chat-api");
1543
+
1544
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1545
+ if(err) return console.error(err);
1546
+
1547
+ api.listen((err, message) => {
1548
+ if(err) return console.error(err);
1549
+
1550
+ // Marks messages as delivered immediately after they're received
1551
+ api.markAsDelivered(message.threadID, message.messageID);
1552
+ });
1553
+ });
1554
+ ```
1555
+
1556
+ ---------------------------------------
1557
+
1558
+ <a name="markAsRead"></a>
1559
+ ### api.markAsRead(threadID, [read, [callback]])
1560
+
1561
+ Given a threadID will mark all the unread messages in a thread as read. Facebook will take a couple of seconds to show that you've read the messages.
1562
+
1563
+ You can also mark new messages as read automatically. See [api.setOptions](#setOptions). But be careful, this will make your account getting banned, especially when receiving *HUGE* amount of messages.
1564
+
1565
+ __Arguments__
1566
+
1567
+ * `threadID` - The id of the thread in which you want to mark the messages as read.
1568
+ * `read` - An optional boolean where `true` means to mark the message as being "read" and `false` means to mark the message as being "unread".
1569
+ * `callback(err)` - A callback called when the operation is done maybe with an object representing an error.
1570
+
1571
+ __Example__
1572
+
1573
+ ```js
1574
+ const fs = require("fs-extra");
1575
+ const login = require("fb-chat-api");
1576
+
1577
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1578
+ if(err) return console.error(err);
1579
+
1580
+ api.listen((err, message) => {
1581
+ if(err) return console.error(err);
1582
+
1583
+ // Marks messages as read immediately after they're received
1584
+ api.markAsRead(message.threadID);
1585
+ });
1586
+ });
1587
+ ```
1588
+
1589
+ ---------------------------------------
1590
+
1591
+ <a name="markAsReadAll"></a>
1592
+ ### api.markAsReadAll([callback])
1593
+
1594
+ This function will mark all of messages in your inbox readed.
1595
+
1596
+ ---------------------------------------
1597
+
1598
+ <a name="markAsSeen"></a>
1599
+ ### api.markAsSeen([seenTimestamp], [callback])
1600
+
1601
+ This function will mark your entire inbox as seen (don't be confused with read!).
1602
+
1603
+ ---------------------------------------
1604
+
1605
+ <a name="muteThread"></a>
1606
+ ### api.muteThread(threadID, muteSeconds, [callback])
1607
+
1608
+ Mute a chat for a period of time, or unmute a chat.
1609
+
1610
+ __Arguments__
1611
+
1612
+ * `threadID` - The ID of the chat you want to mute.
1613
+ * `muteSeconds` - Mute the chat for this amount of seconds. Use `0` to unmute a chat. Use '-1' to mute a chat indefinitely.
1614
+ * `callback(err)` - A callback called when the operation is done maybe with an object representing an error.
1615
+
1616
+ __Example__
1617
+
1618
+ ```js
1619
+ const fs = require("fs-extra");
1620
+ const login = require("fb-chat-api");
1621
+
1622
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1623
+ if(err) return console.error(err);
1624
+
1625
+ api.listen((err, message) => {
1626
+ if(err) return console.error(err);
1627
+
1628
+ // Mute all incoming chats for one minute
1629
+ api.muteThread(message.threadID, 60);
1630
+ });
1631
+ });
1632
+ ```
1633
+
1634
+ ---------------------------------------
1635
+
1636
+ <a name="removeUserFromGroup"></a>
1637
+ ### api.removeUserFromGroup(userID, threadID, [callback])
1638
+
1639
+ Removes a user from a group chat.
1640
+
1641
+ __Arguments__
1642
+
1643
+ * `userID`: User ID.
1644
+ * `threadID`: Group chat ID.
1645
+ * `callback(err)`: A callback called when the query is done (either with an error or with no arguments).
1646
+
1647
+ ---------------------------------------
1648
+
1649
+ <a name="resolvePhotoUrl"></a>
1650
+ ### api.resolvePhotoUrl(photoID, [callback])
1651
+
1652
+ Resolves the URL to the full-size photo, given its ID. This function is useful for retrieving the full-size photo URL
1653
+ of image attachments in messages, returned by [`api.getThreadHistory`](#getThreadHistory).
1654
+
1655
+ __Arguments__
1656
+
1657
+ * `photoID`: Photo ID.
1658
+ * `callback(err, url)`: A callback called when the query is done (either with an error or with the photo's URL). `url` is a string with the photo's URL.
1659
+
1660
+ ---------------------------------------
1661
+
1662
+ <a name="searchForThread"></a>
1663
+ ### api.searchForThread(name, [callback])
1664
+
1665
+ > This part is outdated.
1666
+ > see #396
1667
+
1668
+ Takes a chat title (thread name) and returns matching results as a formatted threads array (ordered according to Facebook).
1669
+
1670
+ __Arguments__
1671
+ * `name`: A messageID string or messageID string array
1672
+ * `callback(err, obj)`: A callback called when the query is done (either with an error or a thread object). The object passed in the callback has the following shape: `threadID`, <del>`participants`</del>, `participantIDs`, `formerParticipants`, `name`, `nicknames`, `snippet`, `snippetHasAttachment`, `snippetAttachments`, `snippetSender`, `unreadCount`, `messageCount`, `imageSrc`, `timestamp`, `serverTimestamp`, `muteSettings`, `isCanonicalUser`, `isCanonical`, `canonicalFbid`, `isSubscribed`, `rootMessageThreadingID`, `folder`, `isArchived`, `recipientsLoadable`, `hasEmailParticipant`, `readOnly`, `canReply`, `composerEnabled`, `blockedParticipants`, `lastMessageID`
1673
+
1674
+ ---------------------------------------
1675
+
1676
+ <a name="sendMessage"></a>
1677
+ ### api.sendMessage(message, threadID, [callback], messageID)
1678
+
1679
+ Sends the given message to the threadID.
1680
+
1681
+ __Arguments__
1682
+
1683
+ * `message`: A string (for backward compatibility) or a message object as described below.
1684
+ * `threadID`: A string, number, or array representing a thread. It happens to be someone's userID in the case of a one to one conversation or an array of userIDs when starting a new group chat.
1685
+ * `callback(err, messageInfo)`: (Optional) A callback called when sending the message is done (either with an error or with an confirmation object). `messageInfo` contains the `threadID` where the message was sent and a `messageID`, as well as the `timestamp` of the message.
1686
+ * `messageID`: (Optional) A string representing a message you want to reply.
1687
+
1688
+ __Message Object__:
1689
+
1690
+ Various types of message can be sent:
1691
+ * *Regular:* set field `body` to the desired message as a string.
1692
+ * *Sticker:* set a field `sticker` to the desired sticker ID.
1693
+ * *File or image:* Set field `attachment` to a readable stream or an array of readable streams.
1694
+ * *URL:* set a field `url` to the desired URL.
1695
+ * *Emoji:* set field `emoji` to the desired emoji as a string and set field `emojiSize` with size of the emoji (`small`, `medium`, `large`)
1696
+ * *Mentions:* set field `mentions` to an array of objects. Objects should have the `tag` field set to the text that should be highlighted in the mention. The object should have an `id` field, where the `id` is the user id of the person being mentioned. The instance of `tag` that is highlighted is determined through indexOf, an optional `fromIndex`
1697
+ can be passed in to specify the start index to start searching for the `tag` text
1698
+ in `body` (default=0). (See below for an example.)
1699
+ * *Location:* set field `location` to an object with `latitude` and `longitude` fields. Optionally set field `current` of the `location` object to true to indicate the location is the user’s current location. Otherwise the location will be sent as a pinned location.
1700
+
1701
+ Note that a message can only be a regular message (which can be empty) and optionally one of the following: a sticker, an attachment or a url.
1702
+
1703
+ __Tip__: to find your own ID, you can look inside the cookies. The `userID` is under the name `c_user`.
1704
+
1705
+ __Example (Basic Message)__
1706
+ ```js
1707
+ const fs = require("fs-extra");
1708
+ const login = require("fb-chat-api");
1709
+
1710
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1711
+ if(err) return console.error(err);
1712
+
1713
+ var yourID = "000000000000000";
1714
+ var msg = {body: "Hey!"};
1715
+ api.sendMessage(msg, yourID);
1716
+ });
1717
+ ```
1718
+
1719
+ __Example (File upload)__
1720
+ ```js
1721
+ const fs = require("fs-extra");
1722
+ const login = require("fb-chat-api");
1723
+
1724
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1725
+ if(err) return console.error(err);
1726
+
1727
+ // This example uploads an image called image.jpg
1728
+ var yourID = "000000000000000";
1729
+ var msg = {
1730
+ body: "Hey!",
1731
+ attachment: fs.createReadStream(__dirname + '/image.jpg')
1732
+ }
1733
+ api.sendMessage(msg, yourID);
1734
+ });
1735
+ ```
1736
+
1737
+ __Example (Mention)__
1738
+ ```js
1739
+ const login = require("fb-chat-api");
1740
+
1741
+ login({email: "EMAIL", password: "PASSWORD"}, (err, api) => {
1742
+ if(err) return console.error(err);
1743
+
1744
+ api.listen((err, message) => {
1745
+ if (message && message.body) {
1746
+ // Getting the actual sender name from ID involves calling
1747
+ // `api.getThreadInfo` and `api.getUserInfo`
1748
+ api.sendMessage({
1749
+ body: 'Hello @Sender! @Sender!',
1750
+ mentions: [{
1751
+ tag: '@Sender',
1752
+ id: message.senderID,
1753
+ fromIndex: 9, // Highlight the second occurrence of @Sender
1754
+ }],
1755
+ }, message.threadID);
1756
+ }
1757
+ });
1758
+ });
1759
+ ```
1760
+
1761
+ __Example (Location)__
1762
+ ```js
1763
+ const login = require("fb-chat-api");
1764
+ login({email: "EMAIL", password: "PASSWORD"}, (err, api) => {
1765
+ if(err) return console.error(err);
1766
+ var yourID = "000000000000000";
1767
+ const msg = {
1768
+ location: { latitude: 48.858093, longitude: 2.294694, current: true },
1769
+ };
1770
+ api.sendMessage(msg, yourID);
1771
+ });
1772
+ ```
1773
+
1774
+ ---------------------------------------
1775
+
1776
+ <a name="sendTypingIndicator"></a>
1777
+ ### api.sendTypingIndicator(threadID, [callback])
1778
+
1779
+ Sends a "USERNAME is typing" indicator to other members of the thread indicated by `threadID`. This indication will disappear after 30 second or when the `end` function is called. The `end` function is returned by `api.sendTypingIndicator`.
1780
+
1781
+ __Arguments__
1782
+
1783
+ * `threadID`: Group chat ID.
1784
+ * `callback(err)`: A callback called when the query is done (with an error or with null).
1785
+
1786
+ ---------------------------------------
1787
+
1788
+ <a name="setMessageReaction"></a>
1789
+ ### api.setMessageReaction(reaction, messageID, [callback], forceCustomReaction)
1790
+
1791
+ Sets reaction on message
1792
+
1793
+ __Arguments__
1794
+
1795
+ * `reaction`: A string containing either an emoji, an emoji in unicode, or an emoji shortcut (see list of supported emojis below). The string can be left empty ("") in order to remove a reaction.
1796
+ * `messageID`: A string representing the message ID.
1797
+ * `callback(err)`: A callback called when sending the reaction is done.
1798
+ * `forceCustomReaction`: Forcing the use of an emoji for setting reaction **(WARNING: NOT TESTED, YOU SHOULD NOT USE THIS AT ALL, UNLESS YOU'RE TESTING A NEW EMOJI)**
1799
+
1800
+ __Supported Emojis__
1801
+
1802
+ | Emoji | Text | Unicode | Shortcuts |
1803
+ | ----- | ---- | -------------- | --------------------------- |
1804
+ | 😍 | `😍` | `\uD83D\uDE0D` | `:love:`, `:heart_eyes:` |
1805
+ | 😆 | `😆` | `\uD83D\uDE06` | `:haha:`, `:laughing:` |
1806
+ | 😮 | `😮` | `\uD83D\uDE2E` | `:wow:`, `:open_mouth:` |
1807
+ | 😢 | `😢` | `\uD83D\uDE22` | `:sad:`, `:cry:` |
1808
+ | 😠 | `😠` | `\uD83D\uDE20` | `:angry:` |
1809
+ | 👍 | `👍` | `\uD83D\uDC4D` | `:like:`, `:thumbsup:` |
1810
+ | 👎 | `👎` | `\uD83D\uDC4E` | `:dislike:`, `:thumbsdown:` |
1811
+ | ❤ | `❤` | `\u2764` | `:heart:` |
1812
+ | 💗 | `💗` | `\uD83D\uDC97` | `:glowingheart:` |
1813
+
1814
+ ---------------------------------------
1815
+
1816
+ <a name="setOptions"></a>
1817
+ ### api.setOptions(options)
1818
+
1819
+ Sets various configurable options for the api.
1820
+
1821
+ __Arguments__
1822
+
1823
+ * `options` - An object containing the new values for the options that you want
1824
+ to set. If the value for an option is unspecified, it is unchanged. The following options are possible.
1825
+ - `logLevel`: The desired logging level as determined by npmlog. Choose
1826
+ from either `"silly"`, `"verbose"`, `"info"`, `"http"`, `"warn"`, `"error"`, or `"silent"`.
1827
+ - `selfListen`: (Default `false`) Set this to `true` if you want your api
1828
+ to receive messages from its own account. This is to be used with
1829
+ caution, as it can result in loops (a simple echo bot will send messages
1830
+ forever).
1831
+ - `listenEvents`: (Default `false`) Will make [api.listen](#listen) also handle events (look at api.listen for more details).
1832
+ - `pageID`: (Default empty) Makes [api.listen](#listen) only receive messages through the page specified by that ID. Also makes [api.sendMessage](#sendMessage) send from the page.
1833
+ - `updatePresence`: (Default `false`) Will make [api.listen](#listen) also return `presence` ([api.listen](#presence) for more details).
1834
+ - `forceLogin`: (Default `false`) Will automatically approve of any recent logins and continue with the login process.
1835
+ - `userAgent`: (Default `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/600.3.18 (KHTML, like Gecko) Version/8.0.3 Safari/600.3.18`) The desired simulated User Agent.
1836
+ - `autoMarkDelivery`: (Default `true`) Will automatically mark new messages as delivered. See [api.markAsDelivered](#markAsDelivered).
1837
+ - `autoMarkRead`: (Default `false`) Will automatically mark new messages as read/seen. See [api.markAsRead](#markAsRead).
1838
+ - `proxy`: (Default empty) Set this to proxy server address to use proxy. Note: Only HTTP Proxies which support CONNECT method is supported.
1839
+ - `online`: (Default `true`) Set account's online state.
1840
+
1841
+ __Example__
1842
+
1843
+ ```js
1844
+ const fs = require("fs-extra");
1845
+ const login = require("fb-chat-api");
1846
+
1847
+ // Simple echo bot. This will send messages forever.
1848
+
1849
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1850
+ if(err) return console.error(err);
1851
+
1852
+ api.setOptions({
1853
+ selfListen: true,
1854
+ logLevel: "silent"
1855
+ });
1856
+
1857
+ api.listen((err, message) => {
1858
+ if(err) return console.error(err);
1859
+
1860
+ // Ignore empty messages (photos etc.)
1861
+ if (typeof message.body === "string") {
1862
+ api.sendMessage(message.body, message.threadID);
1863
+ }
1864
+ });
1865
+ });
1866
+ ```
1867
+
1868
+ ---------------------------------------
1869
+
1870
+ <a name="setPostReaction"></a>
1871
+ ### api.setPostReaction(postID, type, [callback])
1872
+ __Arguments__
1873
+
1874
+ * `postID`: id of the post to react.
1875
+ * `type`: A string reaction type or key reaction.
1876
+ * `callback(err, obj)`: A callback called when the query is done.
1877
+
1878
+ | Key | Reaction Type |
1879
+ | --- | ------------- |
1880
+ | 0 | unlike |
1881
+ | 1 | like |
1882
+ | 2 | heart |
1883
+ | 16 | love |
1884
+ | 4 | haha |
1885
+ | 3 | wow |
1886
+ | 7 | sad |
1887
+ | 8 | angry |
1888
+
1889
+ ---------------------------------------
1890
+
1891
+ <a name="setTitle"></a>
1892
+ ### api.setTitle(newTitle, threadID, [callback])
1893
+
1894
+ Sets the title of the group chat with thread id `threadID` to `newTitle`.
1895
+
1896
+ Note: This will not work if the thread id corresponds to a single-user chat or if the bot is not in the group chat.
1897
+
1898
+ __Arguments__
1899
+
1900
+ * `newTitle`: A string representing the new title.
1901
+ * `threadID`: A string or number representing a thread. It happens to be someone's userID in the case of a one to one conversation.
1902
+ * `callback(err, obj)` - A callback called when sending the message is done (either with an error or with an confirmation object). `obj` contains only the threadID where the message was sent.
1903
+
1904
+ ---------------------------------------
1905
+
1906
+ <a name="unsendMessage"></a>
1907
+ ### api.unsendMessage(messageID, [callback])
1908
+
1909
+ Revokes a message from anyone that could see that message with `messageID`
1910
+
1911
+ Note: This will only work if the message is sent by you and was sent less than 10 minutes ago.
1912
+
1913
+ __Arguments__
1914
+
1915
+ * `messageID`: Message ID you want to unsend.
1916
+ * `callback(err)`: A callback called when the query is done (with an error or with null).
1917
+
1918
+ ---------------------------------------
1919
+
1920
+ <a name="uploadAttachments"></a>
1921
+ ### api.uploadAttachment(attachments, [callback])
1922
+ This function is used to upload attachments to Facebook. It is used internally by [api.sendMessage](#apisendmessagemessage-threadid-callback-messageid).
1923
+
1924
+ __Arguments__
1925
+ <!-- readable stream or an array of readable streams. -->
1926
+ * `attachments`: A readable stream or an array of readable streams to upload.
1927
+ * `callback(err, info)`: A callback called when the upload is done (either with an error or with the uploaded file info).
1928
+
1929
+ __Example__
1930
+
1931
+ ```js
1932
+ const fs = require("fs-extra");
1933
+ const login = require("fb-chat-api");
1934
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1935
+ if(err) return console.error(err);
1936
+
1937
+ // Send a local file as a stream
1938
+ const iamgeOne = fs.createReadStream(__dirname + '/image.jpg');
1939
+ const iamgeTwo = fs.createReadStream(__dirname + '/image2.jpg');
1940
+
1941
+ api.uploadAttachment([iamgeOne, iamgeTwo], (err, attachments) => {
1942
+ if(err)
1943
+ return console.error(err);
1944
+
1945
+ console.log(attachments);
1946
+ });
1947
+ });