stfca 1.0.19 → 1.0.21

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
@@ -4,6 +4,8 @@ var utils = require("./utils");
4
4
  var cheerio = require("cheerio");
5
5
  var log = require("npmlog");
6
6
  var { checkForFCAUpdate } = require("./checkUpdate");
7
+ const fs = require('fs');
8
+ const path = require('path');
7
9
  /*var { getThemeColors } = require("../../func/utils/log.js");
8
10
  var logger = require("../../func/utils/log.js");
9
11
  var { cra, cv, cb, co } = getThemeColors();*/
@@ -188,6 +190,16 @@ function buildAPI(globalOptions, html, jar) {
188
190
  reqCallbacks: {},
189
191
  threadTypes: {} // Store thread type (dm/group) for each thread
190
192
  };
193
+ let config = { enableTypingIndicator: false, typingDuration: 4000 };
194
+ try {
195
+ const configPath = path.join(__dirname, 'config.json');
196
+ if (fs.existsSync(configPath)) {
197
+ config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
198
+ }
199
+ } catch (e) {
200
+ console.log('Error loading config.json:', e);
201
+ }
202
+ ctx.config = config;
191
203
  var api = {
192
204
  setOptions: setOptions.bind(null, globalOptions),
193
205
  getAppState: () => utils.getAppState(jar),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stfca",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
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": [
package/src/OldMessage.js CHANGED
@@ -311,19 +311,43 @@ module.exports = function (defaultFuncs, api, ctx) {
311
311
  };
312
312
  // console.log(form)
313
313
 
314
- handleLocation(msg, form, callback, () =>
315
- handleSticker(msg, form, callback, () =>
316
- handleAttachment(msg, form, callback, () =>
317
- handleUrl(msg, form, callback, () =>
318
- handleEmoji(msg, form, callback, () =>
319
- handleMention(msg, form, callback, () =>
320
- send(form, threadID, messageAndOTID, callback, isGroup)
314
+ if (isSingleUser && ctx.config.enableTypingIndicator) {
315
+ const stopTyping = api.sendTypingIndicator(threadID, () => {}, false);
316
+ const originalCallback = callback;
317
+ callback = (err, data) => {
318
+ stopTyping(() => {});
319
+ originalCallback(err, data);
320
+ };
321
+ setTimeout(() => {
322
+ handleLocation(msg, form, callback, () =>
323
+ handleSticker(msg, form, callback, () =>
324
+ handleAttachment(msg, form, callback, () =>
325
+ handleUrl(msg, form, callback, () =>
326
+ handleEmoji(msg, form, callback, () =>
327
+ handleMention(msg, form, callback, () =>
328
+ sendContent(form, threadID, isSingleUser, messageAndOTID, callback)
329
+ )
330
+ )
331
+ )
332
+ )
333
+ )
334
+ );
335
+ }, ctx.config.typingDuration);
336
+ } else {
337
+ handleLocation(msg, form, callback, () =>
338
+ handleSticker(msg, form, callback, () =>
339
+ handleAttachment(msg, form, callback, () =>
340
+ handleUrl(msg, form, callback, () =>
341
+ handleEmoji(msg, form, callback, () =>
342
+ handleMention(msg, form, callback, () =>
343
+ sendContent(form, threadID, isSingleUser, messageAndOTID, callback)
344
+ )
345
+ )
321
346
  )
322
347
  )
323
348
  )
324
- )
325
- )
326
- );
349
+ );
350
+ }
327
351
  return returnPromise;
328
352
  };
329
353
  };
@@ -234,10 +234,21 @@ module.exports = (defaultFuncs, api, ctx) => {
234
234
  form["profile_xmd[" + i + "][type]"] = "p";
235
235
  }
236
236
  }
237
- const result = await sendContent(form, threadID, isSingleUser, messageAndOTID);
238
- if (callback && typeof callback === "function") {
239
- callback(null, result);
237
+ if (isSingleUser && ctx.config.enableTypingIndicator) {
238
+ const stopTyping = api.sendTypingIndicator(threadID, () => {}, false);
239
+ await utils.delay(ctx.config.typingDuration);
240
+ const result = await sendContent(form, threadID, isSingleUser, messageAndOTID);
241
+ stopTyping(() => {});
242
+ if (callback && typeof callback === "function") {
243
+ callback(null, result);
244
+ }
245
+ return result;
246
+ } else {
247
+ const result = await sendContent(form, threadID, isSingleUser, messageAndOTID);
248
+ if (callback && typeof callback === "function") {
249
+ callback(null, result);
250
+ }
251
+ return result;
240
252
  }
241
- return result;
242
253
  };
243
254
  };
@@ -8,269 +8,96 @@
8
8
  * 🕊️ Respect the creator & give proper credits if reused.
9
9
  * ===========================================================
10
10
  */
11
- "use strict";
11
+ 'use strict';
12
12
 
13
- var utils = require("../utils");
14
- var log = require("npmlog");
13
+ const utils = require('../utils');
14
+ const log = require('npmlog');
15
15
 
16
16
  module.exports = function (defaultFuncs, api, ctx) {
17
- /** Developed by Sheikh Tamim | GitHub: sheikhtamimlover | Instagram: @sheikh.tamim_lover */
18
- return function setThreadTheme(threadID, themeData, callback) {
19
- var resolveFunc = function () { };
20
- var rejectFunc = function () { };
21
- var returnPromise = new Promise(function (resolve, reject) {
22
- resolveFunc = resolve;
23
- rejectFunc = reject;
24
- });
25
-
26
- if (!callback) {
27
- callback = function (err, data) {
28
- if (err) return rejectFunc(err);
29
- resolveFunc(data);
30
- };
31
- }
32
-
33
- if (!threadID) {
34
- return callback({ error: "threadID is required" });
35
- }
36
-
37
- async function updateThreadTheme() {
38
- try {
39
- const timestamp = Date.now();
40
-
41
- // Step 1: Load theme bootloader modules
42
- const moduleParams = new URLSearchParams({
43
- modules: "LSUpdateThreadTheme,LSUpdateThreadCustomEmoji,LSUpdateThreadThemePayloadCacheKey",
44
- __aaid: 0,
45
- __user: ctx.userID,
46
- __a: 1,
47
- __req: utils.getSignatureID(),
48
- __hs: "20352.HYP:comet_pkg.2.1...0",
49
- dpr: 1,
50
- __ccg: "EXCELLENT",
51
- __rev: "1027396270",
52
- __s: utils.getSignatureID(),
53
- __hsi: "7552524636527201016",
54
- __comet_req: 15,
55
- fb_dtsg_ag: ctx.fb_dtsg,
56
- jazoest: ctx.ttstamp,
57
- __spin_r: "1027396270",
58
- __spin_b: "trunk",
59
- __spin_t: timestamp,
60
- __crn: "comet.fbweb.MWInboxHomeRoute"
61
- });
62
-
63
- await defaultFuncs
64
- .get("https://www.facebook.com/ajax/bootloader-endpoint/?" + moduleParams.toString(), ctx.jar)
65
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs));
66
-
67
- // Step 2: Get available themes first
68
- let availableThemes = [];
69
- try {
70
- const themeForm = {
71
- av: ctx.userID,
72
- __aaid: 0,
73
- __user: ctx.userID,
74
- __a: 1,
75
- __req: utils.getSignatureID(),
76
- __hs: "20352.HYP:comet_pkg.2.1...0",
77
- dpr: 1,
78
- __ccg: "EXCELLENT",
79
- __rev: "1027396270",
80
- __s: utils.getSignatureID(),
81
- __hsi: "7552524636527201016",
82
- __comet_req: 15,
83
- fb_dtsg: ctx.fb_dtsg,
84
- jazoest: ctx.ttstamp,
85
- lsd: ctx.fb_dtsg,
86
- __spin_r: "1027396270",
87
- __spin_b: "trunk",
88
- __spin_t: timestamp,
89
- __crn: "comet.fbweb.MWInboxHomeRoute",
90
- qpl_active_flow_ids: "25308101",
91
- fb_api_caller_class: "RelayModern",
92
- fb_api_req_friendly_name: "MWPThreadThemeQuery_AllThemesQuery",
93
- variables: JSON.stringify({
94
- "version": "default"
95
- }),
96
- server_timestamps: true,
97
- doc_id: "24474714052117636"
98
- };
99
-
100
- const themeResult = await defaultFuncs
101
- .post("https://www.facebook.com/api/graphql/", ctx.jar, themeForm)
102
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs));
103
-
104
- if (themeResult && themeResult.data && themeResult.data.messenger_thread_themes) {
105
- availableThemes = themeResult.data.messenger_thread_themes;
106
- }
107
- } catch (e) {
108
- log.warn("setThreadTheme", "Could not fetch available themes, proceeding with theme update");
109
- }
110
-
111
- // Step 3: Determine theme ID based on input
112
- let themeId = null;
113
- let customEmoji = "👍";
114
-
115
- if (typeof themeData === "string") {
116
- // If it's a string, try to find matching theme
117
- if (themeData.match(/^[0-9]+$/)) {
118
- // Numeric theme ID
119
- themeId = themeData;
120
- } else {
121
- // Search by theme name/description
122
- const foundTheme = availableThemes.find(theme =>
123
- theme.accessibility_label &&
124
- theme.accessibility_label.toLowerCase().includes(themeData.toLowerCase())
125
- );
126
- if (foundTheme) {
127
- themeId = foundTheme.id;
128
- } else {
129
- // Fallback color mapping
130
- const colorMap = {
131
- blue: "196241301102133",
132
- purple: "370940413392601",
133
- green: "169463077092846",
134
- pink: "230032715012014",
135
- orange: "175615189761153",
136
- red: "2136751179887052",
137
- yellow: "2058653964378557",
138
- teal: "417639218648241",
139
- black: "539927563794799",
140
- white: "2873642392710980",
141
- default: "196241301102133"
142
- };
143
- themeId = colorMap[themeData.toLowerCase()] || colorMap.default;
144
- }
145
- }
146
- } else if (typeof themeData === "object" && themeData !== null) {
147
- themeId = themeData.themeId || themeData.theme_id || themeData.id;
148
- customEmoji = themeData.emoji || themeData.customEmoji || "👍";
149
- }
150
-
151
- if (!themeId) {
152
- themeId = "196241301102133"; // Default blue theme
153
- }
154
-
155
- // Step 4: Use direct bootloader approach for theme update
156
- try {
157
- // First try with the legacy changeThreadColor approach
158
- const legacyForm = {
159
- dpr: 1,
160
- queries: JSON.stringify({
161
- o0: {
162
- doc_id: "1727493033983591",
163
- query_params: {
164
- data: {
165
- actor_id: ctx.userID,
166
- client_mutation_id: "0",
167
- source: "SETTINGS",
168
- theme_id: themeId,
169
- thread_id: threadID,
170
- },
171
- },
172
- },
173
- }),
174
- };
175
-
176
- const legacyResult = await defaultFuncs
177
- .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, legacyForm)
178
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs));
179
-
180
- if (legacyResult && !legacyResult[0]?.o0?.errors) {
181
- return callback(null, {
182
- threadID: threadID,
183
- themeId: themeId,
184
- customEmoji: customEmoji,
185
- timestamp: timestamp,
186
- success: true,
187
- method: "legacy",
188
- availableThemes: availableThemes.length > 0 ? availableThemes.map(t => ({
189
- id: t.id,
190
- name: t.accessibility_label,
191
- description: t.description
192
- })) : null
193
- });
194
- }
195
- } catch (legacyErr) {
196
- log.warn("setThreadTheme", "Legacy method failed, trying alternative approach");
197
- }
198
-
199
- // Step 5: Try alternative GraphQL mutation with updated doc_id
200
- const alternativeForm = {
201
- av: ctx.userID,
202
- __aaid: 0,
203
- __user: ctx.userID,
204
- __a: 1,
205
- __req: utils.getSignatureID(),
206
- __hs: "20352.HYP:comet_pkg.2.1...0",
207
- dpr: 1,
208
- __ccg: "EXCELLENT",
209
- __rev: "1027396270",
210
- __s: utils.getSignatureID(),
211
- __hsi: "7552524636527201016",
212
- __comet_req: 15,
213
- fb_dtsg: ctx.fb_dtsg,
214
- jazoest: ctx.ttstamp,
215
- lsd: ctx.fb_dtsg,
216
- __spin_r: "1027396270",
217
- __spin_b: "trunk",
218
- __spin_t: timestamp,
219
- __crn: "comet.fbweb.MWInboxHomeRoute",
220
- fb_api_caller_class: "RelayModern",
221
- fb_api_req_friendly_name: "MessengerThreadThemeUpdateMutation",
222
- variables: JSON.stringify({
223
- "input": {
224
- "actor_id": ctx.userID,
225
- "client_mutation_id": Math.floor(Math.random() * 10000).toString(),
226
- "source": "SETTINGS",
227
- "thread_id": threadID.toString(),
228
- "theme_id": themeId.toString(),
229
- "custom_emoji": customEmoji
230
- }
231
- }),
232
- server_timestamps: true,
233
- doc_id: "9734829906576883" // Updated doc_id based on working API
234
- };
235
-
236
- const result = await defaultFuncs
237
- .post("https://www.facebook.com/api/graphql/", ctx.jar, alternativeForm)
238
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs));
239
-
240
- if (result && result.errors && result.errors.length > 0) {
241
- throw new Error("GraphQL Error: " + JSON.stringify(result.errors));
242
- }
243
-
244
- // Check if the mutation was successful
245
- if (result && result.data && result.data.messenger_thread_theme_update) {
246
- const updateResult = result.data.messenger_thread_theme_update;
247
- if (updateResult.errors && updateResult.errors.length > 0) {
248
- throw new Error("Theme Update Error: " + JSON.stringify(updateResult.errors));
249
- }
250
- }
251
-
252
- return callback(null, {
253
- threadID: threadID,
254
- themeId: themeId,
255
- customEmoji: customEmoji,
256
- timestamp: timestamp,
257
- success: true,
258
- method: "graphql",
259
- availableThemes: availableThemes.length > 0 ? availableThemes.map(t => ({
260
- id: t.id,
261
- name: t.accessibility_label,
262
- description: t.description
263
- })) : null
264
- });
265
-
266
- } catch (err) {
267
- log.error("setThreadTheme", err);
268
- return callback(err);
269
- }
270
- }
271
-
272
- updateThreadTheme();
273
- return returnPromise;
274
- };
17
+ /** Developed by Sheikh Tamim | GitHub: sheikhtamimlover | Instagram: @sheikh.tamim_lover */
18
+ return function setThreadTheme(threadID, themeFBID, callback) {
19
+ var resolveFunc = function () { };
20
+ var rejectFunc = function () { };
21
+ var returnPromise = new Promise(function (resolve, reject) {
22
+ resolveFunc = resolve;
23
+ rejectFunc = reject;
24
+ });
25
+
26
+ if (!callback) {
27
+ callback = function (err, data) {
28
+ if (err) return rejectFunc(err);
29
+ resolveFunc(data);
30
+ };
31
+ }
32
+
33
+ if (!ctx.mqttClient) {
34
+ return callback(new Error('Not connected to MQTT'));
35
+ }
36
+
37
+ ctx.wsReqNumber += 1;
38
+ let baseTaskNumber = ++ctx.wsTaskNumber;
39
+
40
+ const makeTask = (label, queueName, extraPayload = {}) => ({
41
+ failure_count: null,
42
+ label: String(label),
43
+ payload: JSON.stringify({
44
+ thread_key: threadID,
45
+ theme_fbid: themeFBID,
46
+ sync_group: 1,
47
+ ...extraPayload,
48
+ }),
49
+ queue_name: typeof queueName === 'string' ? queueName : JSON.stringify(queueName),
50
+ task_id: baseTaskNumber++,
51
+ });
52
+
53
+ const messages = [
54
+ {
55
+ label: 1013,
56
+ queue: ['ai_generated_theme', String(threadID)],
57
+ },
58
+ {
59
+ label: 1037,
60
+ queue: ['msgr_custom_thread_theme', String(threadID)],
61
+ },
62
+ {
63
+ label: 1028,
64
+ queue: ['thread_theme_writer', String(threadID)],
65
+ },
66
+ {
67
+ label: 43,
68
+ queue: 'thread_theme',
69
+ extra: { source: null, payload: null },
70
+ },
71
+ ].map(({ label, queue, extra }) => {
72
+ ctx.wsReqNumber += 1;
73
+ return {
74
+ app_id: '772021112871879',
75
+ payload: JSON.stringify({
76
+ epoch_id: parseInt(utils.generateOfflineThreadingID()),
77
+ tasks: [makeTask(label, queue, extra)],
78
+ version_id: '24227364673632991',
79
+ }),
80
+ //pwa_version: '1',
81
+ request_id: ctx.wsReqNumber,
82
+ type: 3,
83
+ };
84
+ });
85
+
86
+ try {
87
+ messages.forEach((msg, idx) => {
88
+ ctx.mqttClient.publish(
89
+ '/ls_req',
90
+ JSON.stringify(msg),
91
+ { qos: 1, retain: false },
92
+ idx === messages.length - 1 && callback ? callback : undefined
93
+ );
94
+ });
95
+ } catch (err) {
96
+ if (callback) callback(err);
97
+ else throw err;
98
+ }
99
+
100
+ return returnPromise;
101
+ };
275
102
  };
276
103
  /** Developed by Sheikh Tamim | GitHub: sheikhtamimlover | Please give credits if reused. */
package/utils.js CHANGED
@@ -2878,6 +2878,10 @@ function cleanHTML(text) {
2878
2878
  return text;
2879
2879
  }
2880
2880
 
2881
+ function delay(ms) {
2882
+ return new Promise(resolve => setTimeout(resolve, ms));
2883
+ }
2884
+
2881
2885
  module.exports = {
2882
2886
  cleanHTML,
2883
2887
  isReadableStream: isReadableStream,
@@ -2926,5 +2930,6 @@ module.exports = {
2926
2930
  getJazoest,
2927
2931
  getEventTime,
2928
2932
  getSessionID,
2929
- getFormData
2933
+ getFormData,
2934
+ delay
2930
2935
  };