@dongdev/fca-unofficial 2.0.12 → 2.0.14

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.
package/CHANGELOG.md CHANGED
@@ -71,3 +71,9 @@ Too lazy to write changelog, sorry! (will write changelog in the next release, t
71
71
 
72
72
  ## v2.0.11 - 2025-10-07
73
73
  - Hotfix / auto bump
74
+
75
+ ## v2.0.12 - 2025-10-07
76
+ - Hotfix / auto bump
77
+
78
+ ## v2.0.13 - 2025-10-07
79
+ - Hotfix / auto bump
package/README.md CHANGED
@@ -8,6 +8,7 @@
8
8
  ## ⚠️ Important Disclaimer
9
9
 
10
10
  **We are not responsible if your account gets banned for spammy activities such as:**
11
+
11
12
  - Sending lots of messages to people you don't know
12
13
  - Sending messages very quickly
13
14
  - Sending spammy looking URLs
@@ -15,13 +16,14 @@
15
16
 
16
17
  **Recommendation:** Use Firefox browser or [this website](https://fca.dongdev.id.vn) to reduce logout issues, especially for iOS users.
17
18
 
18
- **Support:** If you encounter errors, contact us [here](https://www.facebook.com/minhdong.dev)
19
+ **Support:** If you encounter errors, contact us [here](https://www.facebook.com/mdong.dev)
19
20
 
20
21
  ## 🔍 Introduction
21
22
 
22
23
  Facebook now has an [official API for chat bots](https://developers.facebook.com/docs/messenger-platform), however it's only available for Facebook Pages.
23
24
 
24
25
  `@dongdev/fca-unofficial` is the only API that allows you to automate chat functionalities on a **user account** by emulating the browser. This means:
26
+
25
27
  - Making the exact same GET/POST requests as a browser
26
28
  - Does not work with auth tokens
27
29
  - Requires Facebook account credentials (email/password) or AppState
@@ -109,13 +111,13 @@ login({ appState: [] }, (err, api) => {
109
111
 
110
112
  ## 📝 Message Types
111
113
 
112
- | Type | Usage |
113
- | ---------------- | --------------------------------------------------------------- |
114
+ | Type | Usage |
115
+ | ---------------------- | ----------------------------------------------------------------- |
114
116
  | **Regular text** | `{ body: "message text" }` |
115
117
  | **Sticker** | `{ sticker: "sticker_id" }` |
116
118
  | **File/Image** | `{ attachment: fs.createReadStream(path) }` or array of streams |
117
119
  | **URL** | `{ url: "https://example.com" }` |
118
- | **Large emoji** | `{ emoji: "👍", emojiSize: "large" }` (small/medium/large) |
120
+ | **Large emoji** | `{ emoji: "👍", emojiSize: "large" }` (small/medium/large) |
119
121
 
120
122
  **Note:** 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.
121
123
 
@@ -228,6 +230,7 @@ api.setOptions({
228
230
  ```
229
231
 
230
232
  **By default:**
233
+
231
234
  - `listenEvents` is `false` - won't receive events like joining/leaving chat, title changes
232
235
  - `selfListen` is `false` - will ignore messages sent by the current account
233
236
 
@@ -252,6 +255,7 @@ api.setOptions({
252
255
  ## 📚 Full API Documentation
253
256
 
254
257
  See [DOCS.md](./DOCS.md) for detailed information about:
258
+
255
259
  - All available API methods
256
260
  - Parameters and options
257
261
  - Event types
@@ -291,6 +295,7 @@ api.setMessageReaction(reaction, messageID, callback);
291
295
  ## 🤝 Contributing
292
296
 
293
297
  Contributions are welcome! Please:
298
+
294
299
  1. Fork the repository
295
300
  2. Create a new branch (`git checkout -b feature/AmazingFeature`)
296
301
  3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
@@ -1,3 +1,4 @@
1
+ // func/checkUpdate.js
1
2
  const logger = require("./logger");
2
3
  const fs = require("fs");
3
4
  const { exec } = require("child_process");
@@ -21,38 +22,41 @@ function getInstalledVersion() {
21
22
  }
22
23
  }
23
24
 
24
- async function checkAndUpdateVersion(callback) {
25
- try {
26
- logger("Checking version...", "info");
27
- const latest = (await execPromise(`npm view ${pkgName} version`)).stdout.trim();
28
- const installed = getInstalledVersion();
29
- if (!installed || installed !== latest) {
30
- logger(`New version available (${latest}). Current version (${installed || "not installed"}). Updating...`, "info");
25
+ async function _checkAndUpdateVersionImpl() {
26
+ logger("Checking version...", "info");
27
+ const latest = (await execPromise(`npm view ${pkgName} version`)).stdout.trim();
28
+ const installed = getInstalledVersion();
29
+ if (!installed || installed !== latest) {
30
+ logger(`New version available (${latest}). Current version (${installed || "not installed"}). Updating...`, "info");
31
+ try {
32
+ const { stderr } = await execPromise(`npm i ${pkgName}@latest`);
33
+ if (stderr) logger(stderr, "error");
34
+ logger(`Updated fca to the latest version: ${latest}, Restart to apply`, "info");
35
+ process.exit(1);
36
+ } catch (e) {
37
+ logger(`Error running npm install: ${e.error || e}. Trying to install from GitHub...`, "error");
31
38
  try {
32
- const { stderr } = await execPromise(`npm i ${pkgName}@latest`);
39
+ const { stderr } = await execPromise("npm i https://github.com/Donix-VN/fca-unofficial");
33
40
  if (stderr) logger(stderr, "error");
34
- logger(`Updated fca to the latest version: ${latest}, Restart to apply`, "info");
35
- callback(null);
36
- } catch (e) {
37
- logger(`Error running npm install: ${e.error || e}. Trying to install from GitHub...`, "error");
38
- try {
39
- const { stderr } = await execPromise("npm i https://github.com/Donix-VN/fca-unofficial");
40
- if (stderr) logger(stderr, "error");
41
- logger(`Installed from GitHub successfully: ${latest}`, "info");
42
- callback(null);
43
- } catch (gitErr) {
44
- logger(`Error installing from GitHub: ${gitErr.error || gitErr}`, "error");
45
- callback(gitErr.error || gitErr);
46
- }
41
+ logger(`Installed from GitHub successfully: ${latest}`, "info");
42
+ return;
43
+ } catch (gitErr) {
44
+ logger(`Error installing from GitHub: ${gitErr.error || gitErr}`, "error");
45
+ throw (gitErr.error || gitErr);
47
46
  }
48
- } else {
49
- logger(`You're already on the latest version - ${latest}`, "info");
50
- callback(null);
51
47
  }
52
- } catch (err) {
53
- logger(`Error checking version: ${err}`, "error");
54
- callback(err);
48
+ } else {
49
+ logger(`You're already on the latest version - ${latest}`, "info");
50
+ return;
51
+ }
52
+ }
53
+
54
+ function checkAndUpdateVersion(callback) {
55
+ if (typeof callback === "function") {
56
+ _checkAndUpdateVersionImpl().then(() => callback(null)).catch(err => callback(err));
57
+ return;
55
58
  }
59
+ return _checkAndUpdateVersionImpl();
56
60
  }
57
61
 
58
- module.exports.checkAndUpdateVersion = checkAndUpdateVersion;
62
+ module.exports = { checkAndUpdateVersion };
package/module/login.js CHANGED
@@ -1,11 +1,11 @@
1
- "use strict";
2
1
  const { getType } = require("../src/utils/format");
3
2
  const { setOptions } = require("./options");
4
3
  const { loadConfig } = require("./config");
4
+ const { checkAndUpdateVersion } = require("../func/checkUpdate");
5
+ const loginHelper = require("./loginHelper");
6
+
5
7
  const { config } = loadConfig();
6
- if (config.autoUpdate) require("../func/checkUpdate").checkAndUpdateVersion(() => {});
7
8
  global.fca = { config };
8
- const loginHelper = require("./loginHelper");
9
9
 
10
10
  function login(loginData, options, callback) {
11
11
  if (getType(options) === "Function" || getType(options) === "AsyncFunction") {
@@ -28,10 +28,11 @@ function login(loginData, options, callback) {
28
28
  };
29
29
  setOptions(globalOptions, options);
30
30
  let prCallback = null;
31
+ let rejectFunc = null;
32
+ let resolveFunc = null;
33
+ let returnPromise = null;
31
34
  if (getType(callback) !== "Function" && getType(callback) !== "AsyncFunction") {
32
- let rejectFunc = null;
33
- let resolveFunc = null;
34
- var returnPromise = new Promise(function (resolve, reject) {
35
+ returnPromise = new Promise(function (resolve, reject) {
35
36
  resolveFunc = resolve;
36
37
  rejectFunc = reject;
37
38
  });
@@ -41,7 +42,18 @@ function login(loginData, options, callback) {
41
42
  };
42
43
  callback = prCallback;
43
44
  }
44
- loginHelper(loginData.appState, loginData.Cookie,loginData.email, loginData.password, globalOptions, callback, prCallback);
45
+ const proceed = () => loginHelper(loginData.appState, loginData.Cookie, loginData.email, loginData.password, globalOptions, callback, prCallback);
46
+ if (config && config.autoUpdate) {
47
+ const p = checkAndUpdateVersion();
48
+ if (p && typeof p.then === "function") {
49
+ p.then(proceed).catch(err => callback(err));
50
+ } else {
51
+ proceed();
52
+ }
53
+ } else {
54
+ proceed();
55
+ }
45
56
  return returnPromise;
46
57
  }
58
+
47
59
  module.exports = login;
@@ -127,6 +127,35 @@ const genTotp = async secret => {
127
127
  return typeof r === "object" ? r.otp : r;
128
128
  };
129
129
 
130
+ function normalizeCookieHeaderString(s) {
131
+ let str = String(s || "").trim();
132
+ if (!str) return [];
133
+ if (/^cookie\s*:/i.test(str)) str = str.replace(/^cookie\s*:/i, "").trim();
134
+ str = str.replace(/\r?\n/g, " ").replace(/\s*;\s*/g, ";");
135
+ const parts = str.split(";").map(v => v.trim()).filter(Boolean);
136
+ const out = [];
137
+ for (const p of parts) {
138
+ const eq = p.indexOf("=");
139
+ if (eq <= 0) continue;
140
+ const k = p.slice(0, eq).trim();
141
+ const v = p.slice(eq + 1).trim().replace(/^"(.*)"$/, "$1");
142
+ if (!k) continue;
143
+ out.push(`${k}=${v}`);
144
+ }
145
+ return out;
146
+ }
147
+
148
+ function setJarFromPairs(j, pairs, domain) {
149
+ const expires = new Date(Date.now() + 31536e6).toUTCString();
150
+ for (const kv of pairs) {
151
+ const cookieStr = `${kv}; expires=${expires}; domain=${domain}; path=/;`;
152
+ try {
153
+ if (typeof j.setCookieSync === "function") j.setCookieSync(cookieStr, "https://www.facebook.com");
154
+ else j.setCookie(cookieStr, "https://www.facebook.com");
155
+ } catch { }
156
+ }
157
+ }
158
+
130
159
  function cookieHeaderFromJar(j) {
131
160
  const urls = ["https://www.facebook.com", "https://www.messenger.com"];
132
161
  const seen = new Set();
@@ -135,7 +164,7 @@ function cookieHeaderFromJar(j) {
135
164
  let s = "";
136
165
  try {
137
166
  s = typeof j.getCookieStringSync === "function" ? j.getCookieStringSync(u) : "";
138
- } catch {}
167
+ } catch { }
139
168
  if (!s) continue;
140
169
  for (const kv of s.split(";")) {
141
170
  const t = kv.trim();
@@ -174,7 +203,7 @@ async function ensureUniqueIndex(sequelize) {
174
203
  if (uniqueIndexEnsured) return;
175
204
  try {
176
205
  await sequelize.getQueryInterface().addIndex("app_state_backups", ["userID", "type"], { unique: true, name: "app_state_user_type_unique" });
177
- } catch {}
206
+ } catch { }
178
207
  uniqueIndexEnsured = true;
179
208
  }
180
209
 
@@ -231,7 +260,7 @@ async function getLatestBackupAny(type) {
231
260
  async function tokens(username, password, twofactor = null) {
232
261
  const t0 = process.hrtime.bigint();
233
262
  if (!username || !password) {
234
- logger("Missing email or password", {}, "error");
263
+ logger("Missing email or password", "error");
235
264
  return { status: false, message: "Please provide email and password" };
236
265
  }
237
266
  logger(`AUTO-LOGIN: Initialize login ${mask(username, 2)}`, "info");
@@ -263,13 +292,13 @@ async function tokens(username, password, twofactor = null) {
263
292
  if (code) logger(`AUTO-LOGIN: Error on request #1 ${code} ${message}`, "warn");
264
293
  logger("AUTO-LOGIN: Processing twofactor...", "info");
265
294
  if (code === 401) return { status: false, message: message || "Unauthorized" };
266
- if (twofactor === "0" || !twofactor) {
267
- logger("AUTO-LOGIN: 2FA required but secret missing", {}, "warn");
295
+ if (!config.credentials?.twofactor) {
296
+ logger("AUTO-LOGIN: 2FA required but secret missing", "warn");
268
297
  return { status: false, message: "Please provide the 2FA secret!" };
269
298
  }
270
299
  try {
271
300
  const dataErr = e && e.data && e.data.error && e.data.error.error_data ? e.data.error.error_data : {};
272
- const codeTotp = await genTotp(twofactor);
301
+ const codeTotp = await genTotp(config.credentials.twofactor);
273
302
  logger(`AUTO-LOGIN: Performing 2FA ${mask(codeTotp, 2)}`, "info");
274
303
  const form2 = { ...baseForm, twofactor_code: codeTotp, encrypted_msisdn: "", userid: dataErr.uid || "", machine_id: dataErr.machine_id || baseForm.machine_id, first_factor: dataErr.login_first_factor || "", credentials_type: "two_factor" };
275
304
  form2.sig = encodeSig(sortObject(form2));
@@ -284,58 +313,12 @@ async function tokens(username, password, twofactor = null) {
284
313
  logger(`AUTO-LOGIN: Done success login with 2FA ${Math.round(t1)}ms`, "info");
285
314
  return { status: true, cookies };
286
315
  } catch {
287
- logger("AUTO-LOGIN: 2FA failed", {}, "error");
316
+ logger("AUTO-LOGIN: 2FA failed", "error");
288
317
  return { status: false, message: "Invalid two-factor code!" };
289
318
  }
290
319
  }
291
320
  }
292
321
 
293
- function normalizeCookieHeaderString(s) {
294
- let str = String(s || "").trim();
295
- if (!str) return [];
296
- if (/^cookie\s*:/i.test(str)) str = str.replace(/^cookie\s*:/i, "").trim();
297
- str = str.replace(/\r?\n/g, " ").replace(/\s*;\s*/g, ";");
298
- const parts = str.split(";").map(v => v.trim()).filter(Boolean);
299
- const out = [];
300
- for (const p of parts) {
301
- const eq = p.indexOf("=");
302
- if (eq <= 0) continue;
303
- const k = p.slice(0, eq).trim();
304
- const v = p.slice(eq + 1).trim().replace(/^"(.*)"$/, "$1");
305
- if (!k) continue;
306
- out.push(`${k}=${v}`);
307
- }
308
- return out;
309
- }
310
-
311
- function setJarFromPairs(j, pairs, domain) {
312
- const expires = new Date(Date.now() + 31536e6).toUTCString();
313
- for (const kv of pairs) {
314
- const cookieStr = `${kv}; expires=${expires}; domain=${domain}; path=/;`;
315
- try {
316
- if (typeof j.setCookieSync === "function") j.setCookieSync(cookieStr, "https://www.facebook.com");
317
- else j.setCookie(cookieStr, "https://www.facebook.com");
318
- } catch {}
319
- }
320
- }
321
-
322
- function makeLogin(j, email, password, globalOptions, callback, prCallback) {
323
- return async function () {
324
- const u = email || config.credentials.email;
325
- const p = password || config.credentials.password;
326
- const tf = config.credentials.twofactor || null;
327
- if (!u || !p) return;
328
- const r = await tokens(u, p, tf);
329
- if (r && r.status && Array.isArray(r.cookies)) {
330
- const pairs = r.cookies.map(c => `${c.key || c.name}=${c.value}`);
331
- setJarFromPairs(j, pairs, ".facebook.com");
332
- await get("https://www.facebook.com/", j, null, globalOptions).then(saveCookies(j));
333
- } else {
334
- throw new Error(r && r.message ? r.message : "Login failed");
335
- }
336
- };
337
- }
338
-
339
322
  async function hydrateJarFromDB(userID) {
340
323
  try {
341
324
  let ck = null;
@@ -358,7 +341,7 @@ async function hydrateJarFromDB(userID) {
358
341
  let parsed = null;
359
342
  try {
360
343
  parsed = JSON.parse(app);
361
- } catch {}
344
+ } catch { }
362
345
  if (Array.isArray(parsed)) {
363
346
  const pairs = parsed.map(c => [c.name || c.key, c.value].join("="));
364
347
  setJarFromPairs(jar, pairs, ".facebook.com");
@@ -377,10 +360,8 @@ async function tryAutoLoginIfNeeded(currentHtml, currentCookies, globalOptions)
377
360
  cs.find(c => c.key === "c_user")?.value ||
378
361
  cs.find(c => c.name === "i_user")?.value ||
379
362
  cs.find(c => c.name === "c_user")?.value;
380
-
381
363
  let userID = getUID(currentCookies);
382
364
  if (userID) return { html: currentHtml, cookies: currentCookies, userID };
383
-
384
365
  const hydrated = await hydrateJarFromDB(null);
385
366
  if (hydrated) {
386
367
  logger("AppState backup live — proceeding to login", "info");
@@ -391,12 +372,11 @@ async function tryAutoLoginIfNeeded(currentHtml, currentCookies, globalOptions)
391
372
  const uidB = getUID(cookiesB);
392
373
  if (uidB) return { html: htmlB, cookies: cookiesB, userID: uidB };
393
374
  }
394
-
395
375
  if (config.autoLogin !== true) throw new Error("AppState backup die — Auto-login is disabled");
396
376
  logger("AppState backup die — proceeding to email/password login", "warn");
397
- const u = config.credentials.email;
398
- const p = config.credentials.password;
399
- const tf = config.credentials.twofactor || null;
377
+ const u = config.credentials?.email;
378
+ const p = config.credentials?.password;
379
+ const tf = config.credentials?.twofactor || null;
400
380
  if (!u || !p) throw new Error("Missing user cookie");
401
381
  const r = await tokens(u, p, tf);
402
382
  if (!(r && r.status && Array.isArray(r.cookies))) throw new Error(r && r.message ? r.message : "Login failed");
@@ -411,9 +391,25 @@ async function tryAutoLoginIfNeeded(currentHtml, currentCookies, globalOptions)
411
391
  return { html: html2, cookies: cookies2, userID: uid2 };
412
392
  }
413
393
 
414
- function loginHelper(appState, Cookie, email, password, globalOptions, callback, prCallback) {
394
+ function makeLogin(j, email, password, globalOptions) {
395
+ return async function () {
396
+ const u = email || config.credentials?.email;
397
+ const p = password || config.credentials?.password;
398
+ const tf = config.credentials?.twofactor || null;
399
+ if (!u || !p) return;
400
+ const r = await tokens(u, p, tf);
401
+ if (r && r.status && Array.isArray(r.cookies)) {
402
+ const pairs = r.cookies.map(c => `${c.key || c.name}=${c.value}`);
403
+ setJarFromPairs(j, pairs, ".facebook.com");
404
+ await get("https://www.facebook.com/", j, null, globalOptions).then(saveCookies(j));
405
+ } else {
406
+ throw new Error(r && r.message ? r.message : "Login failed");
407
+ }
408
+ };
409
+ }
410
+
411
+ function loginHelper(appState, Cookie, email, password, globalOptions, callback) {
415
412
  try {
416
- let main;
417
413
  const domain = ".facebook.com";
418
414
  try {
419
415
  if (appState) {
@@ -421,7 +417,7 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
421
417
  let parsed = appState;
422
418
  try {
423
419
  parsed = JSON.parse(appState);
424
- } catch {}
420
+ } catch { }
425
421
  if (Array.isArray(parsed)) {
426
422
  const pairs = parsed.map(c => [c.name || c.key, c.value].join("="));
427
423
  setJarFromPairs(jar, pairs, domain);
@@ -449,7 +445,6 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
449
445
  } catch (e) {
450
446
  return callback(e);
451
447
  }
452
-
453
448
  (async () => {
454
449
  if (appState || Cookie) {
455
450
  return get("https://www.facebook.com/", jar, null, globalOptions).then(saveCookies(jar));
@@ -462,7 +457,7 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
462
457
  logger("AppState backup die — proceeding to email/password login", "warn");
463
458
  return get("https://www.facebook.com/", null, null, globalOptions)
464
459
  .then(saveCookies(jar))
465
- .then(makeLogin(jar, email, password, globalOptions, callback, prCallback))
460
+ .then(makeLogin(jar, email, password, globalOptions))
466
461
  .then(function () {
467
462
  return get("https://www.facebook.com/", jar, null, globalOptions).then(saveCookies(jar));
468
463
  });
@@ -475,34 +470,20 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
475
470
  cookies.find(c => c.key === "c_user")?.value ||
476
471
  cookies.find(c => c.name === "i_user")?.value ||
477
472
  cookies.find(c => c.name === "c_user")?.value;
478
-
479
- try {
480
- const userDataMatch = String(html).match(/\["CurrentUserInitialData",\[\],({.*?}),\d+\]/);
481
- if (userDataMatch) {
482
- const info = JSON.parse(userDataMatch[1]);
483
- logger(`Đăng nhập tài khoản: ${info.NAME} (${info.USER_ID})`, "info");
484
- } else if (userID) {
485
- logger(`ID người dùng: ${userID}`, "info");
486
- }
487
- } catch {}
488
-
489
473
  if (!userID) {
490
474
  const retried = await tryAutoLoginIfNeeded(html, cookies, globalOptions);
491
475
  html = retried.html;
492
476
  cookies = retried.cookies;
493
477
  userID = retried.userID;
494
478
  }
495
-
496
479
  if (html.includes("/checkpoint/block/?next")) {
497
480
  logger("Appstate die, vui lòng thay cái mới!", "error");
498
481
  throw new Error("Checkpoint");
499
482
  }
500
-
501
483
  let mqttEndpoint;
502
484
  let region = "PRN";
503
485
  let fb_dtsg;
504
486
  let irisSeqID;
505
-
506
487
  try {
507
488
  const m1 = html.match(/"endpoint":"([^"]+)"/);
508
489
  const m2 = m1 ? null : html.match(/endpoint\\":\\"([^\\"]+)\\"/);
@@ -526,11 +507,9 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
526
507
  } catch { }
527
508
  const tokenMatch = html.match(/DTSGInitialData.*?token":"(.*?)"/);
528
509
  if (tokenMatch) fb_dtsg = tokenMatch[1];
529
-
530
510
  try {
531
511
  if (userID) await backupAppStateSQL(jar, userID);
532
- } catch {}
533
-
512
+ } catch { }
534
513
  Promise.resolve()
535
514
  .then(function () {
536
515
  if (models && models.sequelize && typeof models.sequelize.authenticate === "function") {
@@ -546,9 +525,7 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
546
525
  console.error(error);
547
526
  console.error("Database connection failed:", error && error.message ? error.message : String(error));
548
527
  });
549
-
550
528
  logger("FCA fix/update by DongDev (Donix-VN)", "info");
551
-
552
529
  const ctx = {
553
530
  userID,
554
531
  jar,
@@ -566,9 +543,25 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
566
543
  clientID: ((Math.random() * 2147483648) | 0).toString(16),
567
544
  clientId: getFrom(html, '["MqttWebDeviceID",[],{"clientID":"', '"}') || "",
568
545
  wsReqNumber: 0,
569
- wsTaskNumber: 0
546
+ wsTaskNumber: 0,
547
+ tasks: new Map()
548
+ };
549
+ ctx.performAutoLogin = async () => {
550
+ try {
551
+ const u = config.credentials?.email || email;
552
+ const p = config.credentials?.password || password;
553
+ const tf = config.credentials?.twofactor || null;
554
+ if (!u || !p) return false;
555
+ const r = await tokens(u, p, tf);
556
+ if (!(r && r.status && Array.isArray(r.cookies))) return false;
557
+ const pairs = r.cookies.map(c => `${c.key || c.name}=${c.value}`);
558
+ setJarFromPairs(jar, pairs, ".facebook.com");
559
+ await get("https://www.facebook.com/", jar, null, globalOptions).then(saveCookies(jar));
560
+ return true;
561
+ } catch {
562
+ return false;
563
+ }
570
564
  };
571
-
572
565
  const api = {
573
566
  setOptions: require("./options").setOptions.bind(null, globalOptions),
574
567
  getCookies: function () {
@@ -585,7 +578,6 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
585
578
  return await getLatestBackup(uid, "cookie");
586
579
  }
587
580
  };
588
-
589
581
  const defaultFuncs = makeDefaults(html, userID, ctx);
590
582
  const srcRoot = path.join(__dirname, "../src/api");
591
583
  let loaded = 0;
@@ -605,23 +597,18 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
605
597
  loaded++;
606
598
  });
607
599
  });
608
-
609
600
  logger(`Loaded ${loaded} FCA API methods${skipped ? `, skipped ${skipped} duplicates` : ""}`);
610
-
611
- api.listen = api.listenMqtt;
612
-
613
- setInterval(function () {
614
- api
615
- .refreshFb_dtsg()
616
- .then(function () {
617
- logger("Successfully refreshed fb_dtsg", "[ FCA-UNO ] >");
618
- })
619
- .catch(function () {
601
+ if (api.listenMqtt) api.listen = api.listenMqtt;
602
+ if (api.refreshFb_dtsg) {
603
+ setInterval(function () {
604
+ api.refreshFb_dtsg().then(function () {
605
+ logger("Successfully refreshed fb_dtsg");
606
+ }).catch(function () {
620
607
  logger("An error occurred while refreshing fb_dtsg", "error");
621
608
  });
622
- }, 86400000);
623
-
624
- logger("Login successful!", "[ FCA-UNO ] >");
609
+ }, 86400000);
610
+ }
611
+ logger("Login successful!");
625
612
  callback(null, api);
626
613
  })
627
614
  .catch(function (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dongdev/fca-unofficial",
3
- "version": "2.0.12",
3
+ "version": "2.0.14",
4
4
  "description": "Unofficial Facebook Chat API for Node.js - Interact with Facebook Messenger programmatically",
5
5
  "main": "index.js",
6
6
  "scripts": {