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 +16 -170
- package/package.json +20 -17
- package/src/addExternalModule.js +2 -0
- package/src/friendList.js +0 -12
- package/src/listenMqtt.js +275 -400
- package/src/sendMessage.js +251 -292
- package/src/sendMessageMqtt.js +1 -0
- package/src/uploadAttachment.js +77 -99
- package/utils.js +13 -75
- package/checkUpdate.js +0 -116
- package/src/sendButtons.js +0 -161
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
|
-
|
|
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
|
|
145
|
+
if (endpointMatch.input.includes("601051028565049")) {
|
|
160
146
|
console.log(`login error.`);
|
|
161
147
|
ditconmemay = true;
|
|
162
148
|
}
|
|
163
149
|
if (endpointMatch) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
|
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: {}
|
|
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
|
|
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
|
-
|
|
573
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
4
|
-
"description": "Custom FCA build by SaGor (forked from fca-unofficial
|
|
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
|
-
"
|
|
14
|
-
"
|
|
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": "
|
|
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.
|
|
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.
|
|
42
|
-
"
|
|
43
|
-
"
|
|
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
|
}
|
package/src/addExternalModule.js
CHANGED
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. */
|