@dongdev/fca-unofficial 3.0.31 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +224 -406
  3. package/dist/index.d.mts +1241 -0
  4. package/dist/index.d.ts +1241 -0
  5. package/dist/index.js +27749 -0
  6. package/dist/index.mjs +27713 -0
  7. package/docs/ARCHITECTURE.md +467 -0
  8. package/docs/DOCS.md +686 -0
  9. package/fca-config.example.json +33 -0
  10. package/package.json +32 -22
  11. package/test/fca.test.cjs +533 -0
  12. package/CHANGELOG.md +0 -296
  13. package/DOCS.md +0 -2712
  14. package/func/checkUpdate.js +0 -222
  15. package/func/logAdapter.js +0 -33
  16. package/func/logger.js +0 -48
  17. package/index.d.ts +0 -751
  18. package/index.js +0 -8
  19. package/module/config.js +0 -40
  20. package/module/login.js +0 -133
  21. package/module/loginHelper.js +0 -1296
  22. package/module/options.js +0 -44
  23. package/src/api/action/addExternalModule.js +0 -25
  24. package/src/api/action/changeAvatar.js +0 -137
  25. package/src/api/action/changeBio.js +0 -75
  26. package/src/api/action/enableAutoSaveAppState.js +0 -73
  27. package/src/api/action/getCurrentUserID.js +0 -7
  28. package/src/api/action/handleFriendRequest.js +0 -57
  29. package/src/api/action/logout.js +0 -76
  30. package/src/api/action/refreshFb_dtsg.js +0 -48
  31. package/src/api/action/setPostReaction.js +0 -106
  32. package/src/api/action/unfriend.js +0 -54
  33. package/src/api/http/httpGet.js +0 -46
  34. package/src/api/http/httpPost.js +0 -52
  35. package/src/api/http/postFormData.js +0 -47
  36. package/src/api/messaging/addUserToGroup.js +0 -68
  37. package/src/api/messaging/changeAdminStatus.js +0 -126
  38. package/src/api/messaging/changeArchivedStatus.js +0 -55
  39. package/src/api/messaging/changeBlockedStatus.js +0 -48
  40. package/src/api/messaging/changeGroupImage.js +0 -91
  41. package/src/api/messaging/changeNickname.js +0 -70
  42. package/src/api/messaging/changeThreadColor.js +0 -79
  43. package/src/api/messaging/changeThreadEmoji.js +0 -111
  44. package/src/api/messaging/createNewGroup.js +0 -88
  45. package/src/api/messaging/createPoll.js +0 -46
  46. package/src/api/messaging/createThemeAI.js +0 -98
  47. package/src/api/messaging/deleteMessage.js +0 -136
  48. package/src/api/messaging/deleteThread.js +0 -56
  49. package/src/api/messaging/editMessage.js +0 -68
  50. package/src/api/messaging/forwardAttachment.js +0 -57
  51. package/src/api/messaging/getEmojiUrl.js +0 -29
  52. package/src/api/messaging/getFriendsList.js +0 -82
  53. package/src/api/messaging/getMessage.js +0 -829
  54. package/src/api/messaging/getThemePictures.js +0 -62
  55. package/src/api/messaging/handleMessageRequest.js +0 -65
  56. package/src/api/messaging/markAsDelivered.js +0 -57
  57. package/src/api/messaging/markAsRead.js +0 -88
  58. package/src/api/messaging/markAsReadAll.js +0 -49
  59. package/src/api/messaging/markAsSeen.js +0 -61
  60. package/src/api/messaging/muteThread.js +0 -50
  61. package/src/api/messaging/removeUserFromGroup.js +0 -62
  62. package/src/api/messaging/resolvePhotoUrl.js +0 -43
  63. package/src/api/messaging/scheduler.js +0 -264
  64. package/src/api/messaging/searchForThread.js +0 -53
  65. package/src/api/messaging/sendMessage.js +0 -270
  66. package/src/api/messaging/sendTypingIndicator.js +0 -74
  67. package/src/api/messaging/setMessageReaction.js +0 -90
  68. package/src/api/messaging/setTitle.js +0 -124
  69. package/src/api/messaging/shareContact.js +0 -49
  70. package/src/api/messaging/threadColors.js +0 -128
  71. package/src/api/messaging/unsendMessage.js +0 -81
  72. package/src/api/messaging/uploadAttachment.js +0 -492
  73. package/src/api/socket/core/connectMqtt.js +0 -258
  74. package/src/api/socket/core/emitAuth.js +0 -103
  75. package/src/api/socket/core/getSeqID.js +0 -320
  76. package/src/api/socket/core/getTaskResponseData.js +0 -25
  77. package/src/api/socket/core/parseDelta.js +0 -377
  78. package/src/api/socket/detail/buildStream.js +0 -215
  79. package/src/api/socket/detail/constants.js +0 -28
  80. package/src/api/socket/listenMqtt.js +0 -377
  81. package/src/api/socket/middleware/index.js +0 -216
  82. package/src/api/threads/getThreadHistory.js +0 -664
  83. package/src/api/threads/getThreadInfo.js +0 -296
  84. package/src/api/threads/getThreadList.js +0 -293
  85. package/src/api/threads/getThreadPictures.js +0 -78
  86. package/src/api/users/getUserID.js +0 -65
  87. package/src/api/users/getUserInfo.js +0 -402
  88. package/src/api/users/getUserInfoV2.js +0 -134
  89. package/src/core/sendReqMqtt.js +0 -96
  90. package/src/database/helpers.js +0 -53
  91. package/src/database/models/index.js +0 -88
  92. package/src/database/models/thread.js +0 -50
  93. package/src/database/models/user.js +0 -46
  94. package/src/database/threadData.js +0 -94
  95. package/src/database/userData.js +0 -98
  96. package/src/remote/remoteClient.js +0 -123
  97. package/src/utils/broadcast.js +0 -51
  98. package/src/utils/client.js +0 -10
  99. package/src/utils/constants.js +0 -23
  100. package/src/utils/cookies.js +0 -68
  101. package/src/utils/format/attachment.js +0 -357
  102. package/src/utils/format/cookie.js +0 -9
  103. package/src/utils/format/date.js +0 -50
  104. package/src/utils/format/decode.js +0 -44
  105. package/src/utils/format/delta.js +0 -194
  106. package/src/utils/format/ids.js +0 -64
  107. package/src/utils/format/index.js +0 -64
  108. package/src/utils/format/message.js +0 -88
  109. package/src/utils/format/presence.js +0 -132
  110. package/src/utils/format/readTyp.js +0 -44
  111. package/src/utils/format/thread.js +0 -42
  112. package/src/utils/format/utils.js +0 -141
  113. package/src/utils/headers.js +0 -115
  114. package/src/utils/loginParser/autoLogin.js +0 -125
  115. package/src/utils/loginParser/helpers.js +0 -43
  116. package/src/utils/loginParser/index.js +0 -10
  117. package/src/utils/loginParser/parseAndCheckLogin.js +0 -220
  118. package/src/utils/loginParser/textUtils.js +0 -28
  119. package/src/utils/request/client.js +0 -26
  120. package/src/utils/request/config.js +0 -23
  121. package/src/utils/request/defaults.js +0 -46
  122. package/src/utils/request/helpers.js +0 -46
  123. package/src/utils/request/index.js +0 -17
  124. package/src/utils/request/methods.js +0 -163
  125. package/src/utils/request/proxy.js +0 -21
  126. package/src/utils/request/retry.js +0 -77
  127. package/src/utils/request/sanitize.js +0 -49
package/DOCS.md DELETED
@@ -1,2712 +0,0 @@
1
- # FCA-Unofficial — API Documentation
2
-
3
- ## Introduction
4
-
5
- **@dongdev/fca-unofficial** is an unofficial Node.js library for interacting with Facebook Messenger by emulating browser behavior. It lets you build chatbots and automate messaging on personal Facebook accounts (not just Pages).
6
-
7
- ## Project structure
8
-
9
- | Path | Description |
10
- |------|--------------|
11
- | `index.js` | Package entry point; exports `login`. |
12
- | `index.d.ts` | TypeScript definitions for the public API. |
13
- | `module/` | Login flow: `login.js`, `loginHelper.js`, `config.js`, `options.js`. |
14
- | `src/api/` | API implementations: `messaging/`, `threads/`, `users/`, `action/`, `http/`, `socket/`. |
15
- | `src/api/socket/` | MQTT/WebSocket real-time listening (`listenMqtt.js`, `core/`, `middleware/`). |
16
- | `src/utils/` | Shared utilities: `request.js`, `client.js`, `format.js`, `headers.js`, `cookies.js`, `broadcast.js` (optional helper). |
17
- | `src/database/` | Optional Sequelize models and data access for threads/users (used for caching and statistics). |
18
- | `src/remote/` | Lightweight WebSocket client for remote control (dashboard/server). |
19
- | `func/` | Logger, check-update, and other helpers. |
20
-
21
- For a concise codebase overview, see [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md).
22
-
23
- ## Installation
24
-
25
- ```bash
26
- npm install @dongdev/fca-unofficial@latest
27
- ```
28
-
29
- ---
30
-
31
- ## 1. LOGIN
32
-
33
- ### 1.1. Login with Email & Password
34
-
35
- ```javascript
36
- const login = require("@dongdev/fca-unofficial");
37
-
38
- const credentials = {
39
- email: "your_email@example.com",
40
- password: "your_password"
41
- };
42
-
43
- login(credentials, (err, api) => {
44
- if (err) {
45
- console.error("Login error:", err);
46
- return;
47
- }
48
- console.log("Login successful!");
49
- });
50
- ```
51
-
52
- ### 1.2. Login with 2FA (Two-Factor Authentication)
53
-
54
- When your account has 2FA enabled, you need to provide the 2FA code:
55
-
56
- ```javascript
57
- const login = require("@dongdev/fca-unofficial");
58
- const readline = require("readline");
59
-
60
- const rl = readline.createInterface({
61
- input: process.stdin,
62
- output: process.stdout
63
- });
64
-
65
- const credentials = {
66
- email: "your_email@example.com",
67
- password: "your_password"
68
- };
69
-
70
- login(credentials, (err, api) => {
71
- if (err) {
72
- // If 2FA is required
73
- if (err.error === 'login-approval') {
74
- console.log("2FA code required!");
75
-
76
- rl.question("Enter 2FA code: ", (code) => {
77
- err.continue(code);
78
- rl.close();
79
- });
80
- } else {
81
- console.error("Login error:", err);
82
- }
83
- return;
84
- }
85
-
86
- console.log("Login successful!");
87
- });
88
- ```
89
-
90
- ### 1.3. Login with AppState (Recommended)
91
-
92
- AppState is saved cookies and session data. Login with AppState helps avoid entering password each time and reduces checkpoint risk.
93
-
94
- #### Get and Save AppState:
95
-
96
- ```javascript
97
- const fs = require("fs");
98
- const login = require("@dongdev/fca-unofficial");
99
-
100
- const credentials = {
101
- email: "your_email@example.com",
102
- password: "your_password"
103
- };
104
-
105
- login(credentials, (err, api) => {
106
- if (err) {
107
- console.error("Login error:", err);
108
- return;
109
- }
110
-
111
- // Save AppState to file
112
- try {
113
- const appState = api.getAppState();
114
- fs.writeFileSync("appstate.json", JSON.stringify(appState, null, 2));
115
- console.log("✅ AppState saved!");
116
- } catch (error) {
117
- console.error("Error saving AppState:", error);
118
- }
119
- });
120
- ```
121
-
122
- #### Use Saved AppState:
123
-
124
- ```javascript
125
- const fs = require("fs");
126
- const login = require("@dongdev/fca-unofficial");
127
-
128
- const credentials = {
129
- appState: JSON.parse(fs.readFileSync("appstate.json", "utf8"))
130
- };
131
-
132
- login(credentials, (err, api) => {
133
- if (err) {
134
- console.error("Login error:", err);
135
- return;
136
- }
137
-
138
- console.log("Login successful with AppState!");
139
- });
140
- ```
141
-
142
- You can use the [c3c-fbstate](https://github.com/c3cbot/c3c-fbstate) tool to obtain AppState from your browser.
143
-
144
- ### 1.4. Auto Login (session recovery)
145
-
146
- When the session (AppState) expires, the library can automatically re-login using credentials from **`fca-config.json`**, so the bot can recover without manual restart.
147
-
148
- 1. Create **`fca-config.json`** in your project root (the directory from which you run your bot):
149
-
150
- ```json
151
- {
152
- "autoLogin": true,
153
- "apiServer": "https://minhdong.site",
154
- "apiKey": "",
155
- "credentials": {
156
- "email": "your_email_or_phone",
157
- "password": "your_password",
158
- "twofactor": ""
159
- }
160
- }
161
- ```
162
-
163
- 2. Log in with AppState as usual. When the session expires, the library will use these credentials (and optionally the external API at `apiServer`) to log in again and retry the failed request.
164
-
165
- | Option | Description |
166
- |--------|-------------|
167
- | `autoLogin` | `true` (default) or `false`. Set to `false` to disable automatic re-login when session expires. |
168
- | `apiServer` | Base URL for external login API (e.g. iOS-style login). Default: `https://minhdong.site`. |
169
- | `apiKey` | Optional API key for the external login server (e.g. `x-api-key` header). |
170
- | `credentials.email` | Facebook email or phone number. |
171
- | `credentials.password` | Facebook password. |
172
- | `credentials.twofactor` | Base32 secret for 2FA (TOTP). Leave empty if you do not use 2FA. Do not put the 6-digit code here. |
173
-
174
- **Security:** Add `fca-config.json` to `.gitignore`; it contains sensitive credentials.
175
-
176
- ---
177
-
178
- ## 2. CONFIGURATION (Options)
179
-
180
- ### 2.1. Runtime options (api.setOptions)
181
-
182
- After login, you can configure API options:
183
-
184
- ```javascript
185
- api.setOptions({
186
- // Listen to events (add/remove members, change group name, etc.)
187
- listenEvents: true,
188
-
189
- // Listen to your own messages
190
- selfListen: false,
191
-
192
- // Auto mark messages as read
193
- autoMarkRead: false,
194
-
195
- // Online status (true/false)
196
- online: true,
197
-
198
- // Log level (silent/error/warn/info/verbose)
199
- logLevel: "info",
200
-
201
- // Custom user agent
202
- userAgent: "Mozilla/5.0..."
203
- });
204
- ```
205
-
206
- ### 2.2. File config (fca-config.json)
207
-
208
- Optional config file in the project root (see [§ 1.4. Auto Login](#14-auto-login-session-recovery)):
209
-
210
- | Key | Description |
211
- |-----|-------------|
212
- | `autoLogin` | Enable/disable automatic re-login when session expires (default: `true`). |
213
- | `autoUpdate` | Check for package updates on startup (default: `true`). |
214
- | `mqtt` | `{ enabled, reconnectInterval }` for MQTT. |
215
- | `apiServer` | Base URL for external login API (default: `https://minhdong.site`). |
216
- | `apiKey` | Optional API key for the login server. |
217
- | `credentials` | `{ email, password, twofactor }` for auto-login and external API login. |
218
- | `antiGetInfo` | `{ AntiGetThreadInfo, AntiGetUserInfo }` switches between DB-backed anti-get-info and legacy behavior. |
219
- | `remoteControl` | `{ enabled, url, token, autoReconnect }` enables remote control over WebSocket. |
220
-
221
- ---
222
-
223
- ## 3. DETAILED API METHODS
224
-
225
- ### 3.1. sendMessage - Send Message
226
-
227
- Send message to user or group chat.
228
-
229
- #### Syntax:
230
- ```javascript
231
- api.sendMessage(message, threadID, [messageID], [callback])
232
- ```
233
-
234
- #### Parameters:
235
- - `message`: Message content (string or object)
236
- - `threadID`: Conversation ID (user ID or group ID)
237
- - `messageID`: (Optional) Message ID to reply to
238
- - `callback`: (Optional) Callback function `(err, messageInfo)`
239
-
240
- #### Basic Example:
241
-
242
- ```javascript
243
- api.sendMessage("Hello!", "100012345678901", (err, messageInfo) => {
244
- if (err) {
245
- console.error("Send message error:", err);
246
- return;
247
- }
248
- console.log("Message sent, ID:", messageInfo.messageID);
249
- });
250
- ```
251
-
252
- #### Send Messages with Various Content Types:
253
-
254
- ```javascript
255
- // 1. Simple text message
256
- api.sendMessage("Hello World", threadID);
257
-
258
- // 2. Send sticker
259
- api.sendMessage({
260
- sticker: "767334476655547" // Sticker ID
261
- }, threadID);
262
-
263
- // 3. Send emoji with size
264
- api.sendMessage({
265
- body: "Awesome!",
266
- emoji: "👍",
267
- emojiSize: "large" // small, medium, large
268
- }, threadID);
269
-
270
- // 4. Send file/image
271
- const fs = require("fs");
272
- api.sendMessage({
273
- body: "Here is an image",
274
- attachment: fs.createReadStream("./image.jpg")
275
- }, threadID);
276
-
277
- // 5. Send multiple files
278
- api.sendMessage({
279
- body: "Multiple attachments",
280
- attachment: [
281
- fs.createReadStream("./image1.jpg"),
282
- fs.createReadStream("./image2.jpg"),
283
- fs.createReadStream("./document.pdf")
284
- ]
285
- }, threadID);
286
-
287
- // 6. Send URL
288
- api.sendMessage({
289
- body: "Check this link",
290
- url: "https://example.com"
291
- }, threadID);
292
-
293
- // 7. Reply to message
294
- api.sendMessage({
295
- body: "This is a reply"
296
- }, threadID, messageID);
297
-
298
- // 8. Mention users
299
- api.sendMessage({
300
- body: "Hello @User1 and @User2!",
301
- mentions: [
302
- {
303
- tag: "@User1",
304
- id: "100012345678901",
305
- fromIndex: 6 // Starting position of @User1
306
- },
307
- {
308
- tag: "@User2",
309
- id: "100012345678902",
310
- fromIndex: 17
311
- }
312
- ]
313
- }, threadID);
314
- ```
315
-
316
- ---
317
-
318
- ### 3.2. listenMqtt - Listen for Messages
319
-
320
- Listen for messages and events from Facebook Messenger (using MQTT).
321
-
322
- #### Syntax:
323
- ```javascript
324
- const stopListening = api.listenMqtt(callback);
325
- ```
326
-
327
- #### Parameters:
328
- - `callback`: Function `(err, event)` called when new message/event arrives
329
-
330
- #### Example:
331
-
332
- ```javascript
333
- const stopListening = api.listenMqtt((err, event) => {
334
- if (err) {
335
- console.error("Listen error:", err);
336
- return;
337
- }
338
-
339
- // Handle events
340
- switch (event.type) {
341
- case "message":
342
- console.log("New message:", event.body);
343
- console.log("From user:", event.senderID);
344
- console.log("In conversation:", event.threadID);
345
-
346
- // Reply to message
347
- if (event.body === "Hi") {
348
- api.sendMessage("Hello!", event.threadID);
349
- }
350
- break;
351
-
352
- case "event":
353
- console.log("Event:", event.logMessageType);
354
- // log_message_type can be:
355
- // - log:subscribe (member added)
356
- // - log:unsubscribe (member removed)
357
- // - log:thread-name (group name changed)
358
- // - log:thread-icon (group icon changed)
359
- // - log:thread-color (chat color changed)
360
- break;
361
-
362
- case "typ":
363
- console.log(event.from, "is typing...");
364
- break;
365
-
366
- case "read_receipt":
367
- console.log("Message read by:", event.reader);
368
- break;
369
- }
370
- });
371
-
372
- // Stop listening
373
- // stopListening();
374
- ```
375
-
376
- #### Event Object Details:
377
-
378
- ```javascript
379
- // Event type: "message"
380
- {
381
- type: "message",
382
- threadID: "1234567890",
383
- messageID: "mid.xxx",
384
- senderID: "100012345678901",
385
- body: "Message content",
386
- args: ["Message", "content"], // Array of words from body (split by whitespace)
387
- attachments: [], // Array of attachments
388
- mentions: {}, // Object of mentions
389
- timestamp: 1234567890000,
390
- isGroup: false, // true if group chat
391
- isUnread: false, // Whether message is unread
392
- participantIDs: ["100012345678901"] // Array of participant IDs
393
- }
394
-
395
- // Event type: "event"
396
- {
397
- type: "event",
398
- threadID: "1234567890",
399
- logMessageType: "log:subscribe",
400
- logMessageData: {...},
401
- author: "100012345678901"
402
- }
403
-
404
- // Event type: "typ" (typing)
405
- {
406
- type: "typ",
407
- threadID: "1234567890",
408
- from: "100012345678901",
409
- isTyping: true
410
- }
411
-
412
- // Event type: "read_receipt" (read)
413
- {
414
- type: "read_receipt",
415
- threadID: "1234567890",
416
- reader: "100012345678901",
417
- time: 1234567890000
418
- }
419
- ```
420
-
421
- ---
422
-
423
- ### 3.3. Middleware System - Filter and Process Events
424
-
425
- The middleware system allows you to intercept, filter, and modify events before they are emitted to your callback. This is useful for logging, rate limiting, message filtering, auto-replies, and more.
426
-
427
- #### Syntax:
428
- ```javascript
429
- // Add middleware
430
- const removeMiddleware = api.useMiddleware(middlewareFunction);
431
- const removeMiddleware = api.useMiddleware("middlewareName", middlewareFunction);
432
-
433
- // Remove middleware
434
- api.removeMiddleware(identifier); // identifier can be name (string) or function
435
-
436
- // Clear all middleware
437
- api.clearMiddleware();
438
-
439
- // List middleware
440
- const names = api.listMiddleware();
441
-
442
- // Enable/disable middleware
443
- api.setMiddlewareEnabled("middlewareName", true); // enable
444
- api.setMiddlewareEnabled("middlewareName", false); // disable
445
-
446
- // Get middleware count
447
- const count = api.middlewareCount;
448
- ```
449
-
450
- #### Middleware Function Signature:
451
- ```javascript
452
- function middleware(event, next) {
453
- // event: The event object (can be modified)
454
- // next: Function to continue to next middleware
455
- // - next() - continue to next middleware
456
- // - next(false) or next(null) - stop processing, don't emit event
457
- // - next(error) - emit error instead
458
-
459
- // Your logic here
460
-
461
- next(); // Continue to next middleware
462
- }
463
- ```
464
-
465
- #### Examples:
466
-
467
- **1. Message Filtering - Block messages from specific users:**
468
- ```javascript
469
- api.useMiddleware("blockUsers", (event, next) => {
470
- if (event.type === "message") {
471
- const blockedUsers = ["100012345678901", "100012345678902"];
472
- if (blockedUsers.includes(event.senderID)) {
473
- // Block this message
474
- return next(false);
475
- }
476
- }
477
- next(); // Continue processing
478
- });
479
- ```
480
-
481
- **2. Logging Middleware:**
482
- ```javascript
483
- api.useMiddleware("logger", (event, next) => {
484
- if (event.type === "message") {
485
- console.log(`[${new Date().toISOString()}] Message from ${event.senderID}: ${event.body}`);
486
- }
487
- next(); // Continue to next middleware
488
- });
489
- ```
490
-
491
- **3. Auto-Reply Middleware:**
492
- ```javascript
493
- api.useMiddleware("autoReply", (event, next) => {
494
- if (event.type === "message" && event.body.toLowerCase() === "hello") {
495
- api.sendMessage("Hi there! How can I help you?", event.threadID);
496
- }
497
- next(); // Continue processing
498
- });
499
- ```
500
-
501
- **4. Rate Limiting Middleware:**
502
- ```javascript
503
- const messageCounts = {};
504
- const RATE_LIMIT = 10; // messages per minute
505
- const RATE_WINDOW = 60000; // 1 minute
506
-
507
- api.useMiddleware("rateLimit", (event, next) => {
508
- if (event.type === "message") {
509
- const now = Date.now();
510
- const senderID = event.senderID;
511
-
512
- // Clean old entries
513
- if (messageCounts[senderID] && messageCounts[senderID].timestamp < now - RATE_WINDOW) {
514
- delete messageCounts[senderID];
515
- }
516
-
517
- // Initialize or increment
518
- if (!messageCounts[senderID]) {
519
- messageCounts[senderID] = { count: 0, timestamp: now };
520
- }
521
- messageCounts[senderID].count++;
522
-
523
- // Check rate limit
524
- if (messageCounts[senderID].count > RATE_LIMIT) {
525
- console.log(`Rate limit exceeded for user ${senderID}`);
526
- return next(false); // Block message
527
- }
528
- }
529
- next();
530
- });
531
- ```
532
-
533
- **5. Message Transformation:**
534
- ```javascript
535
- api.useMiddleware("transform", (event, next) => {
536
- if (event.type === "message") {
537
- // Add custom property
538
- event.customProperty = "customValue";
539
-
540
- // Transform message body
541
- if (event.body) {
542
- event.body = event.body.toUpperCase();
543
- }
544
- }
545
- next();
546
- });
547
- ```
548
-
549
- **6. Async Middleware (Promise-based):**
550
- ```javascript
551
- api.useMiddleware("asyncMiddleware", async (event, next) => {
552
- if (event.type === "message") {
553
- // Do async operation
554
- const userInfo = await api.getUserInfo(event.senderID);
555
- event.senderName = userInfo[event.senderID].name;
556
- }
557
- next(); // Continue
558
- });
559
- ```
560
-
561
- **7. Conditional Middleware:**
562
- ```javascript
563
- // Only process messages in group chats
564
- api.useMiddleware("groupOnly", (event, next) => {
565
- if (event.type === "message" && !event.isGroup) {
566
- return next(false); // Skip non-group messages
567
- }
568
- next();
569
- });
570
-
571
- // Only process messages containing specific keywords
572
- api.useMiddleware("keywordFilter", (event, next) => {
573
- if (event.type === "message") {
574
- const keywords = ["help", "support", "info"];
575
- const hasKeyword = keywords.some(keyword =>
576
- event.body.toLowerCase().includes(keyword)
577
- );
578
- if (!hasKeyword) {
579
- return next(false); // Skip messages without keywords
580
- }
581
- }
582
- next();
583
- });
584
- ```
585
-
586
- **8. Remove Middleware:**
587
- ```javascript
588
- // Remove by name
589
- api.removeMiddleware("logger");
590
-
591
- // Remove by function reference
592
- const myMiddleware = (event, next) => { /* ... */ };
593
- api.useMiddleware("myMiddleware", myMiddleware);
594
- // Later...
595
- api.removeMiddleware(myMiddleware);
596
- ```
597
-
598
- **9. Complete Example - Bot with Multiple Middleware:**
599
- ```javascript
600
- const login = require("@dongdev/fca-unofficial");
601
-
602
- login({ appState: [] }, (err, api) => {
603
- if (err) return console.error(err);
604
-
605
- // 1. Logging middleware
606
- api.useMiddleware("logger", (event, next) => {
607
- if (event.type === "message") {
608
- console.log(`Message: ${event.body}`);
609
- }
610
- next();
611
- });
612
-
613
- // 2. Block spam users
614
- const spamUsers = ["100012345678901"];
615
- api.useMiddleware("spamFilter", (event, next) => {
616
- if (event.type === "message" && spamUsers.includes(event.senderID)) {
617
- return next(false);
618
- }
619
- next();
620
- });
621
-
622
- // 3. Auto-reply to greetings
623
- api.useMiddleware("autoReply", (event, next) => {
624
- if (event.type === "message") {
625
- const greetings = ["hi", "hello", "hey"];
626
- if (greetings.includes(event.body.toLowerCase())) {
627
- api.sendMessage("Hello! How can I help?", event.threadID);
628
- }
629
- }
630
- next();
631
- });
632
-
633
- // 4. Listen for messages (middleware will process them first)
634
- api.listenMqtt((err, event) => {
635
- if (err) return console.error(err);
636
-
637
- // This callback receives events AFTER middleware processing
638
- if (event.type === "message") {
639
- console.log("Received message:", event.body);
640
- }
641
- });
642
- });
643
- ```
644
-
645
- #### Middleware Execution Order:
646
- Middleware functions are executed in the order they are added. If a middleware calls `next(false)` or `next(null)`, the event will be blocked and not emitted to your callback.
647
-
648
- #### Notes:
649
- - Middleware only processes events, not errors (errors bypass middleware)
650
- - You can modify the event object in middleware (it will be passed to the next middleware and callback)
651
- - Middleware can be async (return a Promise)
652
- - Middleware can be enabled/disabled without removing them
653
- - The middleware system is persistent across reconnections
654
-
655
- ---
656
-
657
- ### 3.4. getUserInfo - Get User Information
658
-
659
- Get detailed information about one or more users.
660
-
661
- #### Syntax:
662
- ```javascript
663
- api.getUserInfo(userID, callback);
664
- ```
665
-
666
- #### Example:
667
-
668
- ```javascript
669
- // Get info for 1 user
670
- api.getUserInfo("100012345678901", (err, userInfo) => {
671
- if (err) {
672
- console.error(err);
673
- return;
674
- }
675
-
676
- console.log(userInfo);
677
- // {
678
- // "100012345678901": {
679
- // name: "John Doe",
680
- // firstName: "John",
681
- // vanity: "john.doe",
682
- // thumbSrc: "avatar_url",
683
- // profileUrl: "https://facebook.com/john.doe",
684
- // gender: "MALE", // MALE/FEMALE
685
- // type: "user",
686
- // isFriend: true,
687
- // isBirthday: false
688
- // }
689
- // }
690
- });
691
-
692
- // Get info for multiple users
693
- api.getUserInfo(["100012345678901", "100012345678902"], (err, userInfo) => {
694
- if (err) return console.error(err);
695
-
696
- for (let id in userInfo) {
697
- console.log(userInfo[id].name);
698
- }
699
- });
700
- ```
701
-
702
- #### Caching and Anti-Get-Info
703
-
704
- - `getUserInfo` uses GraphQL to fetch profiles and stores normalized data in the `User` table (see `src/database/userData.js`).
705
- - On each call:
706
- - The library first checks the DB for existing entries.
707
- - Missing or stale entries are fetched from Facebook and persisted back to SQLite.
708
- - If `antiGetInfo.AntiGetUserInfo` is set to `true` in `fca-config.json`, the implementation falls back to the legacy `/chat/user_info/` endpoint and logs a Horizon-style warning when spam/limits are detected.
709
-
710
- ---
711
-
712
- ### 3.4. Message Scheduler - Schedule Messages
713
-
714
- Schedule messages to be sent at a specific time in the future. Useful for reminders, scheduled announcements, and automated messages.
715
-
716
- #### Syntax:
717
- ```javascript
718
- // Schedule a message
719
- const id = api.scheduler.scheduleMessage(message, threadID, when, options);
720
-
721
- // Cancel a scheduled message
722
- api.scheduler.cancelScheduledMessage(id);
723
-
724
- // Get scheduled message info
725
- const scheduled = api.scheduler.getScheduledMessage(id);
726
-
727
- // List all scheduled messages
728
- const list = api.scheduler.listScheduledMessages();
729
-
730
- // Cancel all scheduled messages
731
- const count = api.scheduler.cancelAllScheduledMessages();
732
-
733
- // Get count of scheduled messages
734
- const count = api.scheduler.getScheduledCount();
735
- ```
736
-
737
- #### Parameters:
738
- - `message`: Message content (string or MessageObject)
739
- - `threadID`: Target thread ID(s) (string or array)
740
- - `when`: When to send - can be:
741
- - `Date` object
742
- - `number` (Unix timestamp in milliseconds)
743
- - `string` (ISO date string)
744
- - `options`: Optional object with:
745
- - `replyMessageID`: Message ID to reply to
746
- - `isGroup`: Whether it's a group chat
747
- - `callback`: Callback function when message is sent
748
-
749
- #### Examples:
750
-
751
- **1. Schedule message for specific time:**
752
- ```javascript
753
- // Schedule for 1 hour from now
754
- const oneHourLater = Date.now() + (60 * 60 * 1000);
755
- const id = api.scheduler.scheduleMessage(
756
- "This is a scheduled message!",
757
- "100012345678901",
758
- oneHourLater
759
- );
760
- console.log(`Message scheduled with ID: ${id}`);
761
- ```
762
-
763
- **2. Schedule using Date object:**
764
- ```javascript
765
- // Schedule for tomorrow at 9:00 AM
766
- const tomorrow = new Date();
767
- tomorrow.setDate(tomorrow.getDate() + 1);
768
- tomorrow.setHours(9, 0, 0, 0);
769
-
770
- const id = api.scheduler.scheduleMessage(
771
- "Good morning! ☀️",
772
- "100012345678901",
773
- tomorrow
774
- );
775
- ```
776
-
777
- **3. Schedule using ISO string:**
778
- ```javascript
779
- // Schedule for specific date/time
780
- const id = api.scheduler.scheduleMessage(
781
- "Meeting reminder!",
782
- "100012345678901",
783
- "2024-12-25T10:00:00Z"
784
- );
785
- ```
786
-
787
- **4. Schedule with options:**
788
- ```javascript
789
- const id = api.scheduler.scheduleMessage(
790
- "Reply to your message",
791
- "100012345678901",
792
- Date.now() + 30000, // 30 seconds from now
793
- {
794
- replyMessageID: "mid.xxx",
795
- isGroup: false,
796
- callback: (err) => {
797
- if (err) {
798
- console.error("Scheduled message failed:", err);
799
- } else {
800
- console.log("Scheduled message sent!");
801
- }
802
- }
803
- }
804
- );
805
- ```
806
-
807
- **5. Cancel scheduled message:**
808
- ```javascript
809
- const id = api.scheduler.scheduleMessage("Test", threadID, Date.now() + 60000);
810
-
811
- // Cancel it
812
- if (api.scheduler.cancelScheduledMessage(id)) {
813
- console.log("Message cancelled");
814
- } else {
815
- console.log("Message not found or already sent");
816
- }
817
- ```
818
-
819
- **6. List all scheduled messages:**
820
- ```javascript
821
- const scheduled = api.scheduler.listScheduledMessages();
822
-
823
- scheduled.forEach(msg => {
824
- const timeUntil = Math.round(msg.timeUntilSend / 1000 / 60); // minutes
825
- console.log(`ID: ${msg.id}, Sends in ${timeUntil} minutes`);
826
- });
827
- ```
828
-
829
- **7. Get scheduled message info:**
830
- ```javascript
831
- const scheduled = api.scheduler.getScheduledMessage(id);
832
- if (scheduled) {
833
- console.log("Message:", scheduled.message);
834
- console.log("Scheduled for:", new Date(scheduled.timestamp));
835
- console.log("Time until send:", scheduled.timeUntilSend, "ms");
836
- }
837
- ```
838
-
839
- **8. Complete example - Reminder bot:**
840
- ```javascript
841
- const login = require("@dongdev/fca-unofficial");
842
-
843
- login({ appState: [] }, (err, api) => {
844
- if (err) return console.error(err);
845
-
846
- api.listenMqtt((err, event) => {
847
- if (err) return console.error(err);
848
-
849
- if (event.type === "message" && event.body.startsWith("/remind")) {
850
- const args = event.body.split(" ");
851
- if (args.length < 3) {
852
- api.sendMessage("Usage: /remind <minutes> <message>", event.threadID);
853
- return;
854
- }
855
-
856
- const minutes = parseInt(args[1]);
857
- const message = args.slice(2).join(" ");
858
- const when = Date.now() + (minutes * 60 * 1000);
859
-
860
- const id = api.scheduler.scheduleMessage(
861
- message,
862
- event.threadID,
863
- when
864
- );
865
-
866
- api.sendMessage(
867
- `Reminder scheduled! I'll remind you in ${minutes} minutes.`,
868
- event.threadID
869
- );
870
- }
871
- });
872
- });
873
- ```
874
-
875
- #### Notes:
876
- - Scheduled messages are stored in memory and will be lost if the bot restarts
877
- - Messages are sent automatically at the scheduled time
878
- - You can cancel messages before they are sent
879
- - The scheduler automatically cleans up expired messages
880
-
881
- ---
882
-
883
- ### 3.5. Auto-save AppState
884
-
885
- Automatically save AppState to a file at regular intervals to prevent session loss.
886
-
887
- #### Syntax:
888
- ```javascript
889
- // Enable auto-save
890
- const disable = api.enableAutoSaveAppState(options);
891
-
892
- // Disable auto-save
893
- disable();
894
- ```
895
-
896
- #### Parameters:
897
- - `options`: Optional object with:
898
- - `filePath`: Path to save AppState file (default: "appstate.json")
899
- - `interval`: Save interval in milliseconds (default: 10 minutes)
900
- - `saveOnLogin`: Save immediately on login (default: true)
901
-
902
- #### Examples:
903
-
904
- **1. Basic auto-save:**
905
- ```javascript
906
- const login = require("@dongdev/fca-unofficial");
907
-
908
- login({ appState: [] }, (err, api) => {
909
- if (err) return console.error(err);
910
-
911
- // Enable auto-save (saves every 10 minutes by default)
912
- api.enableAutoSaveAppState();
913
- });
914
- ```
915
-
916
- **2. Custom file path and interval:**
917
- ```javascript
918
- // Save to custom location every 5 minutes
919
- const disable = api.enableAutoSaveAppState({
920
- filePath: "./data/appstate.json",
921
- interval: 5 * 60 * 1000, // 5 minutes
922
- saveOnLogin: true
923
- });
924
-
925
- // Later, disable it
926
- // disable();
927
- ```
928
-
929
- **3. Save only on login:**
930
- ```javascript
931
- // Save only once on login, not periodically
932
- const disable = api.enableAutoSaveAppState({
933
- interval: Infinity, // Never save periodically
934
- saveOnLogin: true
935
- });
936
- ```
937
-
938
- **4. Complete example:**
939
- ```javascript
940
- const fs = require("fs");
941
- const login = require("@dongdev/fca-unofficial");
942
-
943
- // Try to load existing AppState
944
- let appState = [];
945
- try {
946
- appState = JSON.parse(fs.readFileSync("appstate.json", "utf8"));
947
- } catch (e) {
948
- console.log("No existing AppState found");
949
- }
950
-
951
- login({ appState }, (err, api) => {
952
- if (err) return console.error(err);
953
-
954
- // Enable auto-save
955
- api.enableAutoSaveAppState({
956
- filePath: "appstate.json",
957
- interval: 10 * 60 * 1000, // 10 minutes
958
- saveOnLogin: true
959
- });
960
-
961
- console.log("Bot started with auto-save enabled!");
962
- });
963
- ```
964
-
965
- #### Notes:
966
- - AppState is saved automatically at the specified interval
967
- - Saves immediately on login if `saveOnLogin` is true
968
- - The save function checks if AppState is valid before saving
969
- - Multiple auto-save instances can be enabled with different settings
970
-
971
- ---
972
-
973
- ### 3.6. getThreadInfo - Get Thread Information
974
-
975
- Get information about conversation/group chat.
976
-
977
- #### Syntax:
978
- ```javascript
979
- api.getThreadInfo(threadID, callback);
980
- ```
981
-
982
- #### Example:
983
-
984
- ```javascript
985
- api.getThreadInfo("1234567890", (err, threadInfo) => {
986
- if (err) {
987
- console.error(err);
988
- return;
989
- }
990
-
991
- console.log("Group name:", threadInfo.threadName);
992
- console.log("Member count:", threadInfo.participantIDs.length);
993
- console.log("Members list:", threadInfo.participantIDs);
994
- console.log("Admins:", threadInfo.adminIDs);
995
- console.log("Nicknames:", threadInfo.nicknames);
996
- console.log("Chat color:", threadInfo.color);
997
- console.log("Emoji:", threadInfo.emoji);
998
- });
999
- ```
1000
-
1001
- #### Caching and Anti-Get-Info
1002
-
1003
- - `getThreadInfo` uses a GraphQL batch endpoint and caches responses in the `Thread` table (see `src/database/threadData.js`).
1004
- - Subsequent calls within a short time window may be served from SQLite to reduce pressure on Facebook endpoints.
1005
- - When Facebook signals spam/limits, a Horizon-style warning is logged and the error is surfaced to your callback/Promise.
1006
-
1007
- ---
1008
-
1009
- ### 3.5. changeThreadColor - Change Chat Color
1010
-
1011
- Change the color of conversation.
1012
-
1013
- #### Syntax:
1014
- ```javascript
1015
- api.changeThreadColor(color, threadID, callback);
1016
- ```
1017
-
1018
- #### Example:
1019
-
1020
- ```javascript
1021
- // Color can be:
1022
- // "#0084ff" (Messenger Blue)
1023
- // "#44bec7" (Teal Blue)
1024
- // "#ffc300" (Yellow)
1025
- // "#fa3c4c" (Red)
1026
- // "#d696bb" (Pink)
1027
- // "#6699cc" (Sky Blue)
1028
- // "#13cf13" (Green)
1029
- // "#ff7e29" (Orange)
1030
- // "#e68585" (Light Red)
1031
- // "#7646ff" (Purple)
1032
- // "#20cef5" (Cyan)
1033
- // or any hex color code
1034
-
1035
- api.changeThreadColor("#ffc300", "1234567890", (err) => {
1036
- if (err) {
1037
- console.error("Change color error:", err);
1038
- return;
1039
- }
1040
- console.log("Chat color changed successfully!");
1041
- });
1042
- ```
1043
-
1044
- ---
1045
-
1046
- ### 3.6. changeThreadEmoji - Change Group Emoji
1047
-
1048
- Change the default emoji of conversation.
1049
-
1050
- #### Syntax:
1051
- ```javascript
1052
- api.changeThreadEmoji(emoji, threadID, callback);
1053
- ```
1054
-
1055
- #### Example:
1056
-
1057
- ```javascript
1058
- api.changeThreadEmoji("👍", "1234567890", (err) => {
1059
- if (err) {
1060
- console.error("Change emoji error:", err);
1061
- return;
1062
- }
1063
- console.log("Emoji changed successfully!");
1064
- });
1065
- ```
1066
-
1067
- ---
1068
-
1069
- ### 3.7. setTitle - Change Group Name
1070
-
1071
- Change the name of group chat.
1072
-
1073
- #### Syntax:
1074
- ```javascript
1075
- api.setTitle(newTitle, threadID, callback);
1076
- ```
1077
-
1078
- #### Example:
1079
-
1080
- ```javascript
1081
- api.setTitle("New Chat Group", "1234567890", (err) => {
1082
- if (err) {
1083
- console.error("Change name error:", err);
1084
- return;
1085
- }
1086
- console.log("Group name changed successfully!");
1087
- });
1088
- ```
1089
-
1090
- ---
1091
-
1092
- ### 3.8. addUserToGroup - Add Member to Group
1093
-
1094
- Add user to group chat.
1095
-
1096
- #### Syntax:
1097
- ```javascript
1098
- api.addUserToGroup(userID, threadID, callback);
1099
- ```
1100
-
1101
- #### Example:
1102
-
1103
- ```javascript
1104
- // Add 1 person
1105
- api.addUserToGroup("100012345678901", "1234567890", (err) => {
1106
- if (err) {
1107
- console.error("Add user error:", err);
1108
- return;
1109
- }
1110
- console.log("Member added successfully!");
1111
- });
1112
-
1113
- // Add multiple people
1114
- api.addUserToGroup(["100012345678901", "100012345678902"], "1234567890", (err) => {
1115
- if (err) return console.error(err);
1116
- console.log("Multiple members added!");
1117
- });
1118
- ```
1119
-
1120
- ---
1121
-
1122
- ### 3.9. removeUserFromGroup - Remove Member from Group
1123
-
1124
- Remove user from group chat.
1125
-
1126
- #### Syntax:
1127
- ```javascript
1128
- api.removeUserFromGroup(userID, threadID, callback);
1129
- ```
1130
-
1131
- #### Example:
1132
-
1133
- ```javascript
1134
- api.removeUserFromGroup("100012345678901", "1234567890", (err) => {
1135
- if (err) {
1136
- console.error("Remove user error:", err);
1137
- return;
1138
- }
1139
- console.log("Member removed successfully!");
1140
- });
1141
- ```
1142
-
1143
- ---
1144
-
1145
- ### 3.10. changeNickname - Change Nickname
1146
-
1147
- Change user's nickname in group chat.
1148
-
1149
- #### Syntax:
1150
- ```javascript
1151
- api.changeNickname(nickname, threadID, userID, callback);
1152
- ```
1153
-
1154
- #### Example:
1155
-
1156
- ```javascript
1157
- api.changeNickname("Admin Bot", "1234567890", "100012345678901", (err) => {
1158
- if (err) {
1159
- console.error("Change nickname error:", err);
1160
- return;
1161
- }
1162
- console.log("Nickname changed successfully!");
1163
- });
1164
-
1165
- // Remove nickname (set to original name)
1166
- api.changeNickname("", "1234567890", "100012345678901", (err) => {
1167
- if (err) return console.error(err);
1168
- console.log("Nickname removed!");
1169
- });
1170
- ```
1171
-
1172
- ---
1173
-
1174
- ### 3.11. markAsRead - Mark as Read
1175
-
1176
- Mark message as read.
1177
-
1178
- #### Syntax:
1179
- ```javascript
1180
- api.markAsRead(threadID, callback);
1181
- ```
1182
-
1183
- #### Example:
1184
-
1185
- ```javascript
1186
- api.listenMqtt((err, event) => {
1187
- if (err) return console.error(err);
1188
-
1189
- if (event.type === "message") {
1190
- // Auto mark as read
1191
- api.markAsRead(event.threadID, (err) => {
1192
- if (err) console.error("Mark as read error:", err);
1193
- });
1194
- }
1195
- });
1196
- ```
1197
-
1198
- ---
1199
-
1200
- ### 3.12. markAsDelivered - Mark as Delivered
1201
-
1202
- Mark message as delivered.
1203
-
1204
- #### Syntax:
1205
- ```javascript
1206
- api.markAsDelivered(threadID, messageID, callback);
1207
- ```
1208
-
1209
- #### Example:
1210
-
1211
- ```javascript
1212
- api.markAsDelivered("1234567890", "mid.xxx", (err) => {
1213
- if (err) {
1214
- console.error("Mark as delivered error:", err);
1215
- return;
1216
- }
1217
- console.log("Marked as delivered!");
1218
- });
1219
- ```
1220
-
1221
- ---
1222
-
1223
- ### 3.13. markAsReadAll - Mark All as Read
1224
-
1225
- Mark all messages as read.
1226
-
1227
- #### Syntax:
1228
- ```javascript
1229
- api.markAsReadAll(callback);
1230
- ```
1231
-
1232
- #### Example:
1233
-
1234
- ```javascript
1235
- api.markAsReadAll((err) => {
1236
- if (err) {
1237
- console.error("Error:", err);
1238
- return;
1239
- }
1240
- console.log("All messages marked as read!");
1241
- });
1242
- ```
1243
-
1244
- ---
1245
-
1246
- ### 3.14. sendTypingIndicator - Show Typing Indicator
1247
-
1248
- Display "typing..." status in chat.
1249
-
1250
- #### Syntax:
1251
- ```javascript
1252
- api.sendTypingIndicator(threadID, callback);
1253
- ```
1254
-
1255
- #### Example:
1256
-
1257
- ```javascript
1258
- // Show typing
1259
- api.sendTypingIndicator("1234567890", (err) => {
1260
- if (err) return console.error(err);
1261
-
1262
- // After 3 seconds, send message
1263
- setTimeout(() => {
1264
- api.sendMessage("Hello!", "1234567890");
1265
- }, 3000);
1266
- });
1267
-
1268
- // Or stop typing indicator
1269
- api.sendTypingIndicator("1234567890", (err) => {
1270
- if (err) return console.error(err);
1271
- }, true); // 3rd parameter is true to turn off typing
1272
- ```
1273
-
1274
- ---
1275
-
1276
- ### 3.15. unsendMessage - Unsend Message
1277
-
1278
- Unsend/recall a sent message.
1279
-
1280
- #### Syntax:
1281
- ```javascript
1282
- api.unsendMessage(messageID, callback);
1283
- ```
1284
-
1285
- #### Example:
1286
-
1287
- ```javascript
1288
- api.sendMessage("This message will be deleted", "1234567890", (err, messageInfo) => {
1289
- if (err) return console.error(err);
1290
-
1291
- // Unsend after 5 seconds
1292
- setTimeout(() => {
1293
- api.unsendMessage(messageInfo.messageID, (err) => {
1294
- if (err) {
1295
- console.error("Unsend error:", err);
1296
- return;
1297
- }
1298
- console.log("Message unsent!");
1299
- });
1300
- }, 5000);
1301
- });
1302
- ```
1303
-
1304
- ---
1305
-
1306
- ### 3.16. createPoll - Create Poll
1307
-
1308
- Create poll in group chat.
1309
-
1310
- #### Syntax:
1311
- ```javascript
1312
- api.createPoll(title, threadID, options, callback);
1313
- ```
1314
-
1315
- #### Example:
1316
-
1317
- ```javascript
1318
- const title = "Choose travel destination?";
1319
- const options = {
1320
- "Da Lat": false, // false = allow multiple choices
1321
- "Nha Trang": false,
1322
- "Phu Quoc": false
1323
- };
1324
-
1325
- api.createPoll(title, "1234567890", options, (err, pollInfo) => {
1326
- if (err) {
1327
- console.error("Create poll error:", err);
1328
- return;
1329
- }
1330
- console.log("Poll created successfully!");
1331
- });
1332
- ```
1333
-
1334
- ---
1335
-
1336
- ### 3.17. handleMessageRequest - Handle Message Request
1337
-
1338
- Accept or decline message from stranger.
1339
-
1340
- #### Syntax:
1341
- ```javascript
1342
- api.handleMessageRequest(threadID, accept, callback);
1343
- ```
1344
-
1345
- #### Example:
1346
-
1347
- ```javascript
1348
- // Accept message
1349
- api.handleMessageRequest("1234567890", true, (err) => {
1350
- if (err) {
1351
- console.error("Error:", err);
1352
- return;
1353
- }
1354
- console.log("Message accepted!");
1355
- });
1356
-
1357
- // Decline message
1358
- api.handleMessageRequest("1234567890", false, (err) => {
1359
- if (err) return console.error(err);
1360
- console.log("Message declined!");
1361
- });
1362
- ```
1363
-
1364
- ---
1365
-
1366
- ### 3.18. muteThread - Mute Notifications
1367
-
1368
- Mute or unmute notifications for conversation.
1369
-
1370
- #### Syntax:
1371
- ```javascript
1372
- api.muteThread(threadID, muteSeconds, callback);
1373
- ```
1374
-
1375
- #### Example:
1376
-
1377
- ```javascript
1378
- // Mute for 1 hour (3600 seconds)
1379
- api.muteThread("1234567890", 3600, (err) => {
1380
- if (err) {
1381
- console.error("Error:", err);
1382
- return;
1383
- }
1384
- console.log("Muted for 1 hour!");
1385
- });
1386
-
1387
- // Mute permanently
1388
- api.muteThread("1234567890", -1, (err) => {
1389
- if (err) return console.error(err);
1390
- console.log("Muted permanently!");
1391
- });
1392
-
1393
- // Unmute
1394
- api.muteThread("1234567890", 0, (err) => {
1395
- if (err) return console.error(err);
1396
- console.log("Unmuted!");
1397
- });
1398
- ```
1399
-
1400
- ---
1401
-
1402
- ### 3.19. getThreadList - Get Thread List
1403
-
1404
- Get list of conversations.
1405
-
1406
- #### Syntax:
1407
- ```javascript
1408
- api.getThreadList(limit, timestamp, tags, callback);
1409
- ```
1410
-
1411
- #### Example:
1412
-
1413
- ```javascript
1414
- // Get 20 most recent conversations
1415
- api.getThreadList(20, null, ["INBOX"], (err, threads) => {
1416
- if (err) {
1417
- console.error("Error:", err);
1418
- return;
1419
- }
1420
-
1421
- threads.forEach(thread => {
1422
- console.log("Thread ID:", thread.threadID);
1423
- console.log("Name:", thread.name);
1424
- console.log("Unread count:", thread.unreadCount);
1425
- console.log("Last message:", thread.snippet);
1426
- console.log("---");
1427
- });
1428
- });
1429
-
1430
- // Tags can be:
1431
- // - "INBOX" : Inbox
1432
- // - "ARCHIVED" : Archived
1433
- // - "PENDING" : Pending messages
1434
- // - "OTHER" : Other
1435
- ```
1436
-
1437
- ---
1438
-
1439
- ### 3.20. getThreadHistory - Get Message History
1440
-
1441
- Get message history of conversation.
1442
-
1443
- #### Syntax:
1444
- ```javascript
1445
- api.getThreadHistory(threadID, amount, timestamp, callback);
1446
- ```
1447
-
1448
- #### Example:
1449
-
1450
- ```javascript
1451
- // Get 50 most recent messages
1452
- api.getThreadHistory("1234567890", 50, null, (err, history) => {
1453
- if (err) {
1454
- console.error("Error:", err);
1455
- return;
1456
- }
1457
-
1458
- history.forEach(msg => {
1459
- console.log("From:", msg.senderName);
1460
- console.log("Content:", msg.body);
1461
- console.log("Time:", new Date(msg.timestamp));
1462
- console.log("---");
1463
- });
1464
- });
1465
-
1466
- // Get older messages (pagination)
1467
- const oldestTimestamp = history[history.length - 1].timestamp;
1468
- api.getThreadHistory("1234567890", 50, oldestTimestamp, (err, olderHistory) => {
1469
- if (err) return console.error(err);
1470
- console.log("Retrieved 50 older messages!");
1471
- });
1472
- ```
1473
-
1474
- ---
1475
-
1476
- ### 3.21. getThreadPictures - Get Thread Pictures
1477
-
1478
- Get conversation/group avatar URL.
1479
-
1480
- #### Syntax:
1481
- ```javascript
1482
- api.getThreadPictures(threadID, offset, limit, callback);
1483
- ```
1484
-
1485
- #### Example:
1486
-
1487
- ```javascript
1488
- api.getThreadPictures("1234567890", 0, 10, (err, pictures) => {
1489
- if (err) {
1490
- console.error("Error:", err);
1491
- return;
1492
- }
1493
-
1494
- pictures.forEach(pic => {
1495
- console.log("Image URL:", pic.url);
1496
- console.log("Width:", pic.width);
1497
- console.log("Height:", pic.height);
1498
- });
1499
- });
1500
- ```
1501
-
1502
- ---
1503
-
1504
- ### 3.22. getUserID - Get User ID
1505
-
1506
- Get User ID from username or profile URL.
1507
-
1508
- #### Syntax:
1509
- ```javascript
1510
- api.getUserID(name, callback);
1511
- ```
1512
-
1513
- #### Example:
1514
-
1515
- ```javascript
1516
- // From username
1517
- api.getUserID("john.doe", (err, data) => {
1518
- if (err) {
1519
- console.error("Error:", err);
1520
- return;
1521
- }
1522
- console.log("User ID:", data.userID);
1523
- });
1524
-
1525
- // From profile URL
1526
- api.getUserID("https://facebook.com/john.doe", (err, data) => {
1527
- if (err) return console.error(err);
1528
- console.log("User ID:", data.userID);
1529
- });
1530
- ```
1531
-
1532
- ---
1533
-
1534
- ### 3.23. getAppState - Get Current AppState
1535
-
1536
- Get current AppState (cookies, session).
1537
-
1538
- #### Syntax:
1539
- ```javascript
1540
- const appState = api.getAppState();
1541
- ```
1542
-
1543
- #### Example:
1544
-
1545
- ```javascript
1546
- const fs = require("fs");
1547
-
1548
- // Get and save AppState
1549
- const appState = api.getAppState();
1550
- fs.writeFileSync("appstate.json", JSON.stringify(appState, null, 2));
1551
- console.log("✅ AppState saved!");
1552
-
1553
- // Periodically update AppState (every 10 minutes)
1554
- setInterval(() => {
1555
- const updatedAppState = api.getAppState();
1556
- fs.writeFileSync("appstate.json", JSON.stringify(updatedAppState, null, 2));
1557
- console.log("🔄 AppState updated");
1558
- }, 10 * 60 * 1000);
1559
- ```
1560
-
1561
- ---
1562
-
1563
- ### 3.24. deleteMessage - Delete Message (from your side)
1564
-
1565
- Delete message from your side (not unsend).
1566
-
1567
- #### Syntax:
1568
- ```javascript
1569
- api.deleteMessage(messageID, callback);
1570
- ```
1571
-
1572
- #### Example:
1573
-
1574
- ```javascript
1575
- api.deleteMessage("mid.xxx", (err) => {
1576
- if (err) {
1577
- console.error("Delete message error:", err);
1578
- return;
1579
- }
1580
- console.log("Message deleted!");
1581
- });
1582
- ```
1583
-
1584
- ---
1585
-
1586
- ### 3.25. deleteThread - Delete Thread
1587
-
1588
- Delete conversation from your list.
1589
-
1590
- #### Syntax:
1591
- ```javascript
1592
- api.deleteThread(threadID, callback);
1593
- ```
1594
-
1595
- #### Example:
1596
-
1597
- ```javascript
1598
- api.deleteThread("1234567890", (err) => {
1599
- if (err) {
1600
- console.error("Delete thread error:", err);
1601
- return;
1602
- }
1603
- console.log("Thread deleted!");
1604
- });
1605
- ```
1606
-
1607
- ---
1608
-
1609
- ### 3.26. forwardAttachment - Forward Attachment
1610
-
1611
- Forward attachment from one message to another.
1612
-
1613
- #### Syntax:
1614
- ```javascript
1615
- api.forwardAttachment(attachmentID, userOrThreadID, callback);
1616
- ```
1617
-
1618
- #### Example:
1619
-
1620
- ```javascript
1621
- api.listenMqtt((err, event) => {
1622
- if (err) return console.error(err);
1623
-
1624
- if (event.type === "message" && event.attachments.length > 0) {
1625
- // Forward first attachment
1626
- const attachmentID = event.attachments[0].ID;
1627
-
1628
- api.forwardAttachment(attachmentID, "100012345678901", (err) => {
1629
- if (err) {
1630
- console.error("Forward error:", err);
1631
- return;
1632
- }
1633
- console.log("Attachment forwarded!");
1634
- });
1635
- }
1636
- });
1637
- ```
1638
-
1639
- ---
1640
-
1641
- ### 3.27. setMessageReaction - React to Message
1642
-
1643
- Add reaction (like, love, haha, wow, sad, angry) to message.
1644
-
1645
- #### Syntax:
1646
- ```javascript
1647
- api.setMessageReaction(reaction, messageID, threadID, callback, forceCustomReaction);
1648
- ```
1649
-
1650
- #### Example:
1651
-
1652
- ```javascript
1653
- // Reaction can be:
1654
- // "👍" or ":like:" - Like
1655
- // "❤️" or ":love:" - Love
1656
- // "😂" or ":haha:" - Haha
1657
- // "😮" or ":wow:" - Wow
1658
- // "😢" or ":sad:" - Sad
1659
- // "😠" or ":angry:" - Angry
1660
- // "" (empty string) - Remove reaction
1661
-
1662
- api.listenMqtt((err, event) => {
1663
- if (err) return console.error(err);
1664
-
1665
- if (event.type === "message" && event.body === "React me") {
1666
- api.setMessageReaction("❤️", event.messageID, event.threadID, (err) => {
1667
- if (err) {
1668
- console.error("React error:", err);
1669
- return;
1670
- }
1671
- console.log("Message reacted!");
1672
- });
1673
- }
1674
- });
1675
-
1676
- // Remove reaction
1677
- api.setMessageReaction("", "mid.xxx", "1234567890", (err) => {
1678
- if (err) return console.error(err);
1679
- console.log("Reaction removed!");
1680
- });
1681
- ```
1682
-
1683
- ---
1684
-
1685
- ### 3.28. searchForThread - Search for Thread
1686
-
1687
- Search for conversation by name.
1688
-
1689
- #### Syntax:
1690
- ```javascript
1691
- api.searchForThread(name, callback);
1692
- ```
1693
-
1694
- #### Example:
1695
-
1696
- ```javascript
1697
- api.searchForThread("Study Group", (err, threads) => {
1698
- if (err) {
1699
- console.error("Search error:", err);
1700
- return;
1701
- }
1702
-
1703
- threads.forEach(thread => {
1704
- console.log("Name:", thread.name);
1705
- console.log("Thread ID:", thread.threadID);
1706
- console.log("Type:", thread.isGroup ? "Group" : "Personal");
1707
- console.log("---");
1708
- });
1709
- });
1710
- ```
1711
-
1712
- ---
1713
-
1714
- ### 3.29. logout - Logout
1715
-
1716
- Logout from Facebook account.
1717
-
1718
- #### Syntax:
1719
- ```javascript
1720
- api.logout(callback);
1721
- ```
1722
-
1723
- #### Example:
1724
-
1725
- ```javascript
1726
- api.logout((err) => {
1727
- if (err) {
1728
- console.error("Logout error:", err);
1729
- return;
1730
- }
1731
- console.log("Logged out successfully!");
1732
- });
1733
- ```
1734
-
1735
- ---
1736
-
1737
- ### 3.30. getCurrentUserID - Get Current User ID
1738
-
1739
- Get User ID of currently logged in account.
1740
-
1741
- #### Syntax:
1742
- ```javascript
1743
- const myUserID = api.getCurrentUserID();
1744
- ```
1745
-
1746
- #### Example:
1747
-
1748
- ```javascript
1749
- const myUserID = api.getCurrentUserID();
1750
- console.log("Bot's User ID:", myUserID);
1751
-
1752
- // Use to check if message is from bot
1753
- api.listenMqtt((err, event) => {
1754
- if (err) return console.error(err);
1755
-
1756
- if (event.type === "message") {
1757
- if (event.senderID === myUserID) {
1758
- console.log("This is a message from bot!");
1759
- } else {
1760
- console.log("Message from someone else");
1761
- }
1762
- }
1763
- });
1764
- ```
1765
-
1766
- ---
1767
-
1768
- ### 3.31. resolvePhotoUrl - Get High Quality Photo URL
1769
-
1770
- Get high resolution photo URL from photo ID.
1771
-
1772
- #### Syntax:
1773
- ```javascript
1774
- api.resolvePhotoUrl(photoID, callback);
1775
- ```
1776
-
1777
- #### Example:
1778
-
1779
- ```javascript
1780
- api.resolvePhotoUrl("1234567890123456", (err, url) => {
1781
- if (err) {
1782
- console.error("Error:", err);
1783
- return;
1784
- }
1785
- console.log("High quality image URL:", url);
1786
- });
1787
- ```
1788
-
1789
- ---
1790
-
1791
- ### 3.32. changeArchivedStatus - Archive/Unarchive Thread
1792
-
1793
- Archive or unarchive conversation.
1794
-
1795
- #### Syntax:
1796
- ```javascript
1797
- api.changeArchivedStatus(threadID, archive, callback);
1798
- ```
1799
-
1800
- #### Example:
1801
-
1802
- ```javascript
1803
- // Archive conversation
1804
- api.changeArchivedStatus("1234567890", true, (err) => {
1805
- if (err) {
1806
- console.error("Error:", err);
1807
- return;
1808
- }
1809
- console.log("Thread archived!");
1810
- });
1811
-
1812
- // Unarchive
1813
- api.changeArchivedStatus("1234567890", false, (err) => {
1814
- if (err) return console.error(err);
1815
- console.log("Thread unarchived!");
1816
- });
1817
- ```
1818
-
1819
- ---
1820
-
1821
- ### 3.33. changeBlockedStatus - Block/Unblock User
1822
-
1823
- Block or unblock user.
1824
-
1825
- #### Syntax:
1826
- ```javascript
1827
- api.changeBlockedStatus(userID, block, callback);
1828
- ```
1829
-
1830
- #### Example:
1831
-
1832
- ```javascript
1833
- // Block user
1834
- api.changeBlockedStatus("100012345678901", true, (err) => {
1835
- if (err) {
1836
- console.error("Error:", err);
1837
- return;
1838
- }
1839
- console.log("User blocked!");
1840
- });
1841
-
1842
- // Unblock
1843
- api.changeBlockedStatus("100012345678901", false, (err) => {
1844
- if (err) return console.error(err);
1845
- console.log("User unblocked!");
1846
- });
1847
- ```
1848
-
1849
- ---
1850
-
1851
- ### 3.34. createNewGroup - Create New Group
1852
-
1853
- Create new group chat with member list.
1854
-
1855
- #### Syntax:
1856
- ```javascript
1857
- api.createNewGroup(participantIDs, groupTitle, callback);
1858
- ```
1859
-
1860
- #### Example:
1861
-
1862
- ```javascript
1863
- const members = ["100012345678901", "100012345678902", "100012345678903"];
1864
- const groupName = "New Chat Group";
1865
-
1866
- api.createNewGroup(members, groupName, (err, threadID) => {
1867
- if (err) {
1868
- console.error("Create group error:", err);
1869
- return;
1870
- }
1871
- console.log("Group created successfully!");
1872
- console.log("Thread ID:", threadID);
1873
-
1874
- // Send message to new group
1875
- api.sendMessage("Welcome to the group!", threadID);
1876
- });
1877
- ```
1878
-
1879
- ---
1880
-
1881
- ## 4. COMPLETE BOT EXAMPLES
1882
-
1883
- ### 4.1. Echo Bot (Message Repeater)
1884
-
1885
- ```javascript
1886
- const fs = require("fs");
1887
- const login = require("@dongdev/fca-unofficial");
1888
-
1889
- // Login
1890
- login(
1891
- { appState: JSON.parse(fs.readFileSync("appstate.json", "utf8")) },
1892
- (err, api) => {
1893
- if (err) {
1894
- console.error("Login error:", err);
1895
- return;
1896
- }
1897
-
1898
- console.log("✅ Bot started!");
1899
-
1900
- // Configuration
1901
- api.setOptions({
1902
- listenEvents: true,
1903
- selfListen: false,
1904
- logLevel: "silent"
1905
- });
1906
-
1907
- // Listen for messages
1908
- api.listenMqtt((err, event) => {
1909
- if (err) return console.error(err);
1910
-
1911
- if (event.type === "message") {
1912
- const { body, threadID, messageID, senderID } = event;
1913
-
1914
- // Stop bot command
1915
- if (body === "/stop") {
1916
- api.sendMessage("Bot stopped!", threadID);
1917
- process.exit(0);
1918
- }
1919
-
1920
- // Echo message
1921
- api.sendMessage(`📣 Echo: ${body}`, threadID, messageID);
1922
- }
1923
- });
1924
- }
1925
- );
1926
- ```
1927
-
1928
- ---
1929
-
1930
- ### 4.2. Group Management Bot
1931
-
1932
- ```javascript
1933
- const fs = require("fs");
1934
- const login = require("@dongdev/fca-unofficial");
1935
-
1936
- // Admin list (User IDs)
1937
- const ADMINS = ["100012345678901", "100012345678902"];
1938
-
1939
- // Check admin permission
1940
- function isAdmin(userID) {
1941
- return ADMINS.includes(userID);
1942
- }
1943
-
1944
- login(
1945
- { appState: JSON.parse(fs.readFileSync("appstate.json", "utf8")) },
1946
- (err, api) => {
1947
- if (err) return console.error(err);
1948
-
1949
- console.log("✅ Group management bot started!");
1950
-
1951
- api.setOptions({ listenEvents: true });
1952
-
1953
- api.listenMqtt((err, event) => {
1954
- if (err) return console.error(err);
1955
-
1956
- const { type, threadID, senderID, body, messageID } = event;
1957
-
1958
- // Handle messages
1959
- if (type === "message") {
1960
- // Only admins can use commands
1961
- if (!isAdmin(senderID)) {
1962
- if (body.startsWith("/")) {
1963
- api.sendMessage(
1964
- "❌ You don't have permission to use this command!",
1965
- threadID,
1966
- messageID
1967
- );
1968
- }
1969
- return;
1970
- }
1971
-
1972
- // Kick command
1973
- if (body.startsWith("/kick ")) {
1974
- const userID = body.split(" ")[1];
1975
- api.removeUserFromGroup(userID, threadID, (err) => {
1976
- if (err) {
1977
- api.sendMessage("❌ Error kicking user!", threadID);
1978
- } else {
1979
- api.sendMessage("✅ User kicked!", threadID);
1980
- }
1981
- });
1982
- }
1983
-
1984
- // Rename command
1985
- else if (body.startsWith("/rename ")) {
1986
- const newName = body.substring(8);
1987
- api.setTitle(newName, threadID, (err) => {
1988
- if (err) {
1989
- api.sendMessage("❌ Error renaming group!", threadID);
1990
- } else {
1991
- api.sendMessage(`✅ Group renamed to: ${newName}`, threadID);
1992
- }
1993
- });
1994
- }
1995
-
1996
- // Group info command
1997
- else if (body === "/info") {
1998
- api.getThreadInfo(threadID, (err, info) => {
1999
- if (err) return api.sendMessage("❌ Error getting info!", threadID);
2000
-
2001
- const message = `
2002
- 📊 GROUP INFORMATION
2003
- ━━━━━━━━━━━━━━━
2004
- 👥 Name: ${info.threadName}
2005
- 📝 Members: ${info.participantIDs.length}
2006
- 👑 Admins: ${info.adminIDs.length}
2007
- 🎨 Color: ${info.color}
2008
- 😊 Emoji: ${info.emoji || "Default"}
2009
- `.trim();
2010
-
2011
- api.sendMessage(message, threadID);
2012
- });
2013
- }
2014
-
2015
- // Help command
2016
- else if (body === "/help") {
2017
- const helpMessage = `
2018
- 🤖 COMMAND LIST
2019
- ━━━━━━━━━━━━━━━
2020
- /kick [userID] - Kick member
2021
- /rename [new name] - Rename group
2022
- /info - View group info
2023
- /help - Show help
2024
- `.trim();
2025
-
2026
- api.sendMessage(helpMessage, threadID);
2027
- }
2028
- }
2029
-
2030
- // Handle events
2031
- else if (type === "event") {
2032
- // Welcome new members
2033
- if (event.logMessageType === "log:subscribe") {
2034
- const addedUsers = event.logMessageData.addedParticipants;
2035
- addedUsers.forEach(user => {
2036
- api.sendMessage(
2037
- `👋 Welcome ${user.fullName} to the group!`,
2038
- threadID
2039
- );
2040
- });
2041
- }
2042
-
2043
- // Notify when someone leaves
2044
- else if (event.logMessageType === "log:unsubscribe") {
2045
- api.sendMessage(`👋 Goodbye! A member left the group.`, threadID);
2046
- }
2047
- }
2048
- });
2049
- }
2050
- );
2051
- ```
2052
-
2053
- ---
2054
-
2055
- ### 4.3. AI ChatBot Style (Mock)
2056
-
2057
- ```javascript
2058
- const fs = require("fs");
2059
- const login = require("@dongdev/fca-unofficial");
2060
-
2061
- // Store chat history by threadID
2062
- const chatHistory = {};
2063
-
2064
- // Mock AI response function
2065
- function getAIResponse(message, threadID) {
2066
- // Initialize history if not exists
2067
- if (!chatHistory[threadID]) {
2068
- chatHistory[threadID] = [];
2069
- }
2070
-
2071
- // Add user message to history
2072
- chatHistory[threadID].push({ role: "user", content: message });
2073
-
2074
- // Limit history to last 10 messages
2075
- if (chatHistory[threadID].length > 10) {
2076
- chatHistory[threadID] = chatHistory[threadID].slice(-10);
2077
- }
2078
-
2079
- // Mock response (you can integrate real ChatGPT API here)
2080
- let response = "";
2081
-
2082
- if (message.toLowerCase().includes("hello")) {
2083
- response = "Hello! How can I help you?";
2084
- } else if (message.toLowerCase().includes("name")) {
2085
- response = "I'm an AI Assistant Bot!";
2086
- } else if (message.toLowerCase().includes("weather")) {
2087
- response = "Sorry, I don't have weather information. Please check weather apps!";
2088
- } else {
2089
- response = `I received your message: "${message}". Thank you for chatting with me!`;
2090
- }
2091
-
2092
- // Add response to history
2093
- chatHistory[threadID].push({ role: "assistant", content: response });
2094
-
2095
- return response;
2096
- }
2097
-
2098
- login(
2099
- { appState: JSON.parse(fs.readFileSync("appstate.json", "utf8")) },
2100
- (err, api) => {
2101
- if (err) return console.error(err);
2102
-
2103
- console.log("✅ AI Bot started!");
2104
-
2105
- api.setOptions({
2106
- listenEvents: true,
2107
- selfListen: false
2108
- });
2109
-
2110
- api.listenMqtt((err, event) => {
2111
- if (err) return console.error(err);
2112
-
2113
- if (event.type === "message" && event.body) {
2114
- const { body, threadID, messageID } = event;
2115
-
2116
- // Ignore if doesn't start with "ai" prefix
2117
- if (!body.toLowerCase().startsWith("ai ")) {
2118
- return;
2119
- }
2120
-
2121
- // Get message content (remove "ai " prefix)
2122
- const userMessage = body.substring(3).trim();
2123
-
2124
- // Show typing indicator
2125
- api.sendTypingIndicator(threadID);
2126
-
2127
- // Delay for more natural feel
2128
- setTimeout(() => {
2129
- const aiResponse = getAIResponse(userMessage, threadID);
2130
- api.sendMessage(`🤖 ${aiResponse}`, threadID, messageID);
2131
- }, 1500);
2132
- }
2133
- });
2134
- }
2135
- );
2136
- ```
2137
-
2138
- ---
2139
-
2140
- ### 4.4. Auto-Reply Bot with Keywords
2141
-
2142
- ```javascript
2143
- const fs = require("fs");
2144
- const login = require("@dongdev/fca-unofficial");
2145
-
2146
- // Auto-reply dictionary
2147
- const autoReplies = {
2148
- "hello": "Hi there! How can I help you?",
2149
- "hi": "Hello! What's up?",
2150
- "bye": "Goodbye! See you later!",
2151
- "thanks": "You're welcome! 😊",
2152
- "help": "I'm here to assist! Just ask me anything.",
2153
- "time": () => `Current time: ${new Date().toLocaleTimeString()}`,
2154
- "date": () => `Today's date: ${new Date().toLocaleDateString()}`
2155
- };
2156
-
2157
- function getAutoReply(message) {
2158
- const lowerMessage = message.toLowerCase().trim();
2159
-
2160
- // Check for exact matches
2161
- for (let keyword in autoReplies) {
2162
- if (lowerMessage.includes(keyword)) {
2163
- const reply = autoReplies[keyword];
2164
- // If reply is function, execute it
2165
- return typeof reply === 'function' ? reply() : reply;
2166
- }
2167
- }
2168
-
2169
- return null; // No match found
2170
- }
2171
-
2172
- login(
2173
- { appState: JSON.parse(fs.readFileSync("appstate.json", "utf8")) },
2174
- (err, api) => {
2175
- if (err) return console.error(err);
2176
-
2177
- console.log("✅ Auto-reply bot started!");
2178
-
2179
- api.setOptions({
2180
- listenEvents: true,
2181
- selfListen: false
2182
- });
2183
-
2184
- api.listenMqtt((err, event) => {
2185
- if (err) return console.error(err);
2186
-
2187
- if (event.type === "message" && event.body) {
2188
- const { body, threadID, messageID } = event;
2189
-
2190
- const reply = getAutoReply(body);
2191
-
2192
- if (reply) {
2193
- api.sendMessage(reply, threadID, messageID);
2194
- }
2195
- }
2196
- });
2197
- }
2198
- );
2199
- ```
2200
-
2201
- ---
2202
-
2203
- ### 4.5. Command Handler Bot
2204
-
2205
- ```javascript
2206
- const fs = require("fs");
2207
- const login = require("@dongdev/fca-unofficial");
2208
-
2209
- // Command prefix
2210
- const PREFIX = "/";
2211
-
2212
- // Commands object
2213
- const commands = {
2214
- ping: {
2215
- description: "Check bot latency",
2216
- execute: (api, event) => {
2217
- const start = Date.now();
2218
- api.sendMessage("Pong! 🏓", event.threadID, (err) => {
2219
- if (!err) {
2220
- const latency = Date.now() - start;
2221
- api.sendMessage(`Latency: ${latency}ms`, event.threadID);
2222
- }
2223
- });
2224
- }
2225
- },
2226
-
2227
- userinfo: {
2228
- description: "Get user information",
2229
- execute: (api, event) => {
2230
- api.getUserInfo(event.senderID, (err, userInfo) => {
2231
- if (err) return api.sendMessage("Error getting user info!", event.threadID);
2232
-
2233
- const user = userInfo[event.senderID];
2234
- const info = `
2235
- 👤 USER INFO
2236
- ━━━━━━━━━━━━
2237
- Name: ${user.name}
2238
- Gender: ${user.gender}
2239
- Profile: ${user.profileUrl}
2240
- `.trim();
2241
-
2242
- api.sendMessage(info, event.threadID);
2243
- });
2244
- }
2245
- },
2246
-
2247
- time: {
2248
- description: "Get current time",
2249
- execute: (api, event) => {
2250
- const now = new Date();
2251
- api.sendMessage(`🕐 Current time: ${now.toLocaleString()}`, event.threadID);
2252
- }
2253
- },
2254
-
2255
- help: {
2256
- description: "Show command list",
2257
- execute: (api, event) => {
2258
- let helpText = "📋 AVAILABLE COMMANDS\n━━━━━━━━━━━━━━━\n";
2259
-
2260
- for (let cmd in commands) {
2261
- helpText += `${PREFIX}${cmd} - ${commands[cmd].description}\n`;
2262
- }
2263
-
2264
- api.sendMessage(helpText, event.threadID);
2265
- }
2266
- }
2267
- };
2268
-
2269
- login(
2270
- { appState: JSON.parse(fs.readFileSync("appstate.json", "utf8")) },
2271
- (err, api) => {
2272
- if (err) return console.error(err);
2273
-
2274
- console.log("✅ Command handler bot started!");
2275
-
2276
- api.setOptions({ listenEvents: true, selfListen: false });
2277
-
2278
- api.listenMqtt((err, event) => {
2279
- if (err) return console.error(err);
2280
-
2281
- if (event.type === "message" && event.body) {
2282
- const { body, threadID } = event;
2283
-
2284
- // Check if message starts with prefix
2285
- if (!body.startsWith(PREFIX)) return;
2286
-
2287
- // Parse command
2288
- const args = body.slice(PREFIX.length).trim().split(/ +/);
2289
- const commandName = args.shift().toLowerCase();
2290
-
2291
- // Execute command
2292
- if (commands[commandName]) {
2293
- try {
2294
- commands[commandName].execute(api, event, args);
2295
- } catch (error) {
2296
- console.error("Command execution error:", error);
2297
- api.sendMessage("Error executing command!", threadID);
2298
- }
2299
- } else {
2300
- api.sendMessage(`Unknown command: ${commandName}\nUse ${PREFIX}help for command list`, threadID);
2301
- }
2302
- }
2303
- });
2304
- }
2305
- );
2306
- ```
2307
-
2308
- ---
2309
-
2310
- ## 5. ERROR HANDLING & BEST PRACTICES
2311
-
2312
- ### 5.1. Handle Checkpoint/Security Check
2313
-
2314
- When Facebook detects unusual activity, account may be checkpointed:
2315
-
2316
- ```javascript
2317
- login(credentials, (err, api) => {
2318
- if (err) {
2319
- switch (err.error) {
2320
- case "login-approval":
2321
- console.log("❗ 2FA code required");
2322
- // Handle 2FA
2323
- break;
2324
-
2325
- case "checkpoint":
2326
- console.log("❌ Account checkpointed!");
2327
- console.log("Please login via browser and verify");
2328
- break;
2329
-
2330
- default:
2331
- console.error("Login error:", err);
2332
- }
2333
- return;
2334
- }
2335
- });
2336
- ```
2337
-
2338
- ---
2339
-
2340
- ### 5.2. Auto-save AppState
2341
-
2342
- ```javascript
2343
- // Save AppState every 10 minutes
2344
- setInterval(() => {
2345
- try {
2346
- const appState = api.getAppState();
2347
- fs.writeFileSync("appstate.json", JSON.stringify(appState, null, 2));
2348
- console.log("🔄 AppState updated");
2349
- } catch (error) {
2350
- console.error("Error saving AppState:", error);
2351
- }
2352
- }, 10 * 60 * 1000);
2353
- ```
2354
-
2355
- ---
2356
-
2357
- ### 5.3. Connection Error Handling
2358
-
2359
- ```javascript
2360
- api.listenMqtt((err, event) => {
2361
- if (err) {
2362
- console.error("Listen error:", err);
2363
-
2364
- // Retry connection after 5 seconds
2365
- setTimeout(() => {
2366
- console.log("🔄 Reconnecting...");
2367
- api.listenMqtt(arguments.callee);
2368
- }, 5000);
2369
- return;
2370
- }
2371
-
2372
- // Handle events normally
2373
- });
2374
- ```
2375
-
2376
- ---
2377
-
2378
- ### 5.4. Rate Limiting (Avoid Spam)
2379
-
2380
- ```javascript
2381
- const MESSAGE_COOLDOWN = {}; // Store last message time
2382
-
2383
- function canSendMessage(threadID, cooldownTime = 1000) {
2384
- const now = Date.now();
2385
- const lastTime = MESSAGE_COOLDOWN[threadID] || 0;
2386
-
2387
- if (now - lastTime < cooldownTime) {
2388
- return false;
2389
- }
2390
-
2391
- MESSAGE_COOLDOWN[threadID] = now;
2392
- return true;
2393
- }
2394
-
2395
- api.listenMqtt((err, event) => {
2396
- if (err) return console.error(err);
2397
-
2398
- if (event.type === "message") {
2399
- // Check cooldown
2400
- if (!canSendMessage(event.threadID, 2000)) {
2401
- console.log("⏱️ On cooldown...");
2402
- return;
2403
- }
2404
-
2405
- // Handle message
2406
- api.sendMessage("Response", event.threadID);
2407
- }
2408
- });
2409
- ```
2410
-
2411
- ---
2412
-
2413
- ### 5.5. Logging and Debug
2414
-
2415
- ```javascript
2416
- // Enable detailed logging
2417
- api.setOptions({
2418
- logLevel: "verbose" // silent/error/warn/info/verbose
2419
- });
2420
-
2421
- // Custom logger
2422
- function log(type, message, data = {}) {
2423
- const timestamp = new Date().toISOString();
2424
- console.log(`[${timestamp}] [${type.toUpperCase()}] ${message}`, data);
2425
- }
2426
-
2427
- api.listenMqtt((err, event) => {
2428
- if (err) {
2429
- log("error", "Listen error", err);
2430
- return;
2431
- }
2432
-
2433
- log("info", "New event", {
2434
- type: event.type,
2435
- threadID: event.threadID
2436
- });
2437
- });
2438
- ```
2439
-
2440
- ---
2441
-
2442
- ### 5.6. Environment Variables for Credentials
2443
-
2444
- ```javascript
2445
- require('dotenv').config();
2446
-
2447
- const credentials = {
2448
- email: process.env.FB_EMAIL,
2449
- password: process.env.FB_PASSWORD
2450
- };
2451
-
2452
- // Or use AppState
2453
- const credentials = {
2454
- appState: JSON.parse(fs.readFileSync(process.env.APPSTATE_PATH, "utf8"))
2455
- };
2456
- ```
2457
-
2458
- **.env file:**
2459
- ```
2460
- FB_EMAIL=your_email@example.com
2461
- FB_PASSWORD=your_password
2462
- APPSTATE_PATH=./appstate.json
2463
- ```
2464
-
2465
- ---
2466
-
2467
- ## 6. IMPORTANT NOTES
2468
-
2469
- ### ⚠️ Security Warnings
2470
-
2471
- 1. **Never share AppState**: The `appstate.json` file contains login information, never make it public
2472
- 2. **Use .gitignore**: Add `appstate.json` to `.gitignore`
2473
- 3. **Avoid hardcoding passwords**: Use environment variables or config files
2474
- 4. **Keep dependencies updated**: Regularly update the package
2475
-
2476
- ### 📝 Best Practices
2477
-
2478
- 1. **Use AppState instead of email/password**: Reduces checkpoint risk
2479
- 2. **Don't spam**: Avoid sending too many messages in short time
2480
- 3. **Complete error handling**: Always have callbacks to handle errors
2481
- 4. **Rate limiting**: Limit number of messages/requests
2482
- 5. **Log activities**: Keep logs for debugging
2483
-
2484
- ### 🚫 Avoid Getting Banned
2485
-
2486
- - Don't login/logout repeatedly
2487
- - Don't mass message strangers
2488
- - Don't send spam links
2489
- - Use real browser User-Agent
2490
- - Limit requests per minute
2491
- - Be a responsible Facebook citizen
2492
-
2493
- ---
2494
-
2495
- ## 7. TROUBLESHOOTING
2496
-
2497
- ### Error: "Wrong username/password"
2498
- - Check email and password
2499
- - Try logging in manually via browser
2500
- - Account may be checkpointed
2501
-
2502
- ### Error: "Login approval needed"
2503
- - Account has 2FA enabled
2504
- - Provide 2FA verification code
2505
-
2506
- ### Error: "Checkpoint required"
2507
- - Login to Facebook via browser
2508
- - Complete verification steps
2509
- - Get new AppState after verification
2510
-
2511
- ### Bot not receiving messages
2512
- - Check internet connection
2513
- - Check logs for detailed errors
2514
- - Try restarting bot
2515
- - Update AppState
2516
-
2517
- ### Messages sending too slowly
2518
- - Implement message queue
2519
- - Use rate limiting
2520
- - Check network latency
2521
-
2522
- ---
2523
-
2524
- ## 8. ADVANCED FEATURES
2525
-
2526
- ### 8.1. Message Queue System
2527
-
2528
- ```javascript
2529
- class MessageQueue {
2530
- constructor(api) {
2531
- this.api = api;
2532
- this.queue = [];
2533
- this.processing = false;
2534
- this.delay = 1000; // 1 second delay between messages
2535
- }
2536
-
2537
- add(message, threadID, messageID) {
2538
- this.queue.push({ message, threadID, messageID });
2539
- if (!this.processing) {
2540
- this.process();
2541
- }
2542
- }
2543
-
2544
- async process() {
2545
- this.processing = true;
2546
-
2547
- while (this.queue.length > 0) {
2548
- const { message, threadID, messageID } = this.queue.shift();
2549
-
2550
- await new Promise((resolve) => {
2551
- this.api.sendMessage(message, threadID, messageID, (err) => {
2552
- if (err) console.error("Send error:", err);
2553
- setTimeout(resolve, this.delay);
2554
- });
2555
- });
2556
- }
2557
-
2558
- this.processing = false;
2559
- }
2560
- }
2561
-
2562
- // Usage
2563
- const messageQueue = new MessageQueue(api);
2564
-
2565
- api.listenMqtt((err, event) => {
2566
- if (err) return console.error(err);
2567
-
2568
- if (event.type === "message") {
2569
- messageQueue.add("Response", event.threadID, event.messageID);
2570
- }
2571
- });
2572
- ```
2573
-
2574
- ---
2575
-
2576
- ### 8.2. Multi-Account Bot Manager
2577
-
2578
- ```javascript
2579
- const fs = require("fs");
2580
- const login = require("@dongdev/fca-unofficial");
2581
-
2582
- class BotManager {
2583
- constructor() {
2584
- this.bots = new Map();
2585
- }
2586
-
2587
- async addBot(name, appStatePath) {
2588
- return new Promise((resolve, reject) => {
2589
- const credentials = {
2590
- appState: JSON.parse(fs.readFileSync(appStatePath, "utf8"))
2591
- };
2592
-
2593
- login(credentials, (err, api) => {
2594
- if (err) {
2595
- reject(err);
2596
- return;
2597
- }
2598
-
2599
- this.bots.set(name, api);
2600
- console.log(`✅ Bot "${name}" connected`);
2601
- resolve(api);
2602
- });
2603
- });
2604
- }
2605
-
2606
- getBot(name) {
2607
- return this.bots.get(name);
2608
- }
2609
-
2610
- getAllBots() {
2611
- return Array.from(this.bots.values());
2612
- }
2613
- }
2614
-
2615
- // Usage
2616
- const manager = new BotManager();
2617
-
2618
- (async () => {
2619
- await manager.addBot("bot1", "./appstate1.json");
2620
- await manager.addBot("bot2", "./appstate2.json");
2621
-
2622
- const bot1 = manager.getBot("bot1");
2623
- const bot2 = manager.getBot("bot2");
2624
-
2625
- // Use bots independently
2626
- bot1.sendMessage("Message from Bot 1", threadID);
2627
- bot2.sendMessage("Message from Bot 2", threadID);
2628
- })();
2629
- ```
2630
-
2631
- ---
2632
-
2633
- ### 8.3. Database Integration (SQLite Example)
2634
-
2635
- ```javascript
2636
- const sqlite3 = require('sqlite3').verbose();
2637
- const db = new sqlite3.Database('./bot.db');
2638
-
2639
- // Initialize database
2640
- db.serialize(() => {
2641
- db.run(`CREATE TABLE IF NOT EXISTS users (
2642
- user_id TEXT PRIMARY KEY,
2643
- username TEXT,
2644
- message_count INTEGER DEFAULT 0,
2645
- last_interaction TEXT
2646
- )`);
2647
- });
2648
-
2649
- // Track user messages
2650
- function trackUser(userID, username) {
2651
- db.run(`
2652
- INSERT INTO users (user_id, username, message_count, last_interaction)
2653
- VALUES (?, ?, 1, datetime('now'))
2654
- ON CONFLICT(user_id) DO UPDATE SET
2655
- message_count = message_count + 1,
2656
- last_interaction = datetime('now')
2657
- `, [userID, username]);
2658
- }
2659
-
2660
- // Get user stats
2661
- function getUserStats(userID, callback) {
2662
- db.get('SELECT * FROM users WHERE user_id = ?', [userID], callback);
2663
- }
2664
-
2665
- // Usage in bot
2666
- api.listenMqtt((err, event) => {
2667
- if (err) return console.error(err);
2668
-
2669
- if (event.type === "message") {
2670
- // Track user
2671
- api.getUserInfo(event.senderID, (err, info) => {
2672
- if (!err) {
2673
- const username = info[event.senderID].name;
2674
- trackUser(event.senderID, username);
2675
- }
2676
- });
2677
-
2678
- // Stats command
2679
- if (event.body === "/stats") {
2680
- getUserStats(event.senderID, (err, row) => {
2681
- if (err || !row) return;
2682
-
2683
- const stats = `
2684
- 📊 YOUR STATS
2685
- ━━━━━━━━━━━━
2686
- Messages: ${row.message_count}
2687
- Last seen: ${row.last_interaction}
2688
- `.trim();
2689
-
2690
- api.sendMessage(stats, event.threadID);
2691
- });
2692
- }
2693
- }
2694
- });
2695
- ```
2696
-
2697
- ---
2698
-
2699
- ## 9. RESOURCES
2700
-
2701
- - **GitHub Repository**: https://github.com/Donix-VN/fca-unofficial
2702
- - **NPM Package**: @dongdev/fca-unofficial
2703
- - **AppState Tool**: https://github.com/c3cbot/c3c-fbstate
2704
- - **Facebook Developer Docs**: https://developers.facebook.com/docs/messenger-platform
2705
-
2706
- ---
2707
-
2708
- ## Conclusion
2709
-
2710
- This is a comprehensive documentation for **@dongdev/fca-unofficial** API methods. This library is very powerful but should be used carefully to avoid violating Facebook's policies and getting your account banned.
2711
-
2712
- **Happy bot coding! 🚀**