official-zach-remade 32.2.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of official-zach-remade might be problematic. Click here for more details.

Files changed (92) hide show
  1. package/DOCS.md +1738 -0
  2. package/Extra/ExtraAddons.js +78 -0
  3. package/Extra/ExtraFindUID.js +60 -0
  4. package/Extra/ExtraGetThread.js +118 -0
  5. package/Extra/ExtraScreenShot.js +673 -0
  6. package/Extra/ExtraTranslate.js +62 -0
  7. package/Extra/ExtraUptimeRobot.js +59 -0
  8. package/Extra/Html/Classic/script.js +231 -0
  9. package/Extra/Html/Classic/style.css +8 -0
  10. package/Extra/PM2/ecosystem.config.js +23 -0
  11. package/Extra/Security/Index.js +174 -0
  12. package/Extra/Security/Step_1.js +15 -0
  13. package/Extra/Security/Step_2.js +23 -0
  14. package/Extra/Security/Step_3.js +23 -0
  15. package/Extra/Src/History.js +115 -0
  16. package/Extra/Src/Last-Run.js +65 -0
  17. package/Extra/Src/Premium.js +84 -0
  18. package/Extra/Src/SecurityCheck.js +2 -0
  19. package/Func/AcceptAgreement.js +32 -0
  20. package/Func/ClearCache.js +64 -0
  21. package/Func/ReportV1.js +54 -0
  22. package/LICENSE +21 -0
  23. package/LICENSE.md +23 -0
  24. package/Language/index.json +176 -0
  25. package/OldSecurity.js +100 -0
  26. package/README.md +129 -0
  27. package/SECURITY.md +21 -0
  28. package/broadcast.js +38 -0
  29. package/index.js +1332 -0
  30. package/logger.js +65 -0
  31. package/package.json +191 -0
  32. package/src/Horizon_Data.js +123 -0
  33. package/src/Premium.js +30 -0
  34. package/src/Screenshot.js +85 -0
  35. package/src/addExternalModule.js +16 -0
  36. package/src/addUserToGroup.js +79 -0
  37. package/src/changeAdminStatus.js +79 -0
  38. package/src/changeArchivedStatus.js +41 -0
  39. package/src/changeAvt.js +85 -0
  40. package/src/changeBio.js +65 -0
  41. package/src/changeBlockedStatus.js +36 -0
  42. package/src/changeGroupImage.js +106 -0
  43. package/src/changeNickname.js +45 -0
  44. package/src/changeThreadColor.js +62 -0
  45. package/src/changeThreadEmoji.js +42 -0
  46. package/src/createNewGroup.js +70 -0
  47. package/src/createPoll.js +60 -0
  48. package/src/deleteMessage.js +45 -0
  49. package/src/deleteThread.js +43 -0
  50. package/src/forwardAttachment.js +48 -0
  51. package/src/getAccessToken.js +32 -0
  52. package/src/getCurrentUserID.js +7 -0
  53. package/src/getEmojiUrl.js +27 -0
  54. package/src/getFriendsList.js +73 -0
  55. package/src/getMessage.js +80 -0
  56. package/src/getThreadHistory.js +537 -0
  57. package/src/getThreadInfo.js +348 -0
  58. package/src/getThreadList.js +213 -0
  59. package/src/getThreadMain.js +219 -0
  60. package/src/getThreadPictures.js +59 -0
  61. package/src/getUID.js +59 -0
  62. package/src/getUserID.js +62 -0
  63. package/src/getUserInfo.js +129 -0
  64. package/src/getUserInfoMain.js +65 -0
  65. package/src/getUserInfoV2.js +36 -0
  66. package/src/getUserInfoV3.js +63 -0
  67. package/src/getUserInfoV4.js +55 -0
  68. package/src/getUserInfoV5.js +61 -0
  69. package/src/handleFriendRequest.js +46 -0
  70. package/src/handleMessageRequest.js +49 -0
  71. package/src/httpGet.js +49 -0
  72. package/src/httpPost.js +48 -0
  73. package/src/httpPostFormData.js +41 -0
  74. package/src/listenMqtt.js +702 -0
  75. package/src/logout.js +68 -0
  76. package/src/markAsDelivered.js +48 -0
  77. package/src/markAsRead.js +70 -0
  78. package/src/markAsReadAll.js +43 -0
  79. package/src/markAsSeen.js +51 -0
  80. package/src/muteThread.js +47 -0
  81. package/src/removeUserFromGroup.js +49 -0
  82. package/src/resolvePhotoUrl.js +37 -0
  83. package/src/searchForThread.js +43 -0
  84. package/src/sendMessage.js +334 -0
  85. package/src/sendTypingIndicator.js +80 -0
  86. package/src/setMessageReaction.js +109 -0
  87. package/src/setPostReaction.js +102 -0
  88. package/src/setTitle.js +74 -0
  89. package/src/threadColors.js +39 -0
  90. package/src/unfriend.js +43 -0
  91. package/src/unsendMessage.js +40 -0
  92. package/utils.js +1648 -0
package/DOCS.md ADDED
@@ -0,0 +1,1738 @@
1
+ # Documentation
2
+
3
+ * [`login`](#login)
4
+ * [`api.addUserToGroup`](#addUserToGroup)
5
+ * [`api.changeAdminStatus`](#changeAdminStatus)
6
+ * [`api.changeArchivedStatus`](#changeArchivedStatus)
7
+ * [`api.changeBlockedStatus`](#changeBlockedStatus)
8
+ * [`api.changeGroupImage`](#changeGroupImage)
9
+ * [`api.changeNickname`](#changeNickname)
10
+ * [`api.changeThreadColor`](#changeThreadColor)
11
+ * [`api.changeThreadEmoji`](#changeThreadEmoji)
12
+ * [`api.createNewGroup`](#createNewGroup)
13
+ * [`api.createPoll`](#createPoll)
14
+ * [`api.deleteMessage`](#deleteMessage)
15
+ * [`api.deleteThread`](#deleteThread)
16
+ * [`api.forwardAttachment`](#forwardAttachment)
17
+ * [`api.getAppState`](#getAppState)
18
+ * [`api.getCurrentUserID`](#getCurrentUserID)
19
+ * [`api.getEmojiUrl`](#getEmojiUrl)
20
+ * [`api.getFriendsList`](#getFriendsList)
21
+ * [`api.getThreadHistory`](#getThreadHistory)
22
+ * [`api.getThreadInfo`](#getThreadInfo)
23
+ * [`api.getThreadList`](#getThreadList)
24
+ * [`api.getThreadPictures`](#getThreadPictures)
25
+ * [`api.getUserID`](#getUserID)
26
+ * [`api.getUserInfo`](#getUserInfo)
27
+ * [`api.handleMessageRequest`](#handleMessageRequest)
28
+ * [`api.listenMqtt`](#listenMqtt)
29
+ * [`api.logout`](#logout)
30
+ * [`api.markAsDelivered`](#markAsDelivered)
31
+ * [`api.markAsRead`](#markAsRead)
32
+ * [`api.markAsReadAll`](#markAsReadAll)
33
+ * [`api.markAsSeen`](#markAsSeen)
34
+ * [`api.muteThread`](#muteThread)
35
+ * [`api.removeUserFromGroup`](#removeUserFromGroup)
36
+ * [`api.resolvePhotoUrl`](#resolvePhotoUrl)
37
+ * [`api.searchForThread`](#searchForThread)
38
+ * [`api.sendMessage`](#sendMessage)
39
+ * [`api.sendTypingIndicator`](#sendTypingIndicator)
40
+ * [`api.setMessageReaction`](#setMessageReaction)
41
+ * [`api.setOptions`](#setOptions)
42
+ * [`api.setTitle`](#setTitle)
43
+ * [`api.threadColors`](#threadColors)
44
+ * [`api.unsendMessage`](#unsendMessage)
45
+
46
+ ---------------------------------------
47
+
48
+ ### Password safety
49
+
50
+ **Read this** before you _copy+paste_ examples from below.
51
+
52
+ You should not store Facebook password in your scripts.
53
+ There are few good reasons:
54
+ * People who are standing behind you may look at your "code" and get your password if it is on the screen
55
+ * 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_"
56
+ * 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.
57
+ * 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
58
+
59
+ Preferred method is to have `login.js` that saves `AppState` to a file and then use that file from all your scripts.
60
+ This way you can put password in your code for a minute, login to facebook and then remove it.
61
+
62
+ If you want to be even more safe: _login.js_ can get password with `require("readline")` or with environment variables like this:
63
+ ```js
64
+ var credentials = {
65
+ email: process.env.FB_EMAIL,
66
+ password: process.env.FB_PASSWORD
67
+ }
68
+ ```
69
+ ```bash
70
+ FB_EMAIL="john.doe@example.com"
71
+ FB_PASSWORD="MySuperHardP@ssw0rd"
72
+ nodejs login.js
73
+ ```
74
+
75
+ ---------------------------------------
76
+
77
+ <a name="login"></a>
78
+ ### login(credentials[, options][, callback])
79
+
80
+ This function is returned by `require(...)` and is the main entry point to the API.
81
+
82
+ It allows the user to log into facebook given the right credentials.
83
+
84
+ 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!)
85
+
86
+ If `callback` is supplied:
87
+
88
+ * `callback` will be called with a `null` object (for potential errors) and with an object containing all the available functions if logged in successfully.
89
+
90
+ * `callback` will be called with an error object if failed to login.
91
+
92
+ 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:
93
+
94
+ * If `callback` is not supplied (using `Promise`), this function will return a `Promise` that behaves like `Promise` received from `login`.
95
+
96
+ * If `callback` is supplied, this function will still return a `Promise`, but it will not resolve. Instead, the result is called to `callback`.
97
+
98
+ __Arguments__
99
+
100
+ * `credentials`: An object containing the fields `email` and `password` used to login, __*or*__ an object containing the field `appState`.
101
+ * `options`: An object representing options to use when logging in (as described in [api.setOptions](#setOptions)).
102
+ * `callback(err, api)`: A callback called when login is done (successful or not). `err` is an object containing a field `error`.
103
+
104
+ __Example (Email & Password)__
105
+
106
+ ```js
107
+ const login = require("fca-kenlie-plays");
108
+
109
+ login({email: "FB_EMAIL", password: "FB_PASSWORD"}, (err, api) => {
110
+ if(err) return console.error(err);
111
+ // Here you can use the api
112
+ });
113
+ ```
114
+
115
+ __Example (Email & Password then save appState to file)__
116
+
117
+ ```js
118
+ const fs = require("fs");
119
+ const login = require("fca-kenlie-plays");
120
+
121
+ login({email: "FB_EMAIL", password: "FB_PASSWORD"}, (err, api) => {
122
+ if(err) return console.error(err);
123
+
124
+ fs.writeFileSync('appstate.json', JSON.stringify(api.getAppState()));
125
+ });
126
+ ```
127
+
128
+ __Example (AppState loaded from file)__
129
+
130
+ ```js
131
+ const fs = require("fs");
132
+ const login = require("fca-kenlie-plays");
133
+
134
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
135
+ if(err) return console.error(err);
136
+ // Here you can use the api
137
+ });
138
+ ```
139
+
140
+ __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`.
141
+
142
+ __Example__:
143
+
144
+ ```js
145
+ const fs = require("fs");
146
+ const login = require("fca-kenlie-plays");
147
+ const readline = require("readline");
148
+
149
+ var rl = readline.createInterface({
150
+ input: process.stdin,
151
+ output: process.stdout
152
+ });
153
+
154
+ const obj = {email: "FB_EMAIL", password: "FB_PASSWORD"};
155
+ login(obj, (err, api) => {
156
+ if(err) {
157
+ switch (err.error) {
158
+ case 'login-approval':
159
+ console.log('Enter code > ');
160
+ rl.on('line', (line) => {
161
+ err.continue(line);
162
+ rl.close();
163
+ });
164
+ break;
165
+ default:
166
+ console.error(err);
167
+ }
168
+ return;
169
+ }
170
+
171
+ // Logged in!
172
+ });
173
+ ```
174
+
175
+ __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`.
176
+
177
+
178
+ ---------------------------------------
179
+
180
+ <a name="addUserToGroup"></a>
181
+ ### api.addUserToGroup(userID, threadID[, callback])
182
+
183
+ Adds a user (or array of users) to a group chat.
184
+
185
+ __Arguments__
186
+
187
+ * `userID`: User ID or array of user IDs.
188
+ * `threadID`: Group chat ID.
189
+ * `callback(err)`: A callback called when the query is done (either with an error or with no arguments).
190
+
191
+ ---------------------------------------
192
+
193
+ <a name="changeAdminStatus"></a>
194
+ ### api.changeAdminStatus(threadID, adminIDs, adminStatus)
195
+
196
+ Given a adminID, or an array of adminIDs, will set the admin status of the user(s) to `adminStatus`.
197
+
198
+ __Arguments__
199
+ * `threadID`: ID of a group chat (can't use in one-to-one conversations)
200
+ * `adminIDs`: The id(s) of users you wish to admin/unadmin (string or an array).
201
+ * `adminStatus`: Boolean indicating whether the user(s) should be promoted to admin (`true`) or demoted to a regular user (`false`).
202
+
203
+ __Example__
204
+
205
+ ```js
206
+ const fs = require("fs");
207
+ const login = require("fca-kenlie-plays");
208
+
209
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, async function(err, api) {
210
+ if (err) return console.error(err);
211
+
212
+ let threadID = "0000000000000000";
213
+ let newAdmins = ["111111111111111", "222222222222222"];
214
+ await api.changeAdminStatus(threadID, newAdmins, true);
215
+
216
+ let adminToRemove = "333333333333333";
217
+ await api.changeAdminStatus(threadID, adminToRemove, false);
218
+
219
+ });
220
+
221
+ ```
222
+
223
+ ---------------------------------------
224
+
225
+ <a name="changeArchivedStatus"></a>
226
+ ### api.changeArchivedStatus(threadOrThreads, archive[, callback])
227
+
228
+ 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.
229
+
230
+ __Arguments__
231
+ * `threadOrThreads`: The id(s) of the threads you wish to archive/unarchive.
232
+ * `archive`: Boolean indicating the new archive status to assign to the thread(s).
233
+ * `callback(err)`: A callback called when the query is done (either with an error or null).
234
+
235
+ __Example__
236
+
237
+ ```js
238
+ const fs = require("fs");
239
+ const login = require("fca-kenlie-plays");
240
+
241
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
242
+ if(err) return console.error(err);
243
+
244
+ api.changeArchivedStatus("000000000000000", true, (err) => {
245
+ if(err) return console.error(err);
246
+ });
247
+ });
248
+ ```
249
+
250
+ ---------------------------------------
251
+
252
+ <a name="changeBlockedStatus"></a>
253
+ ### api.changeBlockedStatus(userID, block[, callback])
254
+
255
+ Prevents a user from privately contacting you. (Messages in a group chat will still be seen by both parties).
256
+
257
+ __Arguments__
258
+
259
+ * `userID`: User ID.
260
+ * `block`: Boolean indicating whether to block or unblock the user (true for block).
261
+ * `callback(err)`: A callback called when the query is done (either with an error or with no arguments).
262
+
263
+ ---------------------------------------
264
+
265
+ <a name="changeGroupImage"></a>
266
+ ### api.changeGroupImage(image, threadID[, callback])
267
+
268
+ Will change the group chat's image to the given image.
269
+
270
+ __Arguments__
271
+ * `image`: File stream of image.
272
+ * `threadID`: String representing the ID of the thread.
273
+ * `callback(err)`: A callback called when the change is done (either with an error or null).
274
+
275
+ __Example__
276
+
277
+ ```js
278
+ const fs = require("fs");
279
+ const login = require("fca-kenlie-plays");
280
+
281
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
282
+ if(err) return console.error(err);
283
+
284
+ api.changeGroupImage(fs.createReadStream("./avatar.png"), "000000000000000", (err) => {
285
+ if(err) return console.error(err);
286
+ });
287
+ });
288
+ ```
289
+
290
+ ---------------------------------------
291
+
292
+ <a name="changeNickname"></a>
293
+ ### api.changeNickname(nickname, threadID, participantID[, callback])
294
+
295
+ Will change the thread user nickname to the one provided.
296
+
297
+ __Arguments__
298
+ * `nickname`: String containing a nickname. Leave empty to reset nickname.
299
+ * `threadID`: String representing the ID of the thread.
300
+ * `participantID`: String representing the ID of the user.
301
+ * `callback(err)`: An optional callback called when the change is done (either with an error or null).
302
+
303
+ __Example__
304
+
305
+ ```js
306
+ const fs = require("fs");
307
+ const login = require("fca-kenlie-plays");
308
+
309
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
310
+ if(err) return console.error(err);
311
+
312
+ api.changeNickname("Example", "000000000000000", "000000000000000", (err) => {
313
+ if(err) return console.error(err);
314
+ });
315
+ });
316
+ ```
317
+
318
+ ---------------------------------------
319
+
320
+ <a name="changeThreadColor"></a>
321
+ ### api.changeThreadColor(color, threadID[, callback])
322
+
323
+ Will change the thread color to the given hex string color ("#0000ff"). Set it
324
+ to empty string if you want the default.
325
+
326
+ Note: the color needs to start with a "#".
327
+
328
+ __Arguments__
329
+ * `color`: String representing a theme ID (a list of theme ID can be found at `api.threadColors`).
330
+ * `threadID`: String representing the ID of the thread.
331
+ * `callback(err)`: A callback called when the change is done (either with an error or null).
332
+
333
+ __Example__
334
+
335
+ ```js
336
+ const fs = require("fs");
337
+ const login = require("fca-kenlie-plays");
338
+
339
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
340
+ if(err) return console.error(err);
341
+
342
+ api.changeThreadColor("#0000ff", "000000000000000", (err) => {
343
+ if(err) return console.error(err);
344
+ });
345
+ });
346
+ ```
347
+
348
+ ---------------------------------------
349
+
350
+ <a name="changeThreadEmoji"></a>
351
+ ### api.changeThreadEmoji(emoji, threadID[, callback])
352
+
353
+ Will change the thread emoji to the one provided.
354
+
355
+ Note: The UI doesn't play nice with all emoji.
356
+
357
+ __Arguments__
358
+ * `emoji`: String containing a single emoji character.
359
+ * `threadID`: String representing the ID of the thread.
360
+ * `callback(err)`: A callback called when the change is done (either with an error or null).
361
+
362
+ __Example__
363
+
364
+ ```js
365
+ const fs = require("fs");
366
+ const login = require("fca-kenlie-plays");
367
+
368
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
369
+ if(err) return console.error(err);
370
+
371
+ api.changeThreadEmoji("💯", "000000000000000", (err) => {
372
+ if(err) return console.error(err);
373
+ });
374
+ });
375
+ ```
376
+
377
+ ---------------------------------------
378
+
379
+ <a name="createNewGroup"></a>
380
+ ### api.createNewGroup(participantIDs[, groupTitle][, callback])
381
+
382
+ Create a new group chat.
383
+
384
+ __Arguments__
385
+ * `participantIDs`: An array containing participant IDs. (*Length must be >= 2*)
386
+ * `groupTitle`: The title of the new group chat.
387
+ * `callback(err, threadID)`: A callback called when created.
388
+
389
+ ---------------------------------------
390
+
391
+ <a name="createPoll"></a>
392
+ ### api.createPoll(title, threadID[, options][, callback]) (*temporary deprecated because Facebook is updating this feature*)
393
+
394
+ Creates a poll with the specified title and optional poll options, which can also be initially selected by the logged-in user.
395
+
396
+ __Arguments__
397
+ * `title`: String containing a title for the poll.
398
+ * `threadID`: String representing the ID of the thread.
399
+ * `options`: An optional `string : bool` dictionary to specify initial poll options and their initial states (selected/not selected), respectively.
400
+ * `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.
401
+
402
+ __Example__
403
+
404
+ ```js
405
+ const fs = require("fs");
406
+ const login = require("fca-kenlie-plays");
407
+
408
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
409
+ if(err) return console.error(err);
410
+
411
+ api.createPoll("Example Poll", "000000000000000", {
412
+ "Option 1": false,
413
+ "Option 2": true
414
+ }, (err) => {
415
+ if(err) return console.error(err);
416
+ });
417
+ });
418
+ ```
419
+
420
+ ---------------------------------------
421
+
422
+ <a name="deleteMessage"></a>
423
+ ### api.deleteMessage(messageOrMessages[, callback])
424
+
425
+ Takes a messageID or an array of messageIDs and deletes the corresponding message.
426
+
427
+ __Arguments__
428
+ * `messageOrMessages`: A messageID string or messageID string array
429
+ * `callback(err)`: A callback called when the query is done (either with an error or null).
430
+
431
+ __Example__
432
+ ```js
433
+ const fs = require("fs");
434
+ const login = require("fca-kenlie-plays");
435
+
436
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
437
+ if(err) return console.error(err);
438
+
439
+ api.listen((err, message) => {
440
+ if(message.body) {
441
+ api.sendMessage(message.body, message.threadID, (err, messageInfo) => {
442
+ if(err) return console.error(err);
443
+
444
+ api.deleteMessage(messageInfo.messageID);
445
+ });
446
+ }
447
+ });
448
+ });
449
+ ```
450
+
451
+ ---------------------------------------
452
+
453
+ <a name="deleteThread"></a>
454
+ ### api.deleteThread(threadOrThreads[, callback])
455
+
456
+ 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.
457
+
458
+ __Arguments__
459
+
460
+ * `threadOrThreads` - The id(s) of the threads you wish to remove from your account.
461
+ * `callback(err)` - A callback called when the operation is done, maybe with an object representing an error.
462
+
463
+ __Example__
464
+
465
+ ```js
466
+ const fs = require("fs");
467
+ const login = require("fca-kenlie-plays");
468
+
469
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
470
+ if(err) return console.error(err);
471
+
472
+ api.deleteThread("000000000000000", (err) => {
473
+ if(err) return console.error(err);
474
+ });
475
+ });
476
+ ```
477
+
478
+ ---------------------------------------
479
+
480
+ <a name="forwardAttachment"></a>
481
+ ### api.forwardAttachment(attachmentID, userOrUsers[, callback])
482
+
483
+ Forwards corresponding attachment to given userID or to every user from an array of userIDs
484
+
485
+ __Arguments__
486
+ * `attachmentID`: The ID field in the attachment object. Recorded audio cannot be forwarded.
487
+ * `userOrUsers`: A userID string or usersID string array
488
+ * `callback(err)`: A callback called when the query is done (either with an error or null).
489
+
490
+ ---------------------------------------
491
+
492
+ <a name="getAppState"></a>
493
+ ### api.getAppState()
494
+
495
+ Returns current appState which can be saved to a file or stored in a variable.
496
+
497
+ ---------------------------------------
498
+
499
+ <a name="getCurrentUserID"></a>
500
+ ### api.getCurrentUserID()
501
+
502
+ Returns the currently logged-in user's Facebook user ID.
503
+
504
+ ---------------------------------------
505
+
506
+ <a name="getEmojiUrl"></a>
507
+ ### api.getEmojiUrl(c, size[, pixelRatio])
508
+
509
+ Returns the URL to a Facebook Messenger-style emoji image asset.
510
+
511
+ __note__: This function will return a URL regardless of whether the image at the URL actually exists.
512
+ This can happen if, for example, Messenger does not have an image asset for the requested emoji.
513
+
514
+ __Arguments__
515
+
516
+ * `c` - The emoji character
517
+ * `size` - The width and height of the emoji image; supported sizes are 32, 64, and 128
518
+ * `pixelRatio` - The pixel ratio of the emoji image; supported ratios are '1.0' and '1.5' (default is '1.0')
519
+
520
+ __Example__
521
+
522
+ ```js
523
+ const fs = require("fs");
524
+ const login = require("fca-kenlie-plays");
525
+
526
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
527
+ if(err) return console.error(err);
528
+
529
+ // Prints https://static.xx.fbcdn.net/images/emoji.php/v8/z9c/1.0/128/1f40d.png
530
+ console.log('Snake emoji, 128px (128x128 with pixel ratio of 1.0');
531
+ console.log(api.getEmojiUrl('\ud83d\udc0d', 128));
532
+
533
+ // Prints https://static.xx.fbcdn.net/images/emoji.php/v8/ze1/1.5/128/1f40d.png
534
+ console.log('Snake emoji, 192px (128x128 with pixel ratio of 1.5');
535
+ console.log(api.getEmojiUrl('\ud83d\udc0d', 128, '1.5'));
536
+ });
537
+ ```
538
+
539
+ ---------------------------------------
540
+
541
+ <a name="getFriendsList"></a>
542
+ ### api.getFriendsList(callback)
543
+
544
+ Returns an array of objects with some information about your friends.
545
+
546
+ __Arguments__
547
+
548
+ * `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`.
549
+
550
+ __Example__
551
+
552
+ ```js
553
+ const fs = require("fs");
554
+ const login = require("fca-kenlie-plays");
555
+
556
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
557
+ if(err) return console.error(err);
558
+
559
+ api.getFriendsList((err, data) => {
560
+ if(err) return console.error(err);
561
+
562
+ console.log(data.length);
563
+ });
564
+ });
565
+ ```
566
+
567
+ ---------------------------------------
568
+
569
+ <a name="getThreadHistory"></a>
570
+ ### api.getThreadHistory(threadID, amount, timestamp, callback)
571
+
572
+ Takes a threadID, number of messages, a timestamp, and a callback.
573
+
574
+ __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.
575
+
576
+ __Arguments__
577
+ * `threadID`: A threadID corresponding to the target chat
578
+ * `amount`: The amount of messages to *request*
579
+ * `timestamp`: Used to described the time of the most recent message to load. If timestamp is `undefined`, facebook will load the most recent messages.
580
+ * `callback(error, history)`: If error is null, history will contain an array of message objects.
581
+
582
+ __Example__
583
+
584
+ 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.
585
+
586
+ ```js
587
+ var timestamp = undefined;
588
+
589
+ function loadNextThreadHistory(api){
590
+ api.getThreadHistory(threadID, 50, timestamp, (err, history) => {
591
+ if(err) return console.error(err);
592
+
593
+ /*
594
+ Since the timestamp is from a previous loaded message,
595
+ that message will be included in this history so we can discard it unless it is the first load.
596
+ */
597
+ if(timestamp != undefined) history.pop();
598
+
599
+ /*
600
+ Handle message history
601
+ */
602
+
603
+ timestamp = history[0].timestamp;
604
+ });
605
+ }
606
+ ```
607
+
608
+ ---------------------------------------
609
+
610
+ <a name="getThreadInfo"></a>
611
+ ### api.getThreadInfo(threadID[, callback])
612
+
613
+ Takes a threadID and a callback. Works for both single-user and group threads.
614
+
615
+ __Arguments__
616
+ * `threadID`: A threadID corresponding to the target thread.
617
+ * `callback(err, info)`: If `err` is `null`, `info` will contain the following properties:
618
+
619
+ | Key | Description |
620
+ |----------|:-------------:|
621
+ | threadID | ID of the thread |
622
+ | participantIDs | Array of user IDs in the thread |
623
+ | 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. |
624
+ | 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. |
625
+ | nicknames | Map of nicknames for members of the thread. If there are no nicknames set, this will be null. |
626
+ | unreadCount | Number of unread messages |
627
+ | messageCount | Number of messages |
628
+ | imageSrc | URL to the group chat photo. Null if unset or a 1-1 thread. |
629
+ | timestamp | Timestamp of last activity |
630
+ | 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. |
631
+ | isGroup | boolean, true if this thread is a group thread (more than 2 participants). |
632
+ | isSubscribed | |
633
+ | folder | The folder that the thread is in. Can be one of: <ul><li>'inbox'</li><li>'archive'</li></ul> |
634
+ | isArchived | True if the thread is archived, false if not |
635
+ | cannotReplyReason | If you cannot reply to this thread, this will be a string stating why. Otherwise it will be null. |
636
+ | lastReadTimestamp | Timestamp of the last message that is marked as 'read' by the current user. |
637
+ | emoji | Object with key 'emoji' whose value is the emoji unicode character. Null if unset. |
638
+ | color | String form of the custom color in hexadecimal form. |
639
+ | adminIDs | Array of user IDs of the admins of the thread. Empty array if unset. |
640
+ | approvalMode | `true` or `false`, used to check if this group requires admin approval to add users |
641
+ | 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> |
642
+
643
+ ---------------------------------------
644
+
645
+ <a name="getThreadList"></a>
646
+ ### api.getThreadList(limit, timestamp, tags, callback)
647
+
648
+ Returns information about the user's threads.
649
+
650
+ __Arguments__
651
+
652
+ * `limit`: Limit the number of threads to fetch.
653
+ * `timestamp`: Request threads *before* this date. `null` means *now*
654
+ * `tags`: An array describing which folder to fetch. It should be one of these:
655
+ - `["INBOX"]` *(same as `[]`)*
656
+ - `["ARCHIVED"]`
657
+ - `["PENDING"]`
658
+ - `["OTHER"]`
659
+ - `["INBOX", "unread"]`
660
+ - `["ARCHIVED", "unread"]`
661
+ - `["PENDING", "unread"]`
662
+ - `["OTHER", "unread"]`
663
+
664
+ *if you find something new, let us know*
665
+
666
+ * `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:
667
+
668
+ __Thread list__
669
+
670
+ | Key | Description |
671
+ |----------------------|-------------------------------------------------------------|
672
+ | threadID | ID of the thread |
673
+ | name | The name of the thread |
674
+ | unreadCount | Amount of unread messages in thread |
675
+ | messageCount | Amount of messages in thread |
676
+ | imageSrc | Link to the thread's image or `null` |
677
+ | emoji | The default emoji in thread (classic like is `null`) |
678
+ | color | Thread's message color in `RRGGBB` (default blue is `null`) |
679
+ | nicknames | An array of `{"userid": "1234", "nickname": "John Doe"}` |
680
+ | muteUntil | Timestamp until the mute expires or `null` |
681
+ | participants | An array of participants. See below |
682
+ | adminIDs | An array of thread admin IDs |
683
+ | folder | `INBOX`, `ARCHIVED`, `PENDING` or `OTHER` |
684
+ | isGroup | `true` or `false` |
685
+ | customizationEnabled | `false` in one-to-one conversations with `Page` or `ReducedMessagingActor` |
686
+ | participantAddMode | currently `"ADD"` for groups and `null` otherwise |
687
+ | reactionsMuteMode | `REACTIONS_NOT_MUTED` or `REACTIONS_MUTED` |
688
+ | mentionsMuteMode | `MENTIONS_NOT_MUTED` or `MENTIONS_MUTED` |
689
+ | isArchived | `true` or `false` |
690
+ | isSubscribed | `true` or `false` |
691
+ | timestamp | timestamp in miliseconds |
692
+ | snippet | Snippet's text message |
693
+ | snippetAttachments | Attachments in snippet |
694
+ | snippetSender | ID of snippet sender |
695
+ | lastMessageTimestamp | timestamp in milliseconds |
696
+ | lastReadTimestamp | timestamp in milliseconds or `null` |
697
+ | cannotReplyReason | `null`, `"RECIPIENTS_NOT_LOADABLE"` or `"BLOCKED"` |
698
+ | approvalMode | `true` or `false`, used to check if this group requires admin approval to add users |
699
+
700
+ __`participants` format__
701
+
702
+ `accountType` is one of the following:
703
+ - `"User"`
704
+ - `"Page"`
705
+ - `"UnavailableMessagingActor"`
706
+ - `"ReducedMessagingActor"`
707
+
708
+ (*there might be more*)
709
+
710
+ <table>
711
+ <tr>
712
+ <th>Account type</th>
713
+ <th>Key</th>
714
+ <th>Description</th>
715
+ </tr>
716
+ <tr>
717
+ <td rowspan="12"><code>"User"</code></td>
718
+ <td>userID</td>
719
+ <td>ID of user</td>
720
+ </tr>
721
+ <tr>
722
+ <td>name</td>
723
+ <td>Full name of user</td>
724
+ </tr>
725
+ <tr>
726
+ <td>shortName</td>
727
+ <td>Short name of user (most likely first name)</td>
728
+ </tr>
729
+ <tr>
730
+ <td>gender</td>
731
+ <td>Either
732
+ <code>"MALE"</code>,
733
+ <code>"FEMALE"</code>,
734
+ <code>"NEUTER"</code> or
735
+ <code>"UNKNOWN"</code>
736
+ </td>
737
+ </tr>
738
+ <tr>
739
+ <td>url</td>
740
+ <td>URL of the user's Facebook profile</td>
741
+ </tr>
742
+ <tr>
743
+ <td>profilePicture</td>
744
+ <td>URL of the profile picture</td>
745
+ </tr>
746
+ <tr>
747
+ <td>username</td>
748
+ <td>Username of user or
749
+ <code>null</code>
750
+ </td>
751
+ </tr>
752
+ <tr>
753
+ <td>isViewerFriend</td>
754
+ <td>Is the user a friend of you?</td>
755
+ </tr>
756
+ <tr>
757
+ <td>isMessengerUser</td>
758
+ <td>Does the user use Messenger?</td>
759
+ </tr>
760
+ <tr>
761
+ <td>isVerified</td>
762
+ <td>Is the user verified? (Little blue tick mark)</td>
763
+ </tr>
764
+ <tr>
765
+ <td>isMessageBlockedByViewer</td>
766
+ <td>Is the user blocking messages from you?</td>
767
+ </tr>
768
+ <tr>
769
+ <td>isViewerCoworker</td>
770
+ <td>Is the user your coworker?
771
+ </td>
772
+ </tr>
773
+
774
+ <tr>
775
+ <td rowspan="10"><code>"Page"</code></td>
776
+ <td>userID</td>
777
+ <td>ID of the page</td>
778
+ </tr>
779
+ <tr>
780
+ <td>name</td>
781
+ <td>Name of the fanpage</td>
782
+ </tr>
783
+ <tr>
784
+ <td>url</td>
785
+ <td>URL of the fanpage</td>
786
+ </tr>
787
+ <tr>
788
+ <td>profilePicture</td>
789
+ <td>URL of the profile picture</td>
790
+ </tr>
791
+ <tr>
792
+ <td>username</td>
793
+ <td>Username of user or
794
+ <code>null</code>
795
+ </td>
796
+ </tr>
797
+ <tr>
798
+ <td>acceptsMessengerUserFeedback</td>
799
+ <td></td>
800
+ </tr>
801
+ <tr>
802
+ <td>isMessengerUser</td>
803
+ <td>Does the fanpage use Messenger?</td>
804
+ </tr>
805
+ <tr>
806
+ <td>isVerified</td>
807
+ <td>Is the fanpage verified? (Little blue tick mark)</td>
808
+ </tr>
809
+ <tr>
810
+ <td>isMessengerPlatformBot</td>
811
+ <td>Is the fanpage a bot</td>
812
+ </tr>
813
+ <tr>
814
+ <td>isMessageBlockedByViewer</td>
815
+ <td>Is the fanpage blocking messages from you?</td>
816
+ </tr>
817
+
818
+ <tr>
819
+ <td rowspan="7"><code>"ReducedMessagingActor"</code><br />(account requres verification,<br />messages are hidden)</td>
820
+ <td>userID</td>
821
+ <td>ID of the user</td>
822
+ </tr>
823
+ <tr>
824
+ <td>name</td>
825
+ <td>Name of the user</td>
826
+ </tr>
827
+ <tr>
828
+ <td>url</td>
829
+ <td>
830
+ <code>null</code>
831
+ </td>
832
+ </tr>
833
+ <tr>
834
+ <td>profilePicture</td>
835
+ <td>URL of the default Facebook profile picture</td>
836
+ </tr>
837
+ <tr>
838
+ <td>username</td>
839
+ <td>Username of user</td>
840
+ </td>
841
+ </tr>
842
+ <tr>
843
+ <td>acceptsMessengerUserFeedback</td>
844
+ <td></td>
845
+ </tr>
846
+ <tr>
847
+ <td>isMessageBlockedByViewer</td>
848
+ <td>Is the user blocking messages from you?</td>
849
+ </tr>
850
+ <tr>
851
+ <td rowspan="7"><code>"UnavailableMessagingActor"</code><br />(account disabled/removed)</td>
852
+ <td>userID</td>
853
+ <td>ID of the user</td>
854
+ </tr>
855
+ <tr>
856
+ <td>name</td>
857
+ <td><em>Facebook User</em> in user's language</td>
858
+ </tr>
859
+ <tr>
860
+ <td>url</td>
861
+ <td><code>null</code></td>
862
+ </tr>
863
+ <tr>
864
+ <td>profilePicture</td>
865
+ <td>URL of the default **male** Facebook profile picture</td>
866
+ </tr>
867
+ <tr>
868
+ <td>username</td>
869
+ <td><code>null</code></td>
870
+ </tr>
871
+ <tr>
872
+ <td>acceptsMessengerUserFeedback</td>
873
+ <td></td>
874
+ </tr>
875
+ <tr>
876
+ <td>isMessageBlockedByViewer</td>
877
+ <td>Is the user blocking messages from you?</td>
878
+ </tr>
879
+ </table>
880
+
881
+
882
+ 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:
883
+
884
+ | Key | Description |
885
+ |--------------|-------------------------|
886
+ | accountType | type, can be anything |
887
+ | userID | ID of the account |
888
+ | name | Name of the account |
889
+
890
+
891
+ ---------------------------------------
892
+
893
+ <a name="getThreadPictures"></a>
894
+ ### api.getThreadPictures(threadID, offset, limit, callback)
895
+
896
+ Returns pictures sent in the thread.
897
+
898
+ __Arguments__
899
+
900
+ * `threadID`: A threadID corresponding to the target chat
901
+ * `offset`: Start index of picture to retrieve, where 0 is the most recent picture
902
+ * `limit`: Number of pictures to get, incrementing from the offset index
903
+ * `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`.
904
+
905
+ ---------------------------------------
906
+
907
+ <a name="getUserID"></a>
908
+ ### api.getUserID(name, callback)
909
+
910
+ 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).
911
+
912
+ __Arguments__
913
+
914
+ * `name` - A string being the name of the item you're looking for.
915
+ * `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).
916
+
917
+ __Example__
918
+
919
+ ```js
920
+ const fs = require("fs");
921
+ const login = require("fca-kenlie-plays");
922
+
923
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
924
+ if(err) return console.error(err);
925
+
926
+ api.getUserID("Marc Zuckerbot", (err, data) => {
927
+ if(err) return console.error(err);
928
+
929
+ // Send the message to the best match (best by Facebook's criteria)
930
+ var msg = "Hello!"
931
+ var threadID = data[0].userID;
932
+ api.sendMessage(msg, threadID);
933
+ });
934
+ });
935
+ ```
936
+
937
+ ---------------------------------------
938
+
939
+ <a name="getUserInfo"></a>
940
+ ### api.getUserInfo(ids, callback)
941
+
942
+ Will get some information about the given users.
943
+
944
+ __Arguments__
945
+
946
+ * `ids` - Either a string/number for one ID or an array of strings/numbers for a batched query.
947
+ * `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: `name`, `firstName`, `vanity` (user's chosen facebook handle, if any), `thumbSrc`, `profileUrl`, `gender`, `type` (type is generally user, group, page, event or app), `isFriend`, `isBirthday`, `searchTokens`, `alternateName`.
948
+
949
+ __Example__
950
+
951
+ ```js
952
+ const fs = require("fs");
953
+ const login = require("fca-kenlie-plays");
954
+
955
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
956
+ if(err) return console.error(err);
957
+
958
+ api.getUserInfo([1, 2, 3, 4], (err, ret) => {
959
+ if(err) return console.error(err);
960
+
961
+ for(var prop in ret) {
962
+ if(ret.hasOwnProperty(prop) && ret[prop].isBirthday) {
963
+ api.sendMessage("Happy birthday :)", prop);
964
+ }
965
+ }
966
+ });
967
+ });
968
+ ```
969
+
970
+ ---------------------------------------
971
+
972
+ <a name="threadColors"></a>
973
+ ### api.threadColors
974
+
975
+ 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.
976
+
977
+ - DefaultBlue: `196241301102133`
978
+ - HotPink: `169463077092846`
979
+ - AquaBlue: `2442142322678320`
980
+ - BrightPurple: `234137870477637`
981
+ - CoralPink: `980963458735625`
982
+ - Orange: `175615189761153`
983
+ - Green: `2136751179887052`
984
+ - LavenderPurple: `2058653964378557`
985
+ - Red: `2129984390566328`
986
+ - Yellow: `174636906462322`
987
+ - TealBlue: `1928399724138152`
988
+ - Aqua: `417639218648241`
989
+ - Mango: `930060997172551`
990
+ - Berry: `164535220883264`
991
+ - Citrus: `370940413392601`
992
+ - Candy: `205488546921017`
993
+ - ~~StarWars: `809305022860427`~~ (Facebook removed it.)
994
+
995
+ ---------------------------------------
996
+
997
+ <a name="handleMessageRequest"></a>
998
+ ### api.handleMessageRequest(threadID, accept[, callback])
999
+
1000
+ Accept or ignore message request(s) with thread id `threadID`.
1001
+
1002
+ __Arguments__
1003
+
1004
+ * `threadID`: A threadID or array of threadIDs corresponding to the target thread(s). Can be numbers or strings.
1005
+ * `accept`: Boolean indicating the new status to assign to the message request(s); true for inbox, false to others.
1006
+ * `callback(err)`: A callback called when the query is done (with an error or with null).
1007
+
1008
+ ---------------------------------------
1009
+
1010
+ <a name="listen"></a>
1011
+ ### api.listen([callback])
1012
+ <a name="listenMqtt"></a>
1013
+ ### api.listenMqtt([callback])
1014
+
1015
+ Will call `callback` when a new message is received on this account.
1016
+ 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.
1017
+
1018
+ 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.
1019
+
1020
+ __Arguments__
1021
+
1022
+ - `callback(error, message)`: A callback called every time the logged-in account receives a new message.
1023
+
1024
+ <a name="message"></a>
1025
+ __Message__
1026
+
1027
+ 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:
1028
+
1029
+ <table>
1030
+ <tr>
1031
+ <th>Event Type</th>
1032
+ <th>Field</th>
1033
+ <th>Description</th>
1034
+ </tr>
1035
+ <tr>
1036
+ <td rowspan="10">
1037
+ <code>"message"</code><br />
1038
+ A message was sent to a thread.
1039
+ </td>
1040
+ <td><code>attachments</code></td>
1041
+ <td>An array of attachments to the message. Attachments vary in type, see the attachments table below.</td>
1042
+ </tr>
1043
+ <tr>
1044
+ <td><code>body</code></td>
1045
+ <td>The string corresponding to the message that was just received.</td>
1046
+ </tr>
1047
+ <tr>
1048
+ <td><code>isGroup</code></td>
1049
+ <td>boolean, true if this thread is a group thread (more than 2 participants).</td>
1050
+ </tr>
1051
+ <tr>
1052
+ <td><code>mentions</code></td>
1053
+ <td>An object containing people mentioned/tagged in the message in the format { id: name }</td>
1054
+ </tr>
1055
+ <tr>
1056
+ <td><code>messageID</code></td>
1057
+ <td>A string representing the message ID.</td>
1058
+ </tr>
1059
+ <tr>
1060
+ <td><code>senderID</code></td>
1061
+ <td>The id of the person who sent the message in the chat with threadID.</td>
1062
+ </tr>
1063
+ <tr>
1064
+ <td><code>threadID</code></td>
1065
+ <td>The threadID representing the thread in which the message was sent.</td>
1066
+ </tr>
1067
+ <tr>
1068
+ <td><code>isUnread</code></td>
1069
+ <td>Boolean representing whether or not the message was read.</td>
1070
+ </tr>
1071
+ <tr>
1072
+ <td><code>participantIDs</code></td>
1073
+ <td>An array containing participant IDs.</td>
1074
+ </tr>
1075
+ <tr>
1076
+ <td><code>type</code></td>
1077
+ <td>For this event type, this will always be the string <code>"message"</code>.</td>
1078
+ </tr>
1079
+ <tr>
1080
+ <td rowspan="7">
1081
+ <code>"event"</code><br />
1082
+ An event occurred within a thread. Note that receiving this event type needs to be enabled with `api.setOptions({ listenEvents: true })`
1083
+ </td>
1084
+ <td><code>author</code></td>
1085
+ <td>The person who performed the event.</td>
1086
+ </tr>
1087
+ <tr>
1088
+ <td><code>logMessageBody</code></td>
1089
+ <td>String printed in the chat.</td>
1090
+ </tr>
1091
+ <tr>
1092
+ <td><code>logMessageData</code></td>
1093
+ <td>Data relevant to the event.</td>
1094
+ </tr>
1095
+ <tr>
1096
+ <td><code>logMessageType</code></td>
1097
+ <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>, <code>log:thread-call</code>, <code>log:thread-admins</code>)</td>
1098
+ </tr>
1099
+ <tr>
1100
+ <td><code>threadID</code></td>
1101
+ <td>The threadID representing the thread in which the message was sent.</td>
1102
+ </tr>
1103
+ <tr>
1104
+ <td><code>participantIDs</code></td>
1105
+ <td>An array containing participant IDs.</td>
1106
+ </tr>
1107
+ <tr>
1108
+ <td><code>type</code></td>
1109
+ <td>For this event type, this will always be the string <code>"event"</code>.</td>
1110
+ </tr>
1111
+ <tr>
1112
+ <td rowspan="5">
1113
+ <code>"typ"</code><br />
1114
+ A user in a thread is typing. Note that receiving this event type needs to be enabled with `api.setOptions({ listenTyping: true })`
1115
+ </td>
1116
+ <td><code>from</code></td>
1117
+ <td>ID of the user who started/stopped typing.</td>
1118
+ </tr>
1119
+ <tr>
1120
+ <td><code>fromMobile</code></td>
1121
+ <td>Boolean representing whether or not the person's using a mobile device to type.</td>
1122
+ </tr>
1123
+ <tr>
1124
+ <td><code>isTyping</code></td>
1125
+ <td>Boolean representing whether or not a person started typing.</td>
1126
+ </tr>
1127
+ <tr>
1128
+ <td><code>threadID</code></td>
1129
+ <td>The threadID representing the thread in which a user is typing.</td>
1130
+ </tr>
1131
+ <tr>
1132
+ <td><code>type</code></td>
1133
+ <td>For this event type, this will always be the string <code>"typ"</code>.</td>
1134
+ </tr>
1135
+ <tr>
1136
+ <td rowspan="3">
1137
+ <code>"read"</code><br />
1138
+ The current API user has read a message.
1139
+ </td>
1140
+ <td><code>threadID</code></td>
1141
+ <td>The threadID representing the thread in which the message was sent.</td>
1142
+ </tr>
1143
+ <tr>
1144
+ <td><code>time</code></td>
1145
+ <td>The time at which the user read the message.</td>
1146
+ </tr>
1147
+ <tr>
1148
+ <td><code>type</code></td>
1149
+ <td>For this event type, this will always be the string <code>"read"</code>.</td>
1150
+ </tr>
1151
+ <tr>
1152
+ <td rowspan="4">
1153
+ <code>"read_receipt"</code><br />
1154
+ A user within a thread has seen a message sent by the API user.
1155
+ </td>
1156
+ <td><code>reader</code></td>
1157
+ <td>ID of the user who just read the message.</td>
1158
+ </tr>
1159
+ <tr>
1160
+ <td><code>threadID</code></td>
1161
+ <td>The thread in which the message was read.</td>
1162
+ </tr>
1163
+ <tr>
1164
+ <td><code>time</code></td>
1165
+ <td>The time at which the reader read the message.</td>
1166
+ </tr>
1167
+ <tr>
1168
+ <td><code>type</code></td>
1169
+ <td>For this event type, this will always be the string <code>"read_receipt"</code>.</td>
1170
+ </tr>
1171
+ <tr>
1172
+ <td rowspan="8">
1173
+ <code>"message_reaction"</code><br />
1174
+ A user has sent a reaction to a message.
1175
+ </td>
1176
+ <td><code>messageID</code></td>
1177
+ <td>The ID of the message</td>
1178
+ </tr>
1179
+ <tr>
1180
+ <td><code>offlineThreadingID</code></td>
1181
+ <td>The offline message ID</td>
1182
+ </tr>
1183
+ <tr>
1184
+ <td><code>reaction</code></td>
1185
+ <td>Contains reaction emoji</td>
1186
+ </tr>
1187
+ <tr>
1188
+ <td><code>senderID</code></td>
1189
+ <td>ID of the author the message, where has been reaction added</td>
1190
+ </tr>
1191
+ <tr>
1192
+ <td><code>threadID</code></td>
1193
+ <td>ID of the thread where the message has been sent</td>
1194
+ </tr>
1195
+ <tr>
1196
+ <td><code>timestamp</code></td>
1197
+ <td>Unix Timestamp (in miliseconds) when the reaction was sent</td>
1198
+ </tr>
1199
+ <tr>
1200
+ <td><code>type</code></td>
1201
+ <td>For this event type, this will always be the string <code>"message_reaction"</code>.</td>
1202
+ </tr>
1203
+ <tr>
1204
+ <td><code>userID</code></td>
1205
+ <td>ID of the reaction sender</td>
1206
+ </tr>
1207
+ <tr>
1208
+ <td rowspan="4"><a name="presence"></a>
1209
+ <code>"presence"</code><br />
1210
+ 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>
1211
+ </td>
1212
+ <td><code>statuses</code></td>
1213
+ <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>
1214
+ </tr>
1215
+ <tr>
1216
+ <td><code>timestamp</code></td>
1217
+ <td>The time when the user was last online.</td>
1218
+ </tr>
1219
+ <tr>
1220
+ <td><code>type</code></td>
1221
+ <td>For this event type, this will always be the string <code>"presence"</code>.</td>
1222
+ </tr>
1223
+ <tr>
1224
+ <td><code>userID</code></td>
1225
+ <td>The ID of the user whose status this packet is describing.</td>
1226
+ </tr>
1227
+ <tr>
1228
+ <td rowspan="5">
1229
+ <code>"message_unsend"</code><br />
1230
+ A revoke message request for a message from a thread was received.
1231
+ </td>
1232
+ <td><code>threadID</code></td>
1233
+ <td>The threadID representing the thread in which the revoke message request was received.</td>
1234
+ </tr>
1235
+ <tr>
1236
+ <td><code>senderID</code></td>
1237
+ <td>The id of the person who request to revoke message on threadID.</td>
1238
+ </tr>
1239
+ <tr>
1240
+ <td><code>messageID</code></td>
1241
+ <td>A string representing the message ID that the person request to revoke message want to.</td>
1242
+ </tr>
1243
+ <tr>
1244
+ <td><code>deletionTimestamp</code></td>
1245
+ <td>The time when the request was sent.</td>
1246
+ </tr>
1247
+ <tr>
1248
+ <td><code>type</code></td>
1249
+ <td>For this event type, this will always be the string <code>"message_unsend"</code>.</td>
1250
+ </tr>
1251
+ <tr>
1252
+ <td rowspan="11">
1253
+ <code>"message_reply"</code><br />
1254
+ A reply message was sent to a thread.
1255
+ </td>
1256
+ <td><code>attachments</code></td>
1257
+ <td>An array of attachments to the message. Attachments vary in type, see the attachments table below.</td>
1258
+ </tr>
1259
+ <tr>
1260
+ <td><code>body</code></td>
1261
+ <td>The string corresponding to the message that was just received.</td>
1262
+ </tr>
1263
+ <tr>
1264
+ <td><code>isGroup</code></td>
1265
+ <td>boolean, true if this thread is a group thread (more than 2 participants).</td>
1266
+ </tr>
1267
+ <tr>
1268
+ <td><code>mentions</code></td>
1269
+ <td>An object containing people mentioned/tagged in the message in the format { id: name }</td>
1270
+ </tr>
1271
+ <tr>
1272
+ <td><code>messageID</code></td>
1273
+ <td>A string representing the message ID.</td>
1274
+ </tr>
1275
+ <tr>
1276
+ <td><code>senderID</code></td>
1277
+ <td>The id of the person who sent the message in the chat with threadID.</td>
1278
+ </tr>
1279
+ <tr>
1280
+ <td><code>threadID</code></td>
1281
+ <td>The threadID representing the thread in which the message was sent.</td>
1282
+ </tr>
1283
+ <tr>
1284
+ <td><code>isUnread</code></td>
1285
+ <td>Boolean representing whether or not the message was read.</td>
1286
+ </tr>
1287
+ <tr>
1288
+ <td><code>type</code></td>
1289
+ <td>For this event type, this will always be the string <code>"message_reply"</code>.</td>
1290
+ </tr>
1291
+ <tr>
1292
+ <td><code>participantIDs</code></td>
1293
+ <td>An array containing participant IDs.</td>
1294
+ </tr>
1295
+ <tr>
1296
+ <td><code>messageReply</code></td>
1297
+ <td>An object represent a message being replied. Content inside is the same like a normal <code>"message"</code> event.</td>
1298
+ </tr>
1299
+ </table>
1300
+
1301
+ __Attachments__
1302
+
1303
+ 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:
1304
+
1305
+ | Attachment Type | Fields |
1306
+ | --------------- | ------ |
1307
+ | `"sticker"` | `ID`, `url`, `packID`, `spriteUrl`, `spriteUrl2x`, `width`, `height`, `caption`, `description`, `frameCount`, `frameRate`, `framesPerRow`, `framesPerCol` |
1308
+ | `"file"` | `ID`, `filename`, `url`, `isMalicious`, `contentType` |
1309
+ | `"photo"` | `ID`, `filename`, `thumbnailUrl`, `previewUrl`, `previewWidth`, `previewHeight`, `largePreviewUrl`, `largePreviewWidth`, `largePreviewHeight` |
1310
+ | `"animated_image"` | `ID`, `filename`, `previewUrl`, `previewWidth`, `previewHeight`, `url`, `width`, `height` |
1311
+ | `"video"` | `ID`, `filename`, `previewUrl`, `previewWidth`, `previewHeight`, `url`, `width`, `height`, `duration`, `videoType` |
1312
+ | `"audio"` | `ID`, `filename`, `audioType`, `duration`, `url`, `isVoiceMail` |
1313
+ | `"location"` | `ID`, `latitude`, `longitude`, `image`, `width`, `height`, `url`, `address` |
1314
+ | `"share"` | `ID`, `url`, `title`, `description`, `source`, `image`, `width`, `height`, `playable`, `duration`, `playableUrl`, `subattachments`, `properties` |
1315
+
1316
+ __Example__
1317
+
1318
+ ```js
1319
+ const fs = require("fs");
1320
+ const login = require("fca-kenlie-plays");
1321
+
1322
+ // Simple echo bot. He'll repeat anything that you say.
1323
+ // Will stop when you say '/stop'
1324
+
1325
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1326
+ if(err) return console.error(err);
1327
+
1328
+ api.setOptions({listenEvents: true});
1329
+
1330
+ var listenEmitter = api.listen((err, event) => {
1331
+ if(err) return console.error(err);
1332
+
1333
+ switch (event.type) {
1334
+ case "message":
1335
+ if(event.body === '/stop') {
1336
+ api.sendMessage("Goodbye...", event.threadID);
1337
+ return listenEmitter.stopListening();
1338
+ }
1339
+ api.markAsRead(event.threadID, (err) => {
1340
+ if(err) console.log(err);
1341
+ });
1342
+ api.sendMessage("TEST BOT: " + event.body, event.threadID);
1343
+ break;
1344
+ case "event":
1345
+ console.log(event);
1346
+ break;
1347
+ }
1348
+ });
1349
+ });
1350
+ ```
1351
+
1352
+ ---------------------------------------
1353
+
1354
+ <a name="logout"></a>
1355
+ ### api.logout([callback])
1356
+
1357
+ Logs out the current user.
1358
+
1359
+ __Arguments__
1360
+
1361
+ * `callback(err)`: A callback called when the query is done (either with an error or with null).
1362
+
1363
+ ---------------------------------------
1364
+
1365
+ <a name="markAsDelivered"></a>
1366
+ ### api.markAsDelivered(threadID, messageID[, callback]])
1367
+
1368
+ 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.
1369
+
1370
+ You can also mark new messages as delivered automatically. This is enabled by default. See [api.setOptions](#setOptions).
1371
+
1372
+ __Arguments__
1373
+
1374
+ * `threadID` - The id of the thread in which you want to mark the message as delivered.
1375
+ * `messageID` - The id of the message want to mark as delivered.
1376
+ * `callback(err)` - A callback called when the operation is done maybe with an object representing an error.
1377
+
1378
+ __Example__
1379
+
1380
+ ```js
1381
+ const fs = require("fs");
1382
+ const login = require("facebook-chat-api");
1383
+
1384
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1385
+ if(err) return console.error(err);
1386
+
1387
+ api.listen((err, message) => {
1388
+ if(err) return console.error(err);
1389
+
1390
+ // Marks messages as delivered immediately after they're received
1391
+ api.markAsDelivered(message.threadID, message.messageID);
1392
+ });
1393
+ });
1394
+ ```
1395
+
1396
+ ---------------------------------------
1397
+
1398
+ <a name="markAsRead"></a>
1399
+ ### api.markAsRead(threadID, [read[, callback]])
1400
+
1401
+ 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.
1402
+
1403
+ 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.
1404
+
1405
+ __Arguments__
1406
+
1407
+ * `threadID` - The id of the thread in which you want to mark the messages as read.
1408
+ * `read` - An optional boolean where `true` means to mark the message as being "read" and `false` means to mark the message as being "unread".
1409
+ * `callback(err)` - A callback called when the operation is done maybe with an object representing an error.
1410
+
1411
+ __Example__
1412
+
1413
+ ```js
1414
+ const fs = require("fs");
1415
+ const login = require("fca-kenlie-plays");
1416
+
1417
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1418
+ if(err) return console.error(err);
1419
+
1420
+ api.listen((err, message) => {
1421
+ if(err) return console.error(err);
1422
+
1423
+ // Marks messages as read immediately after they're received
1424
+ api.markAsRead(message.threadID);
1425
+ });
1426
+ });
1427
+ ```
1428
+
1429
+ ---------------------------------------
1430
+
1431
+ <a name="markAsReadAll"></a>
1432
+ ### api.markAsReadAll([callback])
1433
+
1434
+ This function will mark all of messages in your inbox readed.
1435
+
1436
+ ---------------------------------------
1437
+
1438
+ <a name="markAsSeen"></a>
1439
+ ### api.markAsSeen([seenTimestamp][, callback])
1440
+
1441
+ This function will mark your entire inbox as seen (don't be confused with read!).
1442
+
1443
+ ---------------------------------------
1444
+
1445
+ <a name="muteThread"></a>
1446
+ ### api.muteThread(threadID, muteSeconds[, callback])
1447
+
1448
+ Mute a chat for a period of time, or unmute a chat.
1449
+
1450
+ __Arguments__
1451
+
1452
+ * `threadID` - The ID of the chat you want to mute.
1453
+ * `muteSeconds` - Mute the chat for this amount of seconds. Use `0` to unmute a chat. Use '-1' to mute a chat indefinitely.
1454
+ * `callback(err)` - A callback called when the operation is done maybe with an object representing an error.
1455
+
1456
+ __Example__
1457
+
1458
+ ```js
1459
+ const fs = require("fs");
1460
+ const login = require("fca-kenlie-plays");
1461
+
1462
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1463
+ if(err) return console.error(err);
1464
+
1465
+ api.listen((err, message) => {
1466
+ if(err) return console.error(err);
1467
+
1468
+ // Mute all incoming chats for one minute
1469
+ api.muteThread(message.threadID, 60);
1470
+ });
1471
+ });
1472
+ ```
1473
+
1474
+ ---------------------------------------
1475
+
1476
+ <a name="removeUserFromGroup"></a>
1477
+ ### api.removeUserFromGroup(userID, threadID[, callback])
1478
+
1479
+ Removes a user from a group chat.
1480
+
1481
+ __Arguments__
1482
+
1483
+ * `userID`: User ID.
1484
+ * `threadID`: Group chat ID.
1485
+ * `callback(err)`: A callback called when the query is done (either with an error or with no arguments).
1486
+
1487
+ ---------------------------------------
1488
+
1489
+ <a name="resolvePhotoUrl"></a>
1490
+ ### api.resolvePhotoUrl(photoID, callback)
1491
+
1492
+ Resolves the URL to the full-size photo, given its ID. This function is useful for retrieving the full-size photo URL
1493
+ of image attachments in messages, returned by [`api.getThreadHistory`](#getThreadHistory).
1494
+
1495
+ __Arguments__
1496
+
1497
+ * `photoID`: Photo ID.
1498
+ * `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.
1499
+
1500
+ ---------------------------------------
1501
+
1502
+ <a name="searchForThread"></a>
1503
+ ### api.searchForThread(name, callback)
1504
+
1505
+ > This part is outdated.
1506
+ > see #396
1507
+
1508
+ Takes a chat title (thread name) and returns matching results as a formatted threads array (ordered according to Facebook).
1509
+
1510
+ __Arguments__
1511
+ * `name`: A messageID string or messageID string array
1512
+ * `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`
1513
+
1514
+ ---------------------------------------
1515
+
1516
+ <a name="sendMessage"></a>
1517
+ ### api.sendMessage(message, threadID[, callback][, messageID])
1518
+
1519
+ Sends the given message to the threadID.
1520
+
1521
+ __Arguments__
1522
+
1523
+ * `message`: A string (for backward compatibility) or a message object as described below.
1524
+ * `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.
1525
+ * `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.
1526
+ * `messageID`: (Optional) A string representing a message you want to reply.
1527
+
1528
+ __Message Object__:
1529
+
1530
+ Various types of message can be sent:
1531
+ * *Regular:* set field `body` to the desired message as a string.
1532
+ * *Sticker:* set a field `sticker` to the desired sticker ID.
1533
+ * *File or image:* Set field `attachment` to a readable stream or an array of readable streams.
1534
+ * *URL:* set a field `url` to the desired URL.
1535
+ * *Emoji:* set field `emoji` to the desired emoji as a string and set field `emojiSize` with size of the emoji (`small`, `medium`, `large`)
1536
+ * *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`
1537
+ can be passed in to specify the start index to start searching for the `tag` text
1538
+ in `body` (default=0). (See below for an example.)
1539
+ * *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.
1540
+
1541
+ 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.
1542
+
1543
+ __Tip__: to find your own ID, you can look inside the cookies. The `userID` is under the name `c_user`.
1544
+
1545
+ __Example (Basic Message)__
1546
+ ```js
1547
+ const fs = require("fs");
1548
+ const login = require("fca-kenlie-plays");
1549
+
1550
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1551
+ if(err) return console.error(err);
1552
+
1553
+ var yourID = "000000000000000";
1554
+ var msg = {body: "Hey!"};
1555
+ api.sendMessage(msg, yourID);
1556
+ });
1557
+ ```
1558
+
1559
+ __Example (File upload)__
1560
+ ```js
1561
+ const fs = require("fs");
1562
+ const login = require("fca-kenlie-plays");
1563
+
1564
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1565
+ if(err) return console.error(err);
1566
+
1567
+ // This example uploads an image called image.jpg
1568
+ var yourID = "000000000000000";
1569
+ var msg = {
1570
+ body: "Hey!",
1571
+ attachment: fs.createReadStream(__dirname + '/image.jpg')
1572
+ }
1573
+ api.sendMessage(msg, yourID);
1574
+ });
1575
+ ```
1576
+
1577
+ __Example (Mention)__
1578
+ ```js
1579
+ const login = require("fca-kenlie-plays");
1580
+
1581
+ login({email: "EMAIL", password: "PASSWORD"}, (err, api) => {
1582
+ if(err) return console.error(err);
1583
+
1584
+ api.listen((err, message) => {
1585
+ if (message && message.body) {
1586
+ // Getting the actual sender name from ID involves calling
1587
+ // `api.getThreadInfo` and `api.getUserInfo`
1588
+ api.sendMessage({
1589
+ body: 'Hello @Sender! @Sender!',
1590
+ mentions: [{
1591
+ tag: '@Sender',
1592
+ id: message.senderID,
1593
+ fromIndex: 9, // Highlight the second occurrence of @Sender
1594
+ }],
1595
+ }, message.threadID);
1596
+ }
1597
+ });
1598
+ });
1599
+ ```
1600
+
1601
+ __Example (Location)__
1602
+ ```js
1603
+ const login = require("fca-kenlie-plays");
1604
+ login({email: "EMAIL", password: "PASSWORD"}, (err, api) => {
1605
+ if(err) return console.error(err);
1606
+ var yourID = "000000000000000";
1607
+ const msg = {
1608
+ location: { latitude: 48.858093, longitude: 2.294694, current: true },
1609
+ };
1610
+ api.sendMessage(msg, yourID);
1611
+ });
1612
+ ```
1613
+
1614
+ ---------------------------------------
1615
+
1616
+ <a name="sendTypingIndicator"></a>
1617
+ ### api.sendTypingIndicator(threadID[, callback])
1618
+
1619
+ 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`.
1620
+
1621
+ __Arguments__
1622
+
1623
+ * `threadID`: Group chat ID.
1624
+ * `callback(err)`: A callback called when the query is done (with an error or with null).
1625
+
1626
+ ---------------------------------------
1627
+
1628
+ <a name="setMessageReaction"></a>
1629
+ ### api.setMessageReaction(reaction, messageID[, callback[, forceCustomReaction]])
1630
+
1631
+ Sets reaction on message
1632
+
1633
+ __Arguments__
1634
+
1635
+ * `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.
1636
+ * `messageID`: A string representing the message ID.
1637
+ * `callback(err)`: A callback called when sending the reaction is done.
1638
+ * `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)**
1639
+
1640
+ __Supported Emojis__
1641
+
1642
+ |Emoji|Text|Unicode|Shortcuts|
1643
+ |---|---|---|---|
1644
+ |😍|`😍`|`\uD83D\uDE0D`|`:love:`, `:heart_eyes:`|
1645
+ |😆|`😆`|`\uD83D\uDE06`|`:haha:`, `:laughing:`|
1646
+ |😮|`😮`|`\uD83D\uDE2E`|`:wow:`, `:open_mouth:`|
1647
+ |😢|`😢`|`\uD83D\uDE22`|`:sad:`, `:cry:`|
1648
+ |😠|`😠`|`\uD83D\uDE20`|`:angry:`|
1649
+ |👍|`👍`|`\uD83D\uDC4D`|`:like:`, `:thumbsup:`|
1650
+ |👎|`👎`|`\uD83D\uDC4E`|`:dislike:`, `:thumbsdown:`|
1651
+ |❤|`❤`|`\u2764`|`:heart:`|
1652
+ |💗|`💗`|`\uD83D\uDC97`|`:glowingheart:`|
1653
+
1654
+ ---------------------------------------
1655
+
1656
+ <a name="setOptions"></a>
1657
+ ### api.setOptions(options)
1658
+
1659
+ Sets various configurable options for the api.
1660
+
1661
+ __Arguments__
1662
+
1663
+ * `options` - An object containing the new values for the options that you want
1664
+ to set. If the value for an option is unspecified, it is unchanged. The following options are possible.
1665
+ - `pauseLog`: (Default `false`) Set this to `true` if you want to pause the npmlog output.
1666
+ - `logLevel`: The desired logging level as determined by npmlog. Choose
1667
+ from either `"silly"`, `"verbose"`, `"info"`, `"http"`, `"warn"`, `"error"`, or `"silent"`.
1668
+ - `selfListen`: (Default `false`) Set this to `true` if you want your api
1669
+ to receive messages from its own account. This is to be used with
1670
+ caution, as it can result in loops (a simple echo bot will send messages
1671
+ forever).
1672
+ - `listenEvents`: (Default `false`) Will make [api.listen](#listen) also handle events (look at api.listen for more details).
1673
+ - `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.
1674
+ - `updatePresence`: (Default `false`) Will make [api.listen](#listen) also return `presence` ([api.listen](#presence) for more details).
1675
+ - `forceLogin`: (Default `false`) Will automatically approve of any recent logins and continue with the login process.
1676
+ - `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.
1677
+ - `autoMarkDelivery`: (Default `true`) Will automatically mark new messages as delivered. See [api.markAsDelivered](#markAsDelivered).
1678
+ - `autoMarkRead`: (Default `false`) Will automatically mark new messages as read/seen. See [api.markAsRead](#markAsRead).
1679
+ - `proxy`: (Default empty) Set this to proxy server address to use proxy. Note: Only HTTP Proxies which support CONNECT method is supported.
1680
+ - `online`: (Default `true`) Set account's online state.
1681
+
1682
+ __Example__
1683
+
1684
+ ```js
1685
+ const fs = require("fs");
1686
+ const login = require("fca-kenlie-plays");
1687
+
1688
+ // Simple echo bot. This will send messages forever.
1689
+
1690
+ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
1691
+ if(err) return console.error(err);
1692
+
1693
+ api.setOptions({
1694
+ selfListen: true,
1695
+ logLevel: "silent"
1696
+ });
1697
+
1698
+ api.listen((err, message) => {
1699
+ if(err) return console.error(err);
1700
+
1701
+ // Ignore empty messages (photos etc.)
1702
+ if (typeof message.body === "string") {
1703
+ api.sendMessage(message.body, message.threadID);
1704
+ }
1705
+ });
1706
+ });
1707
+ ```
1708
+
1709
+ ---------------------------------------
1710
+
1711
+ <a name="setTitle"></a>
1712
+ ### api.setTitle(newTitle, threadID[, callback])
1713
+
1714
+ Sets the title of the group chat with thread id `threadID` to `newTitle`.
1715
+
1716
+ 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.
1717
+
1718
+ __Arguments__
1719
+
1720
+ * `newTitle`: A string representing the new title.
1721
+ * `threadID`: A string or number representing a thread. It happens to be someone's userID in the case of a one to one conversation.
1722
+ * `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.
1723
+
1724
+ ---------------------------------------
1725
+
1726
+ <a name="unsendMessage"></a>
1727
+ ### api.unsendMessage(messageID[, callback])
1728
+
1729
+ Revokes a message from anyone that could see that message with `messageID`
1730
+
1731
+ Note: This will only work if the message is sent by you and was sent less than 10 minutes ago.
1732
+
1733
+ __Arguments__
1734
+
1735
+ * `messageID`: Message ID you want to unsend.
1736
+ * `callback(err)`: A callback called when the query is done (with an error or with null).
1737
+
1738
+ ---------------------------------------