nexus-fca 1.0.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.
Files changed (180) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/DOCS.md +2047 -0
  3. package/Fca_Database/database.sqlite +0 -0
  4. package/LICENSE-MIT +21 -0
  5. package/README.md +240 -0
  6. package/docs/README.md +9 -0
  7. package/docs/addExternalModule.md +15 -0
  8. package/docs/addUserToGroup.md +20 -0
  9. package/docs/changeAdminStatus.md +21 -0
  10. package/docs/changeArchivedStatus.md +19 -0
  11. package/docs/changeAvatar.md +21 -0
  12. package/docs/changeAvatarV2.md +18 -0
  13. package/docs/changeBio.md +15 -0
  14. package/docs/changeBlockedStatus.md +16 -0
  15. package/docs/changeBlockedStatusMqtt.md +16 -0
  16. package/docs/changeCover.md +15 -0
  17. package/docs/changeGroupImage.md +16 -0
  18. package/docs/changeName.md +18 -0
  19. package/docs/changeNickname.md +17 -0
  20. package/docs/changeThreadColor.md +16 -0
  21. package/docs/changeThreadEmoji.md +16 -0
  22. package/docs/changeUsername.md +15 -0
  23. package/docs/createCommentPost.md +16 -0
  24. package/docs/createNewGroup.md +16 -0
  25. package/docs/createPoll.md +17 -0
  26. package/docs/createPost.md +15 -0
  27. package/docs/deleteMessage.md +15 -0
  28. package/docs/deleteThread.md +15 -0
  29. package/docs/editMessage.md +16 -0
  30. package/docs/follow.md +15 -0
  31. package/docs/forwardAttachment.md +16 -0
  32. package/docs/getAccess.md +17 -0
  33. package/docs/getAvatarUser.md +15 -0
  34. package/docs/getBotInitialData.md +14 -0
  35. package/docs/getCtx.md +14 -0
  36. package/docs/getCurrentUserID.md +12 -0
  37. package/docs/getEmojiUrl.md +17 -0
  38. package/docs/getFriendsList.md +14 -0
  39. package/docs/getMessage.md +15 -0
  40. package/docs/getOptions.md +14 -0
  41. package/docs/getRegion.md +14 -0
  42. package/docs/getThreadHistory.md +17 -0
  43. package/docs/getThreadHistoryDeprecated.md +17 -0
  44. package/docs/getThreadInfo.md +15 -0
  45. package/docs/getThreadInfoDeprecated.md +17 -0
  46. package/docs/getThreadList.md +17 -0
  47. package/docs/getThreadListDeprecated.md +17 -0
  48. package/docs/getThreadPictures.md +17 -0
  49. package/docs/getUID.md +15 -0
  50. package/docs/getUserID.md +15 -0
  51. package/docs/getUserInfo.md +15 -0
  52. package/docs/handleFriendRequest.md +16 -0
  53. package/docs/handleMessageRequest.md +16 -0
  54. package/docs/httpGet.md +15 -0
  55. package/docs/httpPost.md +16 -0
  56. package/docs/httpPostFormData.md +16 -0
  57. package/docs/listenMqtt.md +17 -0
  58. package/docs/listenNotification.md +14 -0
  59. package/docs/logout.md +14 -0
  60. package/docs/markAsDelivered.md +16 -0
  61. package/docs/markAsRead.md +16 -0
  62. package/docs/markAsReadAll.md +14 -0
  63. package/docs/markAsSeen.md +15 -0
  64. package/docs/muteThread.md +16 -0
  65. package/docs/pinMessage.md +17 -0
  66. package/docs/postFormData.md +16 -0
  67. package/docs/refreshFb_dtsg.md +14 -0
  68. package/docs/removeUserFromGroup.md +16 -0
  69. package/docs/resolvePhotoUrl.md +15 -0
  70. package/docs/searchForThread.md +15 -0
  71. package/docs/searchStickers.md +15 -0
  72. package/docs/sendComment.md +16 -0
  73. package/docs/sendMessage.md +16 -0
  74. package/docs/sendMessageMqtt.md +16 -0
  75. package/docs/sendTypingIndicator.md +15 -0
  76. package/docs/setMessageReaction.md +17 -0
  77. package/docs/setMessageReactionMqtt.md +16 -0
  78. package/docs/setPostReaction.md +16 -0
  79. package/docs/setProfileGuard.md +15 -0
  80. package/docs/setStoryReaction.md +16 -0
  81. package/docs/setTitle.md +16 -0
  82. package/docs/shareContact.md +16 -0
  83. package/docs/shareLink.md +16 -0
  84. package/docs/stopListenMqtt.md +8 -0
  85. package/docs/threadColors.md +11 -0
  86. package/docs/unfriend.md +15 -0
  87. package/docs/unsendMessage.md +15 -0
  88. package/docs/uploadAttachment.md +15 -0
  89. package/fca-config.json +7 -0
  90. package/index.d.ts +618 -0
  91. package/index.js +361 -0
  92. package/lib/database/models/index.js +47 -0
  93. package/lib/database/models/thread.js +31 -0
  94. package/lib/database/threadData.js +93 -0
  95. package/lib/logger.js +24 -0
  96. package/lib/login.js +0 -0
  97. package/package.json +90 -0
  98. package/src/addExternalModule.js +19 -0
  99. package/src/addUserToGroup.js +113 -0
  100. package/src/changeAdminStatus.js +79 -0
  101. package/src/changeArchivedStatus.js +55 -0
  102. package/src/changeAvatar.js +126 -0
  103. package/src/changeAvatarV2.js +77 -0
  104. package/src/changeBio.js +77 -0
  105. package/src/changeBlockedStatus.js +47 -0
  106. package/src/changeBlockedStatusMqtt.js +71 -0
  107. package/src/changeCover.js +72 -0
  108. package/src/changeGroupImage.js +132 -0
  109. package/src/changeName.js +79 -0
  110. package/src/changeNickname.js +59 -0
  111. package/src/changeThreadColor.js +65 -0
  112. package/src/changeThreadEmoji.js +55 -0
  113. package/src/changeUsername.js +58 -0
  114. package/src/createCommentPost.js +225 -0
  115. package/src/createNewGroup.js +86 -0
  116. package/src/createPoll.js +71 -0
  117. package/src/createPost.js +276 -0
  118. package/src/deleteMessage.js +56 -0
  119. package/src/deleteThread.js +56 -0
  120. package/src/editMessage.js +57 -0
  121. package/src/follow.js +54 -0
  122. package/src/forwardAttachment.js +60 -0
  123. package/src/getAccess.js +67 -0
  124. package/src/getAvatarUser.js +56 -0
  125. package/src/getBotInitialData.js +37 -0
  126. package/src/getCtx.js +6 -0
  127. package/src/getCurrentUserID.js +7 -0
  128. package/src/getEmojiUrl.js +29 -0
  129. package/src/getFriendsList.js +83 -0
  130. package/src/getMessage.js +796 -0
  131. package/src/getOptions.js +6 -0
  132. package/src/getRegion.js +8 -0
  133. package/src/getThreadHistory.js +666 -0
  134. package/src/getThreadHistoryDeprecated.js +55 -0
  135. package/src/getThreadInfo.js +535 -0
  136. package/src/getThreadInfoDeprecated.js +49 -0
  137. package/src/getThreadList.js +192 -0
  138. package/src/getThreadListDeprecated.js +54 -0
  139. package/src/getThreadPictures.js +79 -0
  140. package/src/getUID.js +67 -0
  141. package/src/getUserID.js +66 -0
  142. package/src/getUserInfo.js +80 -0
  143. package/src/handleFriendRequest.js +61 -0
  144. package/src/handleMessageRequest.js +65 -0
  145. package/src/httpGet.js +57 -0
  146. package/src/httpPost.js +57 -0
  147. package/src/httpPostFormData.js +63 -0
  148. package/src/listenMqtt.js +1039 -0
  149. package/src/listenNotification.js +65 -0
  150. package/src/logout.js +75 -0
  151. package/src/markAsDelivered.js +58 -0
  152. package/src/markAsRead.js +80 -0
  153. package/src/markAsReadAll.js +50 -0
  154. package/src/markAsSeen.js +59 -0
  155. package/src/muteThread.js +52 -0
  156. package/src/pinMessage.js +59 -0
  157. package/src/postFormData.js +46 -0
  158. package/src/refreshFb_dtsg.js +66 -0
  159. package/src/removeUserFromGroup.js +79 -0
  160. package/src/resolvePhotoUrl.js +45 -0
  161. package/src/searchForThread.js +53 -0
  162. package/src/searchStickers.js +51 -0
  163. package/src/sendComment.js +63 -0
  164. package/src/sendMessage.js +328 -0
  165. package/src/sendMessageMqtt.js +316 -0
  166. package/src/sendTypingIndicator.js +103 -0
  167. package/src/setMessageReaction.js +119 -0
  168. package/src/setMessageReactionMqtt.js +61 -0
  169. package/src/setPostReaction.js +109 -0
  170. package/src/setProfileGuard.js +45 -0
  171. package/src/setStoryReaction.js +62 -0
  172. package/src/setTitle.js +86 -0
  173. package/src/shareContact.js +49 -0
  174. package/src/shareLink.js +59 -0
  175. package/src/stopListenMqtt.js +21 -0
  176. package/src/threadColors.js +131 -0
  177. package/src/unfriend.js +52 -0
  178. package/src/unsendMessage.js +49 -0
  179. package/src/uploadAttachment.js +95 -0
  180. package/utils.js +1432 -0
package/index.js ADDED
@@ -0,0 +1,361 @@
1
+ "use strict";
2
+ // Nexus-FCA: Advanced and Safe Facebook Chat API (custom build)
3
+ const utils = require("./utils");
4
+ const log = require("npmlog");
5
+ const { execSync } = require('child_process');
6
+ const { promises: fsPromises, readFileSync } = require('fs');
7
+ const fs = require('fs');
8
+ const axios = require('axios');
9
+ const path = require('path');
10
+ const models = require("./lib/database/models");
11
+ const logger = require("./lib/logger");
12
+ const { safeMode, isUserAllowed, rateLimiter } = require('./utils');
13
+ let checkVerified = null;
14
+ const defaultLogRecordSize = 100;
15
+ log.maxRecordSize = defaultLogRecordSize;
16
+ const defaultConfig = {
17
+ autoUpdate: true,
18
+ mqtt: {
19
+ enabled: true,
20
+ reconnectInterval: 3600,
21
+ }
22
+ };
23
+ const configPath = path.join(process.cwd(), "fca-config.json");
24
+ let config;
25
+ if (!fs.existsSync(configPath)) {
26
+ fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
27
+ config = defaultConfig;
28
+ } else {
29
+ try {
30
+ const fileContent = fs.readFileSync(configPath, 'utf8');
31
+ config = JSON.parse(fileContent);
32
+ config = { ...defaultConfig, ...config };
33
+ } catch (err) {
34
+ logger("Error reading config file, using defaults", "error");
35
+ config = defaultConfig;
36
+ }
37
+ }
38
+ global.fca = {
39
+ config: config
40
+ };
41
+ const Boolean_Option = [
42
+ "online",
43
+ "selfListen",
44
+ "listenEvents",
45
+ "updatePresence",
46
+ "forceLogin",
47
+ "autoMarkDelivery",
48
+ "autoMarkRead",
49
+ "listenTyping",
50
+ "autoReconnect",
51
+ "emitReady",
52
+ ];
53
+ function setOptions(globalOptions, options) {
54
+ Object.keys(options).map(function (key) {
55
+ switch (Boolean_Option.includes(key)) {
56
+ case true: {
57
+ globalOptions[key] = Boolean(options[key]);
58
+ break;
59
+ }
60
+ case false: {
61
+ switch (key) {
62
+ case "pauseLog": {
63
+ if (options.pauseLog) log.pause();
64
+ else log.resume();
65
+ break;
66
+ }
67
+ case "logLevel": {
68
+ log.level = options.logLevel;
69
+ globalOptions.logLevel = options.logLevel;
70
+ break;
71
+ }
72
+ case "logRecordSize": {
73
+ log.maxRecordSize = options.logRecordSize;
74
+ globalOptions.logRecordSize = options.logRecordSize;
75
+ break;
76
+ }
77
+ case "pageID": {
78
+ globalOptions.pageID = options.pageID.toString();
79
+ break;
80
+ }
81
+ case "userAgent": {
82
+ globalOptions.userAgent =
83
+ options.userAgent ||
84
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36";
85
+ break;
86
+ }
87
+ case "proxy": {
88
+ if (typeof options.proxy != "string") {
89
+ delete globalOptions.proxy;
90
+ utils.setProxy();
91
+ } else {
92
+ globalOptions.proxy = options.proxy;
93
+ utils.setProxy(globalOptions.proxy);
94
+ }
95
+ break;
96
+ }
97
+ default: {
98
+ log.warn(
99
+ "setOptions",
100
+ "Unrecognized option given to setOptions: " + key
101
+ );
102
+ break;
103
+ }
104
+ }
105
+ break;
106
+ }
107
+ }
108
+ });
109
+ }
110
+ function buildAPI(globalOptions, html, jar) {
111
+ const cookies = jar.getCookies("https://www.facebook.com");
112
+ const userCookie = cookies.find(c => c.cookieString().startsWith("c_user="));
113
+ const tiktikCookie = cookies.find(c => c.cookieString().startsWith("i_user="));
114
+ if (userCookie.length === 0 && tiktikCookie.length === 0) {
115
+ return log.error('login', "Không tìm thấy cookie cho người dùng, vui lòng kiểm tra lại thông tin đăng nhập")
116
+ } else if (!userCookie && !tiktikCookie) {
117
+ return log.error('login', "Không tìm thấy cookie cho người dùng, vui lòng kiểm tra lại thông tin đăng nhập")
118
+ } else if (html.includes("/checkpoint/block/?next")) {
119
+ return log.error('login', "Appstate die, vui lòng thay cái mới!", 'error');
120
+ }
121
+ const userID = (tiktikCookie || userCookie).cookieString().split("=")[1];
122
+ const i_userID = tiktikCookie ? tiktikCookie.cookieString().split("=")[1] : null;
123
+ logger(`Logged in as ${userID}`, 'info');
124
+ try {
125
+ clearInterval(checkVerified);
126
+ } catch (_) { }
127
+ const clientID = ((Math.random() * 2147483648) | 0).toString(16);
128
+ let mqttEndpoint, region, fb_dtsg, irisSeqID;
129
+ try {
130
+ const endpointMatch = html.match(/"endpoint":"([^"]+)"/);
131
+ if (endpointMatch) {
132
+ mqttEndpoint = endpointMatch[1].replace(/\\\//g, "/");
133
+ const url = new URL(mqttEndpoint);
134
+ region = url.searchParams.get("region")?.toUpperCase() || "PRN";
135
+ }
136
+ logger(`Sever region ${region}`, 'info');
137
+ } catch (e) {
138
+ log.warning("login", "Not MQTT endpoint");
139
+ }
140
+ const tokenMatch = html.match(/DTSGInitialData.*?token":"(.*?)"/);
141
+ if (tokenMatch) {
142
+ fb_dtsg = tokenMatch[1];
143
+ }
144
+ (async () => {
145
+ try {
146
+ await models.sequelize.authenticate();
147
+ await models.syncAll();
148
+ } catch (error) {
149
+ console.error(error);
150
+ console.error('Database connection failed:', error.message);
151
+ }
152
+ })();
153
+ // Professional gradient banner for Nexus-FCA
154
+ logger('═══════════════════════════════════════════════════════════════════════════════', 'info');
155
+ logger(' Welcome to Nexus-FCA - Advanced & Safe Facebook Chat API', 'info');
156
+ logger('═══════════════════════════════════════════════════════════════════════════════', 'info');
157
+ logger(`Nexus-FCA`, 'info');
158
+ const ctx = {
159
+ userID: userID,
160
+ i_userID: i_userID,
161
+ jar: jar,
162
+ clientID: clientID,
163
+ globalOptions: globalOptions,
164
+ loggedIn: true,
165
+ access_token: "NONE",
166
+ clientMutationId: 0,
167
+ mqttClient: undefined,
168
+ lastSeqId: irisSeqID,
169
+ syncToken: undefined,
170
+ mqttEndpoint,
171
+ region,
172
+ firstListen: true,
173
+ fb_dtsg,
174
+ wsReqNumber: 0,
175
+ wsTaskNumber: 0
176
+ };
177
+ const api = {
178
+ setOptions: setOptions.bind(null, globalOptions),
179
+ getAppState: function getAppState() {
180
+ const appState = utils.getAppState(jar);
181
+ return appState.filter(
182
+ (item, index, self) =>
183
+ self.findIndex((t) => {
184
+ return t.key === item.key;
185
+ }) === index
186
+ );
187
+ },
188
+ healthCheck: function(callback) {
189
+ // Simple health check: returns status and safeMode info
190
+ callback(null, {
191
+ status: 'ok',
192
+ safeMode,
193
+ time: new Date().toISOString(),
194
+ userID: ctx.userID || null
195
+ });
196
+ },
197
+ };
198
+ const defaultFuncs = utils.makeDefaults(html, i_userID || userID, ctx);
199
+ require("fs")
200
+ .readdirSync(__dirname + "/src/")
201
+ .filter((v) => v.endsWith(".js"))
202
+ .map(function (v) {
203
+ api[v.replace(".js", "")] = require("./src/" + v)(defaultFuncs, api, ctx);
204
+ });
205
+ api.listen = api.listenMqtt;
206
+ setInterval(async () => {
207
+ api
208
+ .refreshFb_dtsg()
209
+ .then(() => {
210
+ logger("Successfully refreshed fb_dtsg", 'info');
211
+ })
212
+ .catch((err) => {
213
+ console.error("An error occurred while refreshing fb_dtsg", err);
214
+ });
215
+ }, 1000 * 60 * 60 * 24);
216
+ return {
217
+ ctx,
218
+ defaultFuncs,
219
+ api
220
+ };
221
+ }
222
+
223
+ function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
224
+ let mainPromise = null;
225
+ const jar = utils.getJar();
226
+ if (appState) {
227
+ try {
228
+ appState = JSON.parse(appState);
229
+ } catch (e) {
230
+ try {
231
+ appState = appState;
232
+ } catch (e) {
233
+ return callback(new Error("Failed to parse appState"));
234
+ }
235
+ }
236
+
237
+ try {
238
+ appState.forEach(c => {
239
+ const str = `${c.key}=${c.value}; expires=${c.expires}; domain=${c.domain}; path=${c.path};`;
240
+ jar.setCookie(str, "http://" + c.domain);
241
+ });
242
+
243
+ mainPromise = utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
244
+ .then(utils.saveCookies(jar));
245
+ } catch (e) {
246
+ process.exit(0);
247
+ }
248
+ } else {
249
+ mainPromise = utils
250
+ .get("https://www.facebook.com/", null, null, globalOptions, { noRef: true })
251
+ .then(utils.saveCookies(jar))
252
+ .then(makeLogin(jar, email, password, globalOptions, callback, prCallback))
253
+ .then(() => utils.get('https://www.facebook.com/', jar, null, globalOptions).then(utils.saveCookies(jar)));
254
+ }
255
+
256
+ function handleRedirect(res) {
257
+ const reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
258
+ const redirect = reg.exec(res.body);
259
+ if (redirect && redirect[1]) {
260
+ return utils.get(redirect[1], jar, null, globalOptions).then(utils.saveCookies(jar));
261
+ }
262
+ return res;
263
+ }
264
+
265
+ let ctx, api;
266
+ mainPromise = mainPromise
267
+ .then(handleRedirect)
268
+ .then(res => {
269
+ const mobileAgentRegex = /MPageLoadClientMetrics/gs;
270
+ if (!mobileAgentRegex.test(res.body)) {
271
+ globalOptions.userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36";
272
+ return utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true }).then(utils.saveCookies(jar));
273
+ }
274
+ return res;
275
+ })
276
+ .then(handleRedirect)
277
+ .then(res => {
278
+ const html = res.body;
279
+ const Obj = buildAPI(globalOptions, html, jar);
280
+ ctx = Obj.ctx;
281
+ api = Obj.api;
282
+ return res;
283
+ });
284
+
285
+ if (globalOptions.pageID) {
286
+ mainPromise = mainPromise
287
+ .then(() => utils.get(`https://www.facebook.com/${globalOptions.pageID}/messages/?section=messages&subsection=inbox`, jar, null, globalOptions))
288
+ .then(resData => {
289
+ let url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
290
+ url = url.substring(0, url.length - 1);
291
+ return utils.get('https://www.facebook.com' + url, jar, null, globalOptions);
292
+ });
293
+ }
294
+
295
+ mainPromise
296
+ .then(async () => {
297
+ // Version check and auto-update code removed for safety and to prevent error spam.
298
+ logger('Login successful!', '[ Nexus-FCA ] >');
299
+ callback(null, api);
300
+ })
301
+ .catch(e => {
302
+ callback(e);
303
+ });
304
+ }
305
+
306
+ function login(loginData, options, callback) {
307
+ if (
308
+ utils.getType(options) === "Function" ||
309
+ utils.getType(options) === "AsyncFunction"
310
+ ) {
311
+ callback = options;
312
+ options = {};
313
+ }
314
+ const globalOptions = {
315
+ selfListen: false,
316
+ selfListenEvent: false,
317
+ listenEvents: false,
318
+ listenTyping: false,
319
+ updatePresence: false,
320
+ forceLogin: false,
321
+ autoMarkDelivery: true,
322
+ autoMarkRead: false,
323
+ autoReconnect: true,
324
+ logRecordSize: defaultLogRecordSize,
325
+ online: true,
326
+ emitReady: false,
327
+ userAgent:
328
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
329
+ };
330
+ setOptions(globalOptions, options);
331
+ let prCallback = null;
332
+ if (
333
+ utils.getType(callback) !== "Function" &&
334
+ utils.getType(callback) !== "AsyncFunction"
335
+ ) {
336
+ let rejectFunc = null;
337
+ let resolveFunc = null;
338
+ var returnPromise = new Promise(function (resolve, reject) {
339
+ resolveFunc = resolve;
340
+ rejectFunc = reject;
341
+ });
342
+ prCallback = function (error, api) {
343
+ if (error) {
344
+ return rejectFunc(error);
345
+ }
346
+ return resolveFunc(api);
347
+ };
348
+ callback = prCallback;
349
+ }
350
+ loginHelper(
351
+ loginData.appState,
352
+ loginData.email,
353
+ loginData.password,
354
+ globalOptions,
355
+ callback,
356
+ prCallback
357
+ );
358
+ return returnPromise;
359
+ }
360
+
361
+ module.exports = login;
@@ -0,0 +1,47 @@
1
+ const { Sequelize } = require('sequelize');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const databasePath = path.join(process.cwd(), 'Fca_Database');
5
+ if (!fs.existsSync(databasePath)) {
6
+ fs.mkdirSync(databasePath, { recursive: true });
7
+ }
8
+ const sequelize = new Sequelize({
9
+ dialect: 'sqlite',
10
+ storage: path.join(databasePath, 'database.sqlite'),
11
+ logging: false,
12
+ pool: {
13
+ max: 5,
14
+ min: 0,
15
+ acquire: 30000,
16
+ idle: 10000
17
+ },
18
+ retry: {
19
+ max: 3
20
+ },
21
+ dialectOptions: {
22
+ timeout: 5000
23
+ },
24
+ isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED
25
+ });
26
+ const models = {};
27
+ fs.readdirSync(__dirname).filter(file => file.endsWith('.js') && file !== 'index.js').forEach(file => {
28
+ const model = require(path.join(__dirname, file))(sequelize);
29
+ models[model.name] = model;
30
+ });
31
+ Object.keys(models).forEach(modelName => {
32
+ if (models[modelName].associate) {
33
+ models[modelName].associate(models);
34
+ }
35
+ });
36
+ models.sequelize = sequelize;
37
+ models.Sequelize = Sequelize;
38
+ models.syncAll = async () => {
39
+ try {
40
+ await sequelize.sync({ force: false });
41
+ } catch (error) {
42
+ console.error('Failed to synchronize models:', error);
43
+ throw error;
44
+ }
45
+ };
46
+
47
+ module.exports = models;
@@ -0,0 +1,31 @@
1
+ module.exports = function(sequelize) {
2
+ const { Model, DataTypes } = require("sequelize");
3
+
4
+ class Thread extends Model {}
5
+
6
+ Thread.init(
7
+ {
8
+ num: {
9
+ type: DataTypes.INTEGER,
10
+ allowNull: false,
11
+ autoIncrement: true,
12
+ primaryKey: true,
13
+ },
14
+ threadID: {
15
+ type: DataTypes.STRING,
16
+ allowNull: false,
17
+ unique: true,
18
+ },
19
+ data: {
20
+ type: DataTypes.JSONB,
21
+ allowNull: true,
22
+ }
23
+ },
24
+ {
25
+ sequelize,
26
+ modelName: "Thread",
27
+ timestamps: true,
28
+ }
29
+ );
30
+ return Thread;
31
+ };
@@ -0,0 +1,93 @@
1
+ const { Thread } = require('./models');
2
+
3
+ const validateThreadID = (threadID) => {
4
+ if (typeof threadID !== 'string' && typeof threadID !== 'number') {
5
+ throw new Error('Invalid threadID: must be a string or number.');
6
+ }
7
+ return String(threadID);
8
+ };
9
+ const validateData = (data) => {
10
+ if (!data || typeof data !== 'object' || Array.isArray(data)) {
11
+ throw new Error('Invalid data: must be a non-empty object.');
12
+ }
13
+ };
14
+
15
+ module.exports = function (bot) {
16
+ return {
17
+ async create(threadID, data) {
18
+ try {
19
+ let thread = await Thread.findOne({ where: { threadID } });
20
+ if (thread) {
21
+ return { thread: thread.get(), created: false };
22
+ }
23
+ thread = await Thread.create({ threadID, ...data });
24
+ return { thread: thread.get(), created: true };
25
+ } catch (error) {
26
+ throw new Error(`Failed to create thread: ${error.message}`);
27
+ }
28
+ },
29
+
30
+ async get(threadID) {
31
+ try {
32
+ threadID = validateThreadID(threadID);
33
+ const thread = await Thread.findOne({ where: { threadID } });
34
+ return thread ? thread.get() : null;
35
+ } catch (error) {
36
+ throw new Error(`Failed to get thread: ${error.message}`);
37
+ }
38
+ },
39
+
40
+ async update(threadID, data) {
41
+ try {
42
+ threadID = validateThreadID(threadID);
43
+ validateData(data);
44
+ const thread = await Thread.findOne({ where: { threadID } });
45
+
46
+ if (thread) {
47
+ await thread.update(data);
48
+ return { thread: thread.get(), created: false };
49
+ } else {
50
+ const newThread = await Thread.create({ ...data, threadID });
51
+ return { thread: newThread.get(), created: true };
52
+ }
53
+ } catch (error) {
54
+ throw new Error(`Failed to update thread: ${error.message}`);
55
+ }
56
+ },
57
+
58
+ async del(threadID) {
59
+ try {
60
+ if (!threadID) {
61
+ throw new Error('threadID is required and cannot be undefined');
62
+ }
63
+ threadID = validateThreadID(threadID);
64
+ if (!threadID) {
65
+ throw new Error('Invalid threadID');
66
+ }
67
+ const result = await Thread.destroy({ where: { threadID } });
68
+ if (result === 0) {
69
+ throw new Error('No thread found with the specified threadID');
70
+ }
71
+ return result;
72
+ } catch (error) {
73
+ throw new Error(`Failed to delete thread: ${error.message}`);
74
+ }
75
+ },
76
+ async delAll() {
77
+ try {
78
+ return await Thread.destroy({ where: {} });
79
+ } catch (error) {
80
+ throw new Error(`Failed to delete all threads: ${error.message}`);
81
+ }
82
+ },
83
+ async getAll(keys = null) {
84
+ try {
85
+ const attributes = typeof keys === 'string' ? [keys] : Array.isArray(keys) ? keys : undefined;
86
+ const threads = await Thread.findAll({ attributes });
87
+ return threads.map(thread => thread.get());
88
+ } catch (error) {
89
+ throw new Error(`Failed to get all threads: ${error.message}`);
90
+ }
91
+ },
92
+ };
93
+ };
package/lib/logger.js ADDED
@@ -0,0 +1,24 @@
1
+ const chalk = require('chalk');
2
+ const gradient = require('gradient-string');
3
+
4
+ // Use a professional gradient for info logs
5
+ const infoGradient = gradient(['#00c6ff', '#0072ff']); // blue-cyan gradient
6
+ const warnColor = chalk.yellow.bold;
7
+ const errorColor = chalk.red.bold;
8
+
9
+ module.exports = (text, type) => {
10
+ switch (type) {
11
+ case "warn":
12
+ process.stderr.write(warnColor(`\r[ NEXUS-FCA WARN ] > ${text}`) + '\n');
13
+ break;
14
+ case "error":
15
+ process.stderr.write(errorColor(`\r[ NEXUS-FCA ERROR ] > ${text}`) + '\n');
16
+ break;
17
+ case "info":
18
+ process.stderr.write(infoGradient(`\r[ NEXUS-FCA ] > ${text}`) + '\n');
19
+ break;
20
+ default:
21
+ process.stderr.write(infoGradient(`\r[ NEXUS-FCA ] > ${text}`) + '\n');
22
+ break;
23
+ }
24
+ };
package/lib/login.js ADDED
File without changes
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "nexus-fca",
3
+ "version": "1.0.0",
4
+ "description": "A modern, safe, and advanced Facebook Chat API for Node.js. Messenger automation, bots, and integrations made easy.",
5
+ "main": "index.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/AlAminNexus/nexus-fca.git"
9
+ },
10
+ "author": "Al Amin",
11
+ "license": "MIT",
12
+ "dependencies": {
13
+ "axios": "^1.8.4",
14
+ "bluebird": "^3.7.2",
15
+ "chalk": "^4.1.2",
16
+ "cheerio": "^1.0.0-rc.10",
17
+ "duplexify": "^4.1.3",
18
+ "gradient-string": "^2.0.2",
19
+ "https-proxy-agent": "^4.0.0",
20
+ "mqtt": "^4.3.8",
21
+ "npmlog": "^1.2.0",
22
+ "request": "^2.53.0",
23
+ "sequelize": "^6.37.6",
24
+ "sqlite3": "^5.1.7",
25
+ "totp-generator": "^1.0.0",
26
+ "ws": "^8.18.1"
27
+ },
28
+ "devDependencies": {
29
+ "eslint": "^7.5.0",
30
+ "mocha": "^10.2.0",
31
+ "prettier": "^1.11.1"
32
+ },
33
+ "scripts": {
34
+ "test": "mocha",
35
+ "lint": "eslint **/*.js",
36
+ "prettier": "prettier utils.js src/* --write"
37
+ },
38
+ "keywords": [
39
+ "facebook",
40
+ "chat",
41
+ "api",
42
+ "fca",
43
+ "facebook-chat-api"
44
+ ],
45
+ "engines": {
46
+ "node": ">=10.x"
47
+ },
48
+ "eslintConfig": {
49
+ "env": {
50
+ "es6": true,
51
+ "es2017": true,
52
+ "node": true
53
+ },
54
+ "extends": "eslint:recommended",
55
+ "parserOptions": {
56
+ "sourceType": "module"
57
+ },
58
+ "rules": {
59
+ "linebreak-style": [
60
+ "error",
61
+ "unix"
62
+ ],
63
+ "semi": [
64
+ "error",
65
+ "always"
66
+ ],
67
+ "no-unused-vars": [
68
+ 1,
69
+ {
70
+ "argsIgnorePattern": "^_",
71
+ "varsIgnorePattern": "^_"
72
+ }
73
+ ],
74
+ "no-empty": [
75
+ "error",
76
+ {
77
+ "allowEmptyCatch": true
78
+ }
79
+ ]
80
+ }
81
+ },
82
+ "types": "index.d.ts",
83
+ "homepage": "https://github.com/Nexus-016/Nexus-fCA#readme",
84
+ "bugs": {
85
+ "url": "https://github.com/Nexus-016/Nexus-fCA/issues"
86
+ },
87
+ "directories": {
88
+ "test": "test"
89
+ }
90
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ const utils = require("../utils");
4
+
5
+ module.exports = function (defaultFuncs, api, ctx) {
6
+ return function addExternalModule(moduleObj) {
7
+ if (utils.getType(moduleObj) == "Object") {
8
+ for (const apiName in moduleObj) {
9
+ if (utils.getType(moduleObj[apiName]) == "Function") {
10
+ api[apiName] = moduleObj[apiName](defaultFuncs, api, ctx);
11
+ } else {
12
+ throw new Error(`Item "${apiName}" in moduleObj must be a function, not ${utils.getType(moduleObj[apiName])}!`);
13
+ }
14
+ }
15
+ } else {
16
+ throw new Error(`moduleObj must be an object, not ${utils.getType(moduleObj)}!`);
17
+ }
18
+ };
19
+ };