shadowx-fca 2.1.0 โ 2.3.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.
- package/README.md +449 -0
- package/index.js +1 -106
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
```markdown
|
|
2
|
+
# shadowx-fca
|
|
3
|
+
#Mueid Mursalin Rifat
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>Unofficial Facebook Chat API for Node.js with Auto-Update System</strong><br>
|
|
7
|
+
Modified by Mueid Mursalin Rifat | Original by shadowX
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
## ๐ Table of Contents
|
|
11
|
+
|
|
12
|
+
- [Features](#-features)
|
|
13
|
+
- [Installation](#-installation)
|
|
14
|
+
- [Quick Start](#-quick-start)
|
|
15
|
+
- [Authentication Methods](#-authentication-methods)
|
|
16
|
+
- [API Documentation](#-api-documentation)
|
|
17
|
+
- [Configuration](#-configuration)
|
|
18
|
+
- [Anti-Detection Features](#-anti-detection-features)
|
|
19
|
+
- [Troubleshooting](#-troubleshooting)
|
|
20
|
+
- [Examples](#-examples)
|
|
21
|
+
- [Changelog](#-changelog)
|
|
22
|
+
- [License](#-license)
|
|
23
|
+
|
|
24
|
+
## โจ Features
|
|
25
|
+
|
|
26
|
+
- โ
**Multiple Authentication Methods** - Support for both appState and email/password login
|
|
27
|
+
- โ
**Real-time Messaging** - MQTT/WebSocket based real-time message listening
|
|
28
|
+
- โ
**Auto-Update System** - Automatically checks and updates to latest version
|
|
29
|
+
- โ
**Anti-Detection** - Rotating user agents, rate limiting, and stealth headers
|
|
30
|
+
- โ
**2FA Support** - Two-factor authentication handling
|
|
31
|
+
- โ
**Message Attachments** - Support for images, videos, files, stickers, and more
|
|
32
|
+
- โ
**Typing Indicators** - Send and receive typing status
|
|
33
|
+
- โ
**Read Receipts** - Message read confirmation
|
|
34
|
+
- โ
**Thread Management** - Create, delete, rename threads
|
|
35
|
+
- โ
**Mention Support** - Tag users in messages (both legacy and new formats)
|
|
36
|
+
- โ
**Configurable Options** - Extensive customization options
|
|
37
|
+
|
|
38
|
+
## ๐ฆ Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install shadowx-fca
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Requirements
|
|
45
|
+
|
|
46
|
+
ยท Node.js >= 16.0.0
|
|
47
|
+
ยท npm >= 7.0.0
|
|
48
|
+
|
|
49
|
+
๐ Quick Start
|
|
50
|
+
|
|
51
|
+
Method 1: Using AppState (Recommended)
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
const login = require('shadowx-fca');
|
|
55
|
+
const fs = require('fs');
|
|
56
|
+
|
|
57
|
+
// Load saved appState
|
|
58
|
+
const appState = JSON.parse(fs.readFileSync('appstate.json', 'utf8'));
|
|
59
|
+
|
|
60
|
+
login({ appState: appState }, (err, api) => {
|
|
61
|
+
if (err) return console.error('Login failed:', err);
|
|
62
|
+
|
|
63
|
+
console.log('โ
Logged in successfully!');
|
|
64
|
+
|
|
65
|
+
// Listen for incoming messages
|
|
66
|
+
api.listenMqtt((err, message) => {
|
|
67
|
+
if (err) return console.error('Listen error:', err);
|
|
68
|
+
|
|
69
|
+
if (message.type === 'message') {
|
|
70
|
+
console.log(`[${message.senderID}] ${message.body}`);
|
|
71
|
+
|
|
72
|
+
// Reply to message
|
|
73
|
+
api.sendMessage('Hello! I\'m a bot!', message.threadID);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Method 2: Email & Password
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
const login = require('shadowx-fca');
|
|
83
|
+
|
|
84
|
+
login({
|
|
85
|
+
email: 'your_email@example.com',
|
|
86
|
+
password: 'your_password'
|
|
87
|
+
}, (err, api) => {
|
|
88
|
+
if (err) return console.error('Login failed:', err);
|
|
89
|
+
|
|
90
|
+
console.log('โ
Logged in successfully!');
|
|
91
|
+
|
|
92
|
+
// Save appState for future use
|
|
93
|
+
const appState = api.getAppState();
|
|
94
|
+
fs.writeFileSync('appstate.json', JSON.stringify(appState, null, 2));
|
|
95
|
+
|
|
96
|
+
// Your bot logic here
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
๐ Authentication Methods
|
|
101
|
+
|
|
102
|
+
1. AppState (Recommended)
|
|
103
|
+
|
|
104
|
+
Most secure method - uses saved cookies instead of credentials.
|
|
105
|
+
|
|
106
|
+
Get your appState:
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
const login = require('shadowx-fca');
|
|
110
|
+
const fs = require('fs');
|
|
111
|
+
|
|
112
|
+
login({ email: 'your_email', password: 'your_password' }, (err, api) => {
|
|
113
|
+
if (err) return console.error(err);
|
|
114
|
+
|
|
115
|
+
const appState = api.getAppState();
|
|
116
|
+
fs.writeFileSync('appstate.json', JSON.stringify(appState, null, 2));
|
|
117
|
+
console.log('โ
AppState saved! You can now use this file to login.');
|
|
118
|
+
process.exit(0);
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
2. Email & Password
|
|
123
|
+
|
|
124
|
+
Traditional method with 2FA support.
|
|
125
|
+
|
|
126
|
+
With 2FA:
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
login({ email: 'email@example.com', password: 'password' }, (err, api) => {
|
|
130
|
+
if (err && err.error === 'login-approval') {
|
|
131
|
+
console.log('Enter 2FA code:');
|
|
132
|
+
// Get code from user input
|
|
133
|
+
const twoFACode = '123456';
|
|
134
|
+
err.continue(twoFACode);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
๐ API Documentation
|
|
140
|
+
|
|
141
|
+
Core Methods
|
|
142
|
+
|
|
143
|
+
login(loginData, [options], callback)
|
|
144
|
+
|
|
145
|
+
Main login function.
|
|
146
|
+
|
|
147
|
+
Parameters:
|
|
148
|
+
|
|
149
|
+
ยท loginData - Object containing either appState or email/password
|
|
150
|
+
ยท options - Optional configuration object
|
|
151
|
+
ยท callback - Function called after login
|
|
152
|
+
|
|
153
|
+
api.sendMessage(message, threadID, [callback], [replyToMessage], [isSingleUser])
|
|
154
|
+
|
|
155
|
+
Send a message to a thread.
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
// Simple message
|
|
159
|
+
api.sendMessage('Hello world!', 'thread_id_here');
|
|
160
|
+
|
|
161
|
+
// With reply
|
|
162
|
+
api.sendMessage('Replying to you!', 'thread_id_here', null, 'message_id_here');
|
|
163
|
+
|
|
164
|
+
// With mention
|
|
165
|
+
api.sendMessage('Hello @John Doe', 'thread_id_here');
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
api.listenMqtt(callback)
|
|
169
|
+
|
|
170
|
+
Listen for incoming events (messages, typing, presence).
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
api.listenMqtt((err, event) => {
|
|
174
|
+
if (err) return console.error(err);
|
|
175
|
+
|
|
176
|
+
switch(event.type) {
|
|
177
|
+
case 'message':
|
|
178
|
+
console.log('New message:', event.body);
|
|
179
|
+
break;
|
|
180
|
+
case 'event':
|
|
181
|
+
console.log('Thread event:', event.logMessageType);
|
|
182
|
+
break;
|
|
183
|
+
case 'typ':
|
|
184
|
+
console.log(event.isTyping ? 'Typing...' : 'Stopped typing');
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
api.getThreadInfo(threadID, callback)
|
|
191
|
+
|
|
192
|
+
Get information about a thread.
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
api.getThreadInfo('thread_id_here', (err, info) => {
|
|
196
|
+
if (err) return console.error(err);
|
|
197
|
+
console.log('Thread name:', info.name);
|
|
198
|
+
console.log('Participants:', info.participants);
|
|
199
|
+
console.log('Unread count:', info.unreadCount);
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
api.getUserInfo(userID, callback)
|
|
204
|
+
|
|
205
|
+
Get user information.
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
api.getUserInfo('user_id_here', (err, info) => {
|
|
209
|
+
if (err) return console.error(err);
|
|
210
|
+
console.log('Name:', info.name);
|
|
211
|
+
console.log('Gender:', info.gender);
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
api.setOptions(options)
|
|
216
|
+
|
|
217
|
+
Update API options at runtime.
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
api.setOptions({
|
|
221
|
+
listenEvents: true,
|
|
222
|
+
autoMarkRead: false,
|
|
223
|
+
delayBetweenRequests: 2000
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Additional Methods
|
|
228
|
+
|
|
229
|
+
Method Description
|
|
230
|
+
api.getAppState() Get current appState (cookies)
|
|
231
|
+
api.markAsRead(threadID, callback) Mark thread as read
|
|
232
|
+
api.markAsDelivered(threadID, messageID, callback) Mark message as delivered
|
|
233
|
+
api.sendTypingIndicator(threadID, callback) Send typing indicator
|
|
234
|
+
api.changeNickname(nickname, threadID, userID, callback) Change user nickname
|
|
235
|
+
api.addUserToGroup(userID, threadID, callback) Add user to group
|
|
236
|
+
api.removeUserFromGroup(userID, threadID, callback) Remove user from group
|
|
237
|
+
api.createNewGroup(participantIDs, groupName, callback) Create new group
|
|
238
|
+
api.deleteThread(threadID, callback) Delete/leave thread
|
|
239
|
+
api.getThreadList(limit, timestamp, tags, callback) Get thread list
|
|
240
|
+
|
|
241
|
+
โ๏ธ Configuration
|
|
242
|
+
|
|
243
|
+
Global Configuration (config.json)
|
|
244
|
+
|
|
245
|
+
Create config.json in your project root:
|
|
246
|
+
|
|
247
|
+
```json
|
|
248
|
+
{
|
|
249
|
+
"enableTypingIndicator": false,
|
|
250
|
+
"typingDuration": 4000,
|
|
251
|
+
"delayBetweenRequests": 1500,
|
|
252
|
+
"autoMarkDelivery": false,
|
|
253
|
+
"autoMarkRead": false,
|
|
254
|
+
"listenEvents": true,
|
|
255
|
+
"selfListen": false,
|
|
256
|
+
"autoReconnect": true,
|
|
257
|
+
"logLevel": "info",
|
|
258
|
+
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Options Reference
|
|
263
|
+
|
|
264
|
+
Option Type Default Description
|
|
265
|
+
selfListen Boolean false Listen to own messages
|
|
266
|
+
listenEvents Boolean true Listen to thread events
|
|
267
|
+
listenTyping Boolean false Listen to typing indicators
|
|
268
|
+
updatePresence Boolean false Update online status
|
|
269
|
+
forceLogin Boolean false Force login even if suspicious
|
|
270
|
+
autoMarkDelivery Boolean false Auto-mark messages as delivered
|
|
271
|
+
autoMarkRead Boolean false Auto-mark messages as read
|
|
272
|
+
autoReconnect Boolean true Auto-reconnect on disconnect
|
|
273
|
+
delayBetweenRequests Number 1000 Delay between API requests (ms)
|
|
274
|
+
logLevel String "info" Log level (silent/error/warn/info/verbose)
|
|
275
|
+
|
|
276
|
+
๐ก๏ธ Anti-Detection Features
|
|
277
|
+
|
|
278
|
+
shadowx-fca includes several features to avoid Facebook's anti-bot detection:
|
|
279
|
+
|
|
280
|
+
1. Rate Limiting
|
|
281
|
+
|
|
282
|
+
```javascript
|
|
283
|
+
// Set custom delay between requests
|
|
284
|
+
api.setOptions({ delayBetweenRequests: 2000 });
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
2. Rotating User Agents
|
|
288
|
+
|
|
289
|
+
Automatically rotates between different user agents to avoid fingerprinting.
|
|
290
|
+
|
|
291
|
+
3. Stealth Headers
|
|
292
|
+
|
|
293
|
+
Includes realistic browser headers (Sec-Ch-Ua, Accept-Language, etc.)
|
|
294
|
+
|
|
295
|
+
4. Request Queue
|
|
296
|
+
|
|
297
|
+
Automatically queues and spaces out requests to prevent rate limiting.
|
|
298
|
+
|
|
299
|
+
๐ง Troubleshooting
|
|
300
|
+
|
|
301
|
+
Common Issues & Solutions
|
|
302
|
+
|
|
303
|
+
1. "Error! Your cookiestate is not valid!"
|
|
304
|
+
|
|
305
|
+
Solution: Refresh your appState
|
|
306
|
+
|
|
307
|
+
```javascript
|
|
308
|
+
// Get new appState
|
|
309
|
+
login({ email: 'your_email', password: 'your_password' }, (err, api) => {
|
|
310
|
+
const newAppState = api.getAppState();
|
|
311
|
+
fs.writeFileSync('appstate.json', JSON.stringify(newAppState, null, 2));
|
|
312
|
+
});
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
2. Account Suspension
|
|
316
|
+
|
|
317
|
+
Solutions:
|
|
318
|
+
|
|
319
|
+
ยท Increase delay between requests
|
|
320
|
+
ยท Don't spam messages (add 2-3 second delays)
|
|
321
|
+
ยท Use appState instead of email/password
|
|
322
|
+
ยท Avoid running 24/7
|
|
323
|
+
ยท Use a proxy if running multiple bots
|
|
324
|
+
|
|
325
|
+
3. Login Timeout
|
|
326
|
+
|
|
327
|
+
Solution: Increase timeout in options
|
|
328
|
+
|
|
329
|
+
```javascript
|
|
330
|
+
login({ appState: appState }, { timeout: 120000 }, callback);
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
4. MQTT Connection Issues
|
|
334
|
+
|
|
335
|
+
Solution: Enable auto-reconnect
|
|
336
|
+
|
|
337
|
+
```javascript
|
|
338
|
+
api.setOptions({ autoReconnect: true });
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
๐ก Examples
|
|
342
|
+
|
|
343
|
+
Simple Echo Bot
|
|
344
|
+
|
|
345
|
+
```javascript
|
|
346
|
+
const login = require('shadowx-fca');
|
|
347
|
+
|
|
348
|
+
login({ appState: require('./appstate.json') }, (err, api) => {
|
|
349
|
+
if (err) return console.error(err);
|
|
350
|
+
|
|
351
|
+
api.listenMqtt((err, message) => {
|
|
352
|
+
if (err) return console.error(err);
|
|
353
|
+
|
|
354
|
+
if (message.type === 'message' && message.body) {
|
|
355
|
+
// Echo the message back
|
|
356
|
+
api.sendMessage(message.body, message.threadID);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Command Handler
|
|
363
|
+
|
|
364
|
+
```javascript
|
|
365
|
+
const commands = {
|
|
366
|
+
'!help': (api, message) => {
|
|
367
|
+
api.sendMessage('Available commands: !help, !time, !ping', message.threadID);
|
|
368
|
+
},
|
|
369
|
+
'!time': (api, message) => {
|
|
370
|
+
api.sendMessage(`Current time: ${new Date().toLocaleString()}`, message.threadID);
|
|
371
|
+
},
|
|
372
|
+
'!ping': (api, message) => {
|
|
373
|
+
api.sendMessage('Pong!', message.threadID);
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
login({ appState: require('./appstate.json') }, (err, api) => {
|
|
378
|
+
if (err) return console.error(err);
|
|
379
|
+
|
|
380
|
+
api.listenMqtt((err, message) => {
|
|
381
|
+
if (err) return console.error(err);
|
|
382
|
+
|
|
383
|
+
if (message.type === 'message' && message.body) {
|
|
384
|
+
const cmd = message.body.split(' ')[0];
|
|
385
|
+
if (commands[cmd]) commands[cmd](api, message);
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Auto-Reply with Delay
|
|
392
|
+
|
|
393
|
+
```javascript
|
|
394
|
+
login({ appState: require('./appstate.json') }, (err, api) => {
|
|
395
|
+
if (err) return console.error(err);
|
|
396
|
+
|
|
397
|
+
api.listenMqtt((err, message) => {
|
|
398
|
+
if (err) return console.error(err);
|
|
399
|
+
|
|
400
|
+
if (message.type === 'message' && !message.isGroup) {
|
|
401
|
+
// Add delay to avoid rate limiting
|
|
402
|
+
setTimeout(() => {
|
|
403
|
+
api.sendMessage('Thanks for your message! I\'ll reply soon.', message.threadID);
|
|
404
|
+
}, 3000);
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
๐ Changelog
|
|
411
|
+
|
|
412
|
+
v2.1.0 (Latest)
|
|
413
|
+
|
|
414
|
+
ยท โจ Added rotating user agents for anti-detection
|
|
415
|
+
ยท ๐ Implemented request queue with rate limiting
|
|
416
|
+
ยท ๐ง Fixed email/password login issues
|
|
417
|
+
ยท ๐ก๏ธ Enhanced security headers
|
|
418
|
+
ยท ๐ Improved documentation
|
|
419
|
+
|
|
420
|
+
v2.0.0
|
|
421
|
+
|
|
422
|
+
ยท Added auto-update system
|
|
423
|
+
ยท Improved MQTT connection stability
|
|
424
|
+
ยท Added support for new mention format
|
|
425
|
+
ยท Fixed 2FA handling
|
|
426
|
+
|
|
427
|
+
๐ License
|
|
428
|
+
|
|
429
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
430
|
+
|
|
431
|
+
โ ๏ธ Disclaimer
|
|
432
|
+
|
|
433
|
+
This project is for educational purposes only. Use at your own risk. The authors are not responsible for any consequences that may arise from using this software, including but not limited to account suspension or legal action from Facebook.
|
|
434
|
+
|
|
435
|
+
๐ค Contributing
|
|
436
|
+
|
|
437
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
438
|
+
|
|
439
|
+
๐ Support
|
|
440
|
+
|
|
441
|
+
ยท Issues: t.me/mueidmursalinrifat
|
|
442
|
+
ยท Author: Mueid Mursalin Rifat
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
<div align="center">
|
|
447
|
+
Made with โค๏ธ by Mueid Mursalin Rifat
|
|
448
|
+
</div>
|
|
449
|
+
```
|
package/index.js
CHANGED
|
@@ -3,28 +3,11 @@
|
|
|
3
3
|
var utils = require("./utils");
|
|
4
4
|
var cheerio = require("cheerio");
|
|
5
5
|
var log = require("npmlog");
|
|
6
|
-
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
/*var { getThemeColors } = require("../../func/utils/log.js");
|
|
10
|
-
var logger = require("../../func/utils/log.js");
|
|
11
|
-
var { cra, cv, cb, co } = getThemeColors();*/
|
|
6
|
+
|
|
12
7
|
log.maxRecordSize = 100;
|
|
13
8
|
var checkVerified = null;
|
|
14
9
|
const Boolean_Option = ['online', 'selfListen', 'listenEvents', 'updatePresence', 'forceLogin', 'autoMarkDelivery', 'autoMarkRead', 'listenTyping', 'autoReconnect', 'emitReady'];
|
|
15
10
|
global.ditconmemay = false;
|
|
16
|
-
global.stfcaUpdateChecked = false;
|
|
17
|
-
|
|
18
|
-
// Auto-check for updates on package load (non-blocking)
|
|
19
|
-
if (!global.stfcaUpdateChecked) {
|
|
20
|
-
global.stfcaUpdateChecked = true;
|
|
21
|
-
const { checkForFCAUpdate } = require("./checkUpdate");
|
|
22
|
-
setImmediate(() => {
|
|
23
|
-
checkForFCAUpdate().catch(() => {
|
|
24
|
-
// Silent fail - don't interrupt user's bot
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
11
|
|
|
29
12
|
function setOptions(globalOptions, options) {
|
|
30
13
|
Object.keys(options).map(function (key) {
|
|
@@ -190,86 +173,6 @@ function buildAPI(globalOptions, html, jar) {
|
|
|
190
173
|
reqCallbacks: {},
|
|
191
174
|
threadTypes: {} // Store thread type (dm/group) for each thread
|
|
192
175
|
};
|
|
193
|
-
let config = { enableTypingIndicator: false, typingDuration: 4000 };
|
|
194
|
-
try {
|
|
195
|
-
// Prefer global root config (project-level), but fallback to fca/config.json if present.
|
|
196
|
-
const rootConfigPath = path.join(process.cwd(), 'config.json');
|
|
197
|
-
if (fs.existsSync(rootConfigPath)) {
|
|
198
|
-
const rootConfig = JSON.parse(fs.readFileSync(rootConfigPath, 'utf8'));
|
|
199
|
-
if (rootConfig && typeof rootConfig === 'object') {
|
|
200
|
-
if (typeof rootConfig.enableTypingIndicator !== 'undefined') config.enableTypingIndicator = rootConfig.enableTypingIndicator;
|
|
201
|
-
if (typeof rootConfig.typingDuration !== 'undefined') config.typingDuration = rootConfig.typingDuration;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const fcaConfigPath = path.join(__dirname, 'config.json');
|
|
206
|
-
if (fs.existsSync(fcaConfigPath)) {
|
|
207
|
-
const fcaConfig = JSON.parse(fs.readFileSync(fcaConfigPath, 'utf8'));
|
|
208
|
-
if (fcaConfig && typeof fcaConfig === 'object') {
|
|
209
|
-
if (typeof fcaConfig.enableTypingIndicator !== 'undefined') config.enableTypingIndicator = fcaConfig.enableTypingIndicator;
|
|
210
|
-
if (typeof fcaConfig.typingDuration !== 'undefined') config.typingDuration = fcaConfig.typingDuration;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (global.GoatBot && global.GoatBot.config) {
|
|
215
|
-
if (typeof global.GoatBot.config.enableTypingIndicator !== 'undefined') config.enableTypingIndicator = global.GoatBot.config.enableTypingIndicator;
|
|
216
|
-
if (typeof global.GoatBot.config.typingDuration !== 'undefined') config.typingDuration = global.GoatBot.config.typingDuration;
|
|
217
|
-
}
|
|
218
|
-
} catch (e) {
|
|
219
|
-
console.log('Error loading config.json:', e);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const refreshFcaConfig = () => {
|
|
223
|
-
try {
|
|
224
|
-
// Defaults first
|
|
225
|
-
const updatedConfig = { enableTypingIndicator: false, typingDuration: 4000 };
|
|
226
|
-
|
|
227
|
-
// Layered config sources
|
|
228
|
-
if (fs.existsSync(path.join(process.cwd(), 'config.json'))) {
|
|
229
|
-
const rootConfig = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'config.json'), 'utf8'));
|
|
230
|
-
if (rootConfig && typeof rootConfig === 'object') {
|
|
231
|
-
if (typeof rootConfig.enableTypingIndicator !== 'undefined') updatedConfig.enableTypingIndicator = rootConfig.enableTypingIndicator;
|
|
232
|
-
if (typeof rootConfig.typingDuration !== 'undefined') updatedConfig.typingDuration = rootConfig.typingDuration;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (fs.existsSync(path.join(__dirname, 'config.json'))) {
|
|
237
|
-
const fcaConfig = JSON.parse(fs.readFileSync(path.join(__dirname, 'config.json'), 'utf8'));
|
|
238
|
-
if (fcaConfig && typeof fcaConfig === 'object') {
|
|
239
|
-
if (typeof fcaConfig.enableTypingIndicator !== 'undefined') updatedConfig.enableTypingIndicator = fcaConfig.enableTypingIndicator;
|
|
240
|
-
if (typeof fcaConfig.typingDuration !== 'undefined') updatedConfig.typingDuration = fcaConfig.typingDuration;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if (global.GoatBot && global.GoatBot.config) {
|
|
245
|
-
if (typeof global.GoatBot.config.enableTypingIndicator !== 'undefined') updatedConfig.enableTypingIndicator = global.GoatBot.config.enableTypingIndicator;
|
|
246
|
-
if (typeof global.GoatBot.config.typingDuration !== 'undefined') updatedConfig.typingDuration = global.GoatBot.config.typingDuration;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
ctx.config = updatedConfig;
|
|
250
|
-
config = updatedConfig;
|
|
251
|
-
if (global.GoatBot) global.GoatBot.config = global.GoatBot.config || {};
|
|
252
|
-
if (global.GoatBot && typeof global.GoatBot.config.enableTypingIndicator !== 'undefined') {
|
|
253
|
-
global.GoatBot.config.enableTypingIndicator = updatedConfig.enableTypingIndicator;
|
|
254
|
-
}
|
|
255
|
-
if (global.GoatBot && typeof global.GoatBot.config.typingDuration !== 'undefined') {
|
|
256
|
-
global.GoatBot.config.typingDuration = updatedConfig.typingDuration;
|
|
257
|
-
}
|
|
258
|
-
} catch (e) {
|
|
259
|
-
console.log('Failed to refresh fca config:', e);
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
// Initial config load
|
|
264
|
-
refreshFcaConfig();
|
|
265
|
-
|
|
266
|
-
// Accessible runtime API for config reload
|
|
267
|
-
ctx.refreshFcaConfig = refreshFcaConfig;
|
|
268
|
-
if (global.GoatBot) {
|
|
269
|
-
global.GoatBot.refreshFcaConfig = refreshFcaConfig;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
ctx.config = config;
|
|
273
176
|
var api = {
|
|
274
177
|
setOptions: setOptions.bind(null, globalOptions),
|
|
275
178
|
getAppState: () => utils.getAppState(jar),
|
|
@@ -523,14 +426,6 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
|
|
|
523
426
|
|
|
524
427
|
|
|
525
428
|
function login(loginData, options, callback) {
|
|
526
|
-
// Check for updates (non-blocking, only once per session)
|
|
527
|
-
if (!global.stfcaUpdateChecked) {
|
|
528
|
-
global.stfcaUpdateChecked = true;
|
|
529
|
-
checkForFCAUpdate().catch(err => {
|
|
530
|
-
// Silently ignore update check errors to not block login
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
|
|
534
429
|
if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
|
|
535
430
|
callback = options;
|
|
536
431
|
options = {};
|