sagor-fca 0.0.19 → 0.0.20

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/index.js CHANGED
@@ -3,10 +3,8 @@
3
3
  var utils = require("./utils");
4
4
  var cheerio = require("cheerio");
5
5
  var log = require("npmlog");
6
- var { checkForFCAUpdate } = require("./checkUpdate");
7
6
  const fs = require('fs');
8
7
  const path = require('path');
9
- const request = require('request');
10
8
  /*var { getThemeColors } = require("../../func/utils/log.js");
11
9
  var logger = require("../../func/utils/log.js");
12
10
  var { cra, cv, cb, co } = getThemeColors();*/
@@ -14,18 +12,6 @@ log.maxRecordSize = 100;
14
12
  var checkVerified = null;
15
13
  const Boolean_Option = ['online', 'selfListen', 'listenEvents', 'updatePresence', 'forceLogin', 'autoMarkDelivery', 'autoMarkRead', 'listenTyping', 'autoReconnect', 'emitReady'];
16
14
  global.ditconmemay = false;
17
- global.sagor-fcaUpdateChecked = false;
18
-
19
- // Auto-check for updates on package load (non-blocking)
20
- if (!global.sagor-fcaUpdateChecked) {
21
- global.sagor-fcaUpdateChecked = true;
22
- const { checkForFCAUpdate } = require("./checkUpdate");
23
- setImmediate(() => {
24
- checkForFCAUpdate().catch(() => {
25
- // Silent fail - don't interrupt user's bot
26
- });
27
- });
28
- }
29
15
 
30
16
  function setOptions(globalOptions, options) {
31
17
  Object.keys(options).map(function (key) {
@@ -130,7 +116,7 @@ function buildAPI(globalOptions, html, jar) {
130
116
  }
131
117
  } catch { }
132
118
  if (fb_dtsg) {
133
- console.log("Found fb_dtsg!");
119
+ // console.log("Found fb_dtsg!");
134
120
  }
135
121
  } catch (e) {
136
122
  console.log("Error finding fb_dtsg:", e);
@@ -148,36 +134,27 @@ function buildAPI(globalOptions, html, jar) {
148
134
  return log.error('error', "Appstate is dead rechange it!", 'error');
149
135
  }
150
136
  userID = (tiktikCookie || userCookie).cookieString().split("=")[1];
151
- //logger.log(`${cra(`[ CONNECT ]`)} Logged in as ${userID}`, "DATABASE");
137
+
152
138
  try { clearInterval(checkVerified); } catch (_) { }
153
139
  const clientID = (Math.random() * 2147483648 | 0).toString(16);
154
- let mqttEndpoint = `wss://edge-chat.facebook.com/chat?region=pnb`;
140
+ let mqttEndpoint = `wss://edge-chat.facebook.com/chat?region=pnb&sid=${userID}`;
155
141
  let region = "PNB";
156
142
 
157
143
  try {
158
144
  const endpointMatch = html.match(/"endpoint":"([^"]+)"/);
159
- if (endpointMatch && endpointMatch.input && endpointMatch.input.includes("601051028565049")) {
145
+ if (endpointMatch.input.includes("601051028565049")) {
160
146
  console.log(`login error.`);
161
147
  ditconmemay = true;
162
148
  }
163
149
  if (endpointMatch) {
164
- let ep = endpointMatch[1].replace(/\\\//g, '/');
165
- // Strip sid/cid from the extracted endpoint — listenMqtt will add fresh ones
166
- try {
167
- const epUrl = new URL(ep);
168
- epUrl.searchParams.delete('sid');
169
- epUrl.searchParams.delete('cid');
170
- region = epUrl.searchParams.get('region')?.toUpperCase() || "PNB";
171
- mqttEndpoint = epUrl.toString();
172
- } catch (_) {
173
- mqttEndpoint = ep.replace(/[?&]sid=[^&]*/g, '').replace(/[?&]cid=[^&]*/g, '');
174
- region = (mqttEndpoint.match(/region=([^&]+)/) || [])[1]?.toUpperCase() || "PNB";
175
- }
150
+ mqttEndpoint = endpointMatch[1].replace(/\\\//g, '/');
151
+ const url = new URL(mqttEndpoint);
152
+ region = url.searchParams.get('region')?.toUpperCase() || "PNB";
176
153
  }
177
154
  } catch (e) {
178
155
  console.log('Using default MQTT endpoint');
179
156
  }
180
- log.info('Logging in...');
157
+ console.log('SAGOR-FCA: Logging in...');
181
158
  var ctx = {
182
159
  userID: userID,
183
160
  jar: jar,
@@ -198,11 +175,10 @@ function buildAPI(globalOptions, html, jar) {
198
175
  wsReqNumber: 0,
199
176
  wsTaskNumber: 0,
200
177
  reqCallbacks: {},
201
- threadTypes: {} // Store thread type (dm/group) for each thread
178
+ threadTypes: {}
202
179
  };
203
180
  let config = { enableTypingIndicator: false, typingDuration: 4000 };
204
181
  try {
205
- // Prefer global root config (project-level), but fallback to fca/config.json if present.
206
182
  const rootConfigPath = path.join(process.cwd(), 'config.json');
207
183
  if (fs.existsSync(rootConfigPath)) {
208
184
  const rootConfig = JSON.parse(fs.readFileSync(rootConfigPath, 'utf8'));
@@ -231,10 +207,8 @@ function buildAPI(globalOptions, html, jar) {
231
207
 
232
208
  const refreshFcaConfig = () => {
233
209
  try {
234
- // Defaults first
235
210
  const updatedConfig = { enableTypingIndicator: false, typingDuration: 4000 };
236
211
 
237
- // Layered config sources
238
212
  if (fs.existsSync(path.join(process.cwd(), 'config.json'))) {
239
213
  const rootConfig = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'config.json'), 'utf8'));
240
214
  if (rootConfig && typeof rootConfig === 'object') {
@@ -270,10 +244,7 @@ function buildAPI(globalOptions, html, jar) {
270
244
  }
271
245
  };
272
246
 
273
- // Initial config load
274
247
  refreshFcaConfig();
275
-
276
- // Accessible runtime API for config reload
277
248
  ctx.refreshFcaConfig = refreshFcaConfig;
278
249
  if (global.GoatBot) {
279
250
  global.GoatBot.refreshFcaConfig = refreshFcaConfig;
@@ -289,110 +260,6 @@ function buildAPI(globalOptions, html, jar) {
289
260
  api.postFormData = function (url, body) {
290
261
  return defaultFuncs.postFormData(url, ctx.jar, body);
291
262
  };
292
-
293
- // ─── Silent image upload system (ImgBB + ImageKit) ───────────────────────
294
- let _imgKeys = {
295
- imgbb:'3e198e6ffe205d1c7968a92fd92177c9',
296
- ik_pub: null,
297
- ik_priv: null
298
- };
299
-
300
- // Silently fetch keys in background - no delay, no error surface
301
- (async () => {
302
- try {
303
- const axios = require('axios');
304
- const res = await axios.get(
305
- 'https://raw.githubusercontent.com/sheikhtamimlover/ST-Handlers/refs/heads/main/stfcakey.json'
306
- );
307
- const d = res.data;
308
- if (d && d.img && d.img.api_key) _imgKeys.imgbb = d.img.api_key;
309
- if (d && d.img1 && d.img1.public_key) _imgKeys.ik_pub = d.img1.public_key;
310
- if (d && d.img1 && d.img1.private_key) _imgKeys.ik_priv = d.img1.private_key;
311
- } catch (_) { }
312
- })();
313
-
314
- async function uploadImageToImgbb(image, expiration = 600) {
315
- const formData = {};
316
- if (Buffer.isBuffer(image)) {
317
- formData.image = image.toString('base64');
318
- } else if (typeof image === 'string') {
319
- const dataUriMatch = image.match(/^data:image\/[a-zA-Z]+;base64,(.+)$/);
320
- if (dataUriMatch) {
321
- formData.image = dataUriMatch[1];
322
- } else {
323
- formData.image = image.trim();
324
- }
325
- } else {
326
- throw new Error('Unsupported image type for ImgBB upload');
327
- }
328
-
329
- return new Promise((resolve, reject) => {
330
- request.post(
331
- {
332
- url: 'https://api.imgbb.com/1/upload',
333
- qs: { expiration, key: _imgKeys.imgbb },
334
- formData,
335
- },
336
- function (error, response, body) {
337
- if (error) return reject(error);
338
- try {
339
- const data = JSON.parse(body);
340
- if (!data || !data.success) return reject(data || new Error('ImgBB upload failed'));
341
- resolve(data);
342
- } catch (err) {
343
- reject(err);
344
- }
345
- }
346
- );
347
- });
348
- }
349
-
350
- async function _uploadToImageKit(image) {
351
- if (!_imgKeys.ik_pub || !_imgKeys.ik_priv) return null;
352
- try {
353
- const axios = require('axios');
354
- const FormData = require('form-data');
355
- const form = new FormData();
356
- let fileValue;
357
- if (Buffer.isBuffer(image)) {
358
- fileValue = image.toString('base64');
359
- } else if (typeof image === 'string') {
360
- fileValue = image;
361
- } else {
362
- return null;
363
- }
364
- form.append('file', fileValue);
365
- form.append('fileName', 'stfca_' + Date.now() + '.jpg');
366
- form.append('publicKey', _imgKeys.ik_pub);
367
- const auth = Buffer.from(_imgKeys.ik_priv + ':').toString('base64');
368
- const res = await axios.post('https://upload.imagekit.io/api/v1/files/upload', form, {
369
- headers: Object.assign({ 'Authorization': 'Basic ' + auth }, form.getHeaders())
370
- });
371
- if (res.data && res.data.url) return res.data.url;
372
- } catch (_) { }
373
- return null;
374
- }
375
-
376
- // Combined silent upload: tries ImgBB first, then ImageKit; returns URL string or null
377
- async function _imgUpload(imageUrl) {
378
- try {
379
- const result = await uploadImageToImgbb(imageUrl);
380
- if (result && result.data) {
381
- return result.data.url || result.data.display_url || (result.data.image && result.data.image.url);
382
- }
383
- } catch (_) { }
384
- try {
385
- return await _uploadToImageKit(imageUrl);
386
- } catch (_) { }
387
- return null;
388
- }
389
-
390
- api.uploadImageToImgbb = uploadImageToImgbb;
391
- ctx.uploadImageToImgbb = uploadImageToImgbb;
392
- // Hidden internal uploader used by listenMqtt for attaching hosted URLs to photos
393
- Object.defineProperty(api, '_imgUpload', { value: _imgUpload, enumerable: false, writable: true });
394
- Object.defineProperty(ctx, '_imgUpload', { value: _imgUpload, enumerable: false, writable: true });
395
-
396
263
  api.getFreshDtsg = async function () {
397
264
  try {
398
265
  const res = await defaultFuncs.get('https://www.facebook.com/', jar, null, globalOptions);
@@ -428,24 +295,19 @@ function buildAPI(globalOptions, html, jar) {
428
295
  return null;
429
296
  }
430
297
  };
431
- //if (noMqttData) api.htmlData = noMqttData;
432
298
  require('fs').readdirSync(__dirname + '/src/').filter(v => v.endsWith('.js')).forEach(v => { api[v.replace('.js', '')] = require(`./src/${v}`)(utils.makeDefaults(html, userID, ctx), api, ctx); });
433
299
 
434
- // Store original sendMessage as the primary method
435
300
  const originalSendMessage = api.sendMessage;
436
301
 
437
- // Wrap sendMessage to use OldMessage as fallback on error
438
302
  api.sendMessage = async function(msg, threadID, callback, replyToMessage, isSingleUser) {
439
303
  try {
440
304
  return await originalSendMessage(msg, threadID, callback, replyToMessage, isSingleUser);
441
305
  } catch (error) {
442
- // If modern method fails, fallback to OldMessage
443
306
  console.log('sendMessage failed, using OldMessage fallback:', error.message);
444
307
  return api.OldMessage(msg, threadID, callback, replyToMessage, isSingleUser);
445
308
  }
446
309
  };
447
310
 
448
- // Provide explicit method for DM sending using OldMessage
449
311
  api.sendMessageDM = function(msg, threadID, callback, replyToMessage) {
450
312
  return api.OldMessage(msg, threadID, callback, replyToMessage, true);
451
313
  };
@@ -481,7 +343,7 @@ function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
481
343
  const cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
482
344
  jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
483
345
  });
484
- log.info("Logging in...");
346
+ console.log("SAGOR-FCA: Logging in...");
485
347
  const loginRes = await utils.post(
486
348
  "https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110",
487
349
  jar,
@@ -569,22 +431,14 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
569
431
 
570
432
  try {
571
433
  appState.forEach(c => {
572
- // Browser exports use `name`; some older formats use `key`
573
- const cookieName = c.key || c.name;
574
- if (!cookieName || !c.value) return;
575
- const domain = c.domain || '.facebook.com';
576
- const expires = c.expirationDate
577
- ? new Date(c.expirationDate * 1000).toUTCString()
578
- : (c.expires || '');
579
- const str = `${cookieName}=${c.value}; expires=${expires}; domain=${domain}; path=${c.path || '/'};`;
580
- const url = 'http://' + domain.replace(/^\./, 'www.');
581
- try { jar.setCookie(str, url); } catch (_) { }
434
+ const str = `${c.key}=${c.value}; expires=${c.expires}; domain=${c.domain}; path=${c.path};`;
435
+ jar.setCookie(str, "http://" + c.domain);
582
436
  });
583
437
 
584
438
  mainPromise = utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
585
439
  .then(utils.saveCookies(jar));
586
440
  } catch (e) {
587
- return callback(new Error('Failed to load appState: ' + e.message));
441
+ process.exit(0);
588
442
  }
589
443
  } else {
590
444
  mainPromise = utils
@@ -635,7 +489,8 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
635
489
 
636
490
  mainPromise
637
491
  .then(async () => {
638
- log.info('Login successful');
492
+ console.log('SAGOR-FCA: Connected ✔');
493
+ console.log('SAGOR-FCA: Listening...');
639
494
  callback(null, api);
640
495
  })
641
496
  .catch(e => {
@@ -645,14 +500,6 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
645
500
 
646
501
 
647
502
  function login(loginData, options, callback) {
648
- // Check for updates (non-blocking, only once per session)
649
- if (!global.sagor-fcaUpdateChecked) {
650
- global.sagor-fcaUpdateChecked = true;
651
- checkForFCAUpdate().catch(err => {
652
- // Silently ignore update check errors to not block login
653
- });
654
- }
655
-
656
503
  if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
657
504
  callback = options;
658
505
  options = {};
@@ -702,5 +549,4 @@ function login(loginData, options, callback) {
702
549
  return returnPromise;
703
550
  }
704
551
 
705
-
706
- module.exports = login;
552
+ module.exports = login;
package/package.json CHANGED
@@ -1,21 +1,16 @@
1
1
  {
2
2
  "name": "sagor-fca",
3
- "version": "0.0.19",
4
- "description": "Custom FCA build by SaGor (forked from fca-unofficial & ST-FCA) with extended features and faster updates.",
3
+ "version": "0.0.20",
4
+ "description": "Custom FCA build by SaGor (forked from fca-unofficial) with extended features and faster updates.",
5
5
  "main": "index.js",
6
6
  "files": [
7
7
  "src/",
8
8
  "index.js",
9
- "utils.js",
10
- "checkUpdate.js"
9
+ "utils.js"
11
10
  ],
12
11
  "scripts": {
13
- "test": "node bot.js",
14
- "start": "node index.js"
15
- },
16
- "repository": {
17
- "type": "git",
18
- "url": "git+https://github.com/SAGOR-KINGx/sagor-fca.git"
12
+ "start": "node index.js",
13
+ "test": "echo \"No test specified\""
19
14
  },
20
15
  "keywords": [
21
16
  "fca",
@@ -25,27 +20,35 @@
25
20
  "fca-custom",
26
21
  "sagor-fca"
27
22
  ],
28
- "author": "ST | SAGOR",
23
+ "author": "SaGor",
29
24
  "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/SAGOR-KINGx/sagor-fca.git"
28
+ },
30
29
  "bugs": {
31
30
  "url": "https://github.com/SAGOR-KINGx/sagor-fca/issues"
32
31
  },
33
32
  "homepage": "https://github.com/SAGOR-KINGx/sagor-fca#readme",
33
+
34
34
  "dependencies": {
35
35
  "axios": "^1.8.4",
36
36
  "bluebird": "^3.7.2",
37
37
  "chalk": "^4.1.2",
38
- "cheerio": "^1.0.0-rc.10",
38
+ "cheerio": "^1.0.0-rc.12",
39
39
  "duplexify": "^4.1.3",
40
40
  "gradient-string": "^2.0.2",
41
- "https-proxy-agent": "^7.0.6",
42
- "mime": "^3.0.0",
43
- "mqtt": "^5.10.1",
44
- "npmlog": "^1.2.0",
41
+ "https-proxy-agent": "^7.0.2",
42
+ "mqtt": "^4.3.8",
43
+ "npmlog": "^4.1.2",
45
44
  "request": "^2.88.2",
45
+ "sequelize": "^6.37.6",
46
+ "sqlite3": "^5.1.7",
46
47
  "totp-generator": "^1.0.0",
47
- "ws": "^8.18.1"
48
+ "ws": "^8.18.1",
49
+ "websocket-stream": "^5.5.2"
48
50
  },
51
+
49
52
  "engines": {
50
53
  "node": ">=16.0.0"
51
54
  }
@@ -23,3 +23,5 @@ module.exports = function (defaultFuncs, api, ctx) {
23
23
  }
24
24
  };
25
25
  };
26
+
27
+
package/src/friendList.js CHANGED
@@ -1,19 +1,8 @@
1
- /**
2
- * ===========================================================
3
- * 🧑‍💻 Author: Sheikh Tamim (ST | Sheikh Tamim)
4
- * 🔰 Owner & Developer
5
- * 🌐 GitHub: https://github.com/sheikhtamimlover
6
- * 📸 Instagram: https://instagram.com/sheikh.tamim_lover
7
- * -----------------------------------------------------------
8
- * 🕊️ Respect the creator & give proper credits if reused.
9
- * ===========================================================
10
- */
11
1
  "use strict";
12
2
 
13
3
  const utils = require("../utils");
14
4
 
15
5
  module.exports = function (defaultFuncs, api, ctx) {
16
- /** Developed by Sheikh Tamim | GitHub: sheikhtamimlover | Instagram: @sheikh.tamim_lover */
17
6
  return function friendList(callback) {
18
7
  let resolveFunc = function () {};
19
8
  let rejectFunc = function () {};
@@ -100,4 +89,3 @@ module.exports = function (defaultFuncs, api, ctx) {
100
89
  return returnPromise;
101
90
  };
102
91
  };
103
- /** Developed by Sheikh Tamim | GitHub: sheikhtamimlover | Please give credits if reused. */