stfca 1.0.9 → 1.0.11

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 CHANGED
@@ -306,21 +306,13 @@ api.setOptions({
306
306
 
307
307
  ## 🛠️ Projects Using This API
308
308
 
309
- - **[c3c](https://github.com/lequanglam/c3c)** - Customizable bot with plugins, supports Facebook & Discord
310
- - **[Miraiv2](https://github.com/miraiPr0ject/miraiv2)** - Simple Facebook Messenger Bot
311
- - **[Messer](https://github.com/mjkaufer/Messer)** - Command-line messaging for Facebook Messenger
312
- - **[messen](https://github.com/tomquirk/messen)** - Rapidly build Facebook Messenger apps in Node.js
313
- - **[Concierge](https://github.com/concierge/Concierge)** - Highly modular chat bot with built-in package manager
314
- - **[Marc Zuckerbot](https://github.com/bsansouci/marc-zuckerbot)** - Facebook chat bot
315
- - **[Botyo](https://github.com/ivkos/botyo)** - Modular bot for group chat rooms
316
- - **[matrix-puppet-facebook](https://github.com/matrix-hacks/matrix-puppet-facebook)** - Facebook bridge for Matrix
317
- - **[Miscord](https://github.com/Bjornskjald/miscord)** - Easy-to-use Facebook bridge for Discord
318
- - **[chat-bridge](https://github.com/rexx0520/chat-bridge)** - Messenger, Telegram and IRC chat bridge
319
- - **[Botium](https://github.com/codeforequity-at/botium-core)** - The Selenium for Chatbots
320
- - **[Messenger-CLI](https://github.com/AstroCB/Messenger-CLI)** - Command-line interface for Facebook Messenger
321
- - **[BotCore](https://github.com/AstroCB/BotCore)** - Tools for writing and managing Facebook Messenger bots
322
-
323
- [See more projects...](https://github.com/Donix-VN/fca-unofficial#projects-using-this-api)
309
+ ### Primary Project
310
+
311
+ - **[ST-BOT](https://github.com/sheikhtamimlover/ST-BOT)** - Enhanced version of GoatBot V2, a powerful and customizable Facebook Messenger bot with advanced features, plugin support, and automatic updates. This is the main project that ST-FCA was designed for.
312
+
313
+ ### Other Use Cases
314
+
315
+ ST-FCA can be used for any Facebook Messenger bot project or automation tool. If you want to create your own messenger bot or use this API for other purposes, feel free to integrate it into your project.
324
316
 
325
317
  ## 📚 Full API Documentation
326
318
 
package/checkUpdate.js CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  const axios = require('axios');
3
2
  const { execSync } = require('child_process');
4
3
  const fs = require('fs');
@@ -44,6 +43,9 @@ async function checkForFCAUpdate() {
44
43
  // Update npm package
45
44
  await updateNpmPackage(latestVersion);
46
45
 
46
+ // Update version in user's package.json
47
+ await updateUserPackageJson(latestVersion);
48
+
47
49
  console.log('\x1b[32m%s\x1b[0m', '✅ ST-FCA updated successfully!');
48
50
  console.log('\x1b[33m%s\x1b[0m', '🔄 Restarting to apply changes...');
49
51
 
@@ -65,162 +67,46 @@ async function checkForFCAUpdate() {
65
67
 
66
68
  async function updateNpmPackage(version) {
67
69
  try {
68
- console.log('\x1b[36m%s\x1b[0m', '📦 Running npm install stfca@latest...');
70
+ console.log('\x1b[36m%s\x1b[0m', `📦 Running npm install stfca@${version}...`);
69
71
 
70
72
  // Execute npm install command
71
- execSync('npm install stfca@latest --save', {
73
+ execSync(`npm install stfca@${version} --save`, {
72
74
  cwd: process.cwd(),
73
75
  stdio: 'inherit'
74
76
  });
75
77
 
76
- console.log('\x1b[32m%s\x1b[0m', '✅ Package updated successfully!');
78
+ console.log('\x1b[32m%s\x1b[0m', '✅ Package installed successfully!');
77
79
  return true;
78
80
  } catch (error) {
79
- console.log('\x1b[31m%s\x1b[0m', '❌ Failed to update package:', error.message);
80
- throw error;
81
- }
82
- }
83
-
84
- async function performComprehensiveUpdate() {
85
- try {
86
- // Step 1: Get the complete file tree from GitHub
87
- console.log('\x1b[36m%s\x1b[0m', '📂 Fetching complete file structure...');
88
- const fileTree = await getGitHubFileTree();
89
-
90
- // Step 2: Get local files
91
- const localFiles = getLocalFiles();
92
-
93
- // Step 3: Download/Update all files from GitHub
94
- console.log('\x1b[36m%s\x1b[0m', '⬇️ Downloading files...');
95
- for (const file of fileTree) {
96
- await downloadFile(file);
97
- }
98
-
99
- // Step 4: Delete files that don't exist in the latest version
100
- console.log('\x1b[36m%s\x1b[0m', '🗑️ Cleaning up old files...');
101
- const githubFilePaths = fileTree.map(f => f.path);
102
- for (const localFile of localFiles) {
103
- if (!githubFilePaths.includes(localFile) && !shouldKeepFile(localFile)) {
104
- deleteLocalFile(localFile);
105
- }
106
- }
107
-
108
- console.log('\x1b[32m%s\x1b[0m', '✅ All files synchronized!');
109
- } catch (error) {
110
- console.log('\x1b[31m%s\x1b[0m', '❌ Update failed:', error.message);
81
+ console.log('\x1b[31m%s\x1b[0m', '❌ Failed to install package:', error.message);
111
82
  throw error;
112
83
  }
113
84
  }
114
85
 
115
- async function getGitHubFileTree() {
86
+ async function updateUserPackageJson(version) {
116
87
  try {
117
- const { data } = await axios.get(
118
- 'https://api.github.com/repos/sheikhtamimlover/ST-FCA/git/trees/main?recursive=1'
119
- );
120
-
121
- // Filter only files (not directories)
122
- return data.tree
123
- .filter(item => item.type === 'blob')
124
- .filter(item => !item.path.startsWith('.git'))
125
- .filter(item => !shouldIgnoreFile(item.path));
126
- } catch (error) {
127
- console.log('\x1b[31m%s\x1b[0m', '❌ Failed to fetch file tree:', error.message);
128
- throw error;
129
- }
130
- }
88
+ const userPackageJsonPath = path.join(process.cwd(), 'package.json');
131
89
 
132
- function getLocalFiles() {
133
- const files = [];
134
-
135
- function walkDir(dir, baseDir = '') {
136
- const items = fs.readdirSync(dir);
137
-
138
- for (const item of items) {
139
- const fullPath = path.join(dir, item);
140
- const relativePath = baseDir ? path.join(baseDir, item) : item;
141
-
142
- if (shouldIgnoreFile(relativePath)) continue;
143
-
144
- const stat = fs.statSync(fullPath);
145
-
146
- if (stat.isDirectory()) {
147
- walkDir(fullPath, relativePath);
148
- } else {
149
- files.push(relativePath.replace(/\\/g, '/'));
150
- }
90
+ if (!fs.existsSync(userPackageJsonPath)) {
91
+ console.log('\x1b[33m%s\x1b[0m', '⚠️ No package.json found in user project');
92
+ return;
151
93
  }
152
- }
153
-
154
- walkDir(__dirname);
155
- return files;
156
- }
157
94
 
158
- function shouldIgnoreFile(filePath) {
159
- const ignorePatterns = [
160
- 'node_modules',
161
- '.git',
162
- '.env',
163
- 'appstate.json',
164
- 'fbstate.json',
165
- 'package-lock.json',
166
- '.replit',
167
- 'replit.nix',
168
- '.config',
169
- 'generated-icon.png'
170
- ];
171
-
172
- return ignorePatterns.some(pattern => filePath.includes(pattern));
173
- }
174
-
175
- function shouldKeepFile(filePath) {
176
- const keepPatterns = [
177
- 'node_modules',
178
- '.env',
179
- 'appstate.json',
180
- 'fbstate.json',
181
- 'package-lock.json',
182
- '.replit',
183
- 'replit.nix',
184
- '.config'
185
- ];
186
-
187
- return keepPatterns.some(pattern => filePath.includes(pattern));
188
- }
95
+ const packageJson = JSON.parse(fs.readFileSync(userPackageJsonPath, 'utf-8'));
189
96
 
190
- async function downloadFile(fileInfo) {
191
- try {
192
- const targetPath = path.join(__dirname, fileInfo.path);
193
-
194
- // Download file content
195
- const { data } = await axios.get(
196
- `https://raw.githubusercontent.com/sheikhtamimlover/ST-FCA/main/${fileInfo.path}`,
197
- { responseType: 'arraybuffer' }
198
- );
199
-
200
- // Ensure directory exists
201
- const fileDir = path.dirname(targetPath);
202
- if (!fs.existsSync(fileDir)) {
203
- fs.mkdirSync(fileDir, { recursive: true });
97
+ // Update stfca version in dependencies
98
+ if (packageJson.dependencies && packageJson.dependencies.stfca) {
99
+ packageJson.dependencies.stfca = `^${version}`;
100
+ fs.writeFileSync(userPackageJsonPath, JSON.stringify(packageJson, null, 2));
101
+ console.log('\x1b[32m%s\x1b[0m', `✅ Updated package.json to stfca@${version}`);
204
102
  }
205
-
206
- // Write file
207
- fs.writeFileSync(targetPath, Buffer.from(data));
208
- console.log('\x1b[32m%s\x1b[0m', ` ✓ ${fileInfo.path}`);
209
- } catch (error) {
210
- console.log('\x1b[31m%s\x1b[0m', ` ✗ Failed: ${fileInfo.path}`, error.message);
211
- }
212
- }
213
103
 
214
- function deleteLocalFile(filePath) {
215
- try {
216
- const fullPath = path.join(__dirname, filePath);
217
- if (fs.existsSync(fullPath)) {
218
- fs.unlinkSync(fullPath);
219
- console.log('\x1b[33m%s\x1b[0m', ` 🗑️ Deleted: ${filePath}`);
220
- }
104
+ return true;
221
105
  } catch (error) {
222
- console.log('\x1b[31m%s\x1b[0m', ` Failed to delete: ${filePath}`, error.message);
106
+ console.log('\x1b[31m%s\x1b[0m', '⚠️ Failed to update user package.json:', error.message);
107
+ // Don't throw - this is not critical
108
+ return false;
223
109
  }
224
110
  }
225
111
 
226
- module.exports = { checkForFCAUpdate, performComprehensiveUpdate, updateNpmPackage };
112
+ module.exports = { checkForFCAUpdate, updateNpmPackage, updateUserPackageJson };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stfca",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
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": [
@@ -0,0 +1,190 @@
1
+ /**
2
+ * ===========================================================
3
+ * 💫 META THEME GENERATOR MODULE 💫
4
+ * ===========================================================
5
+ * 🧑‍💻 Author: Sheikh Tamim (ST | Sheikh Tamim)
6
+ * 🔰 Owner & Developer
7
+ * 🌐 GitHub: https://github.com/sheikhtamimlover
8
+ * 📸 Instagram: https://instagram.com/sheikh.tamim_lover
9
+ * 🧠 Description:
10
+ * This module generates beautiful Messenger AI themes
11
+ * using Meta's hidden GraphQL endpoints. It allows you to
12
+ * create unique chat themes based on your custom prompt
13
+ * or optional image inspiration.
14
+ * -----------------------------------------------------------
15
+ * ⚙️ Features:
16
+ * • Generate AI-based Messenger chat themes.
17
+ * • Custom prompt & optional image URL input.
18
+ * • Returns structured theme data with full color mapping.
19
+ * -----------------------------------------------------------
20
+ * 🕊️ Respect the creator & give proper credits if reused.
21
+ * ===========================================================
22
+ */
23
+
24
+ "use strict";
25
+
26
+ const utils = require("../utils");
27
+ const log = require("npmlog");
28
+ /** © Sheikh Tamim - Please give proper credits if you copy or reuse this code. */
29
+ module.exports = function (defaultFuncs, api, ctx) {
30
+ return function metaTheme(prompt, options, callback) {
31
+ var resolveFunc = function () { };
32
+ var rejectFunc = function () { };
33
+ var returnPromise = new Promise(function (resolve, reject) {
34
+ resolveFunc = resolve;
35
+ rejectFunc = reject;
36
+ });
37
+
38
+ // Handle optional parameters
39
+ if (typeof options === 'function') {
40
+ callback = options;
41
+ options = {};
42
+ }
43
+
44
+ if (!callback) {
45
+ callback = function (err, data) {
46
+ if (err) return rejectFunc(err);
47
+ resolveFunc(data);
48
+ };
49
+ }
50
+
51
+ if (!prompt || typeof prompt !== 'string') {
52
+ return callback({ error: "Prompt is required and must be a string" });
53
+ }
54
+
55
+ // Parse options
56
+ const numThemes = options.numThemes || 1;
57
+ const imageUrl = options.imageUrl || null;
58
+
59
+ const inputData = {
60
+ client_mutation_id: Math.floor(Math.random() * 10).toString(),
61
+ actor_id: ctx.userID,
62
+ bypass_cache: true,
63
+ caller: "MESSENGER",
64
+ num_themes: Math.min(numThemes, 5), // Limit to max 5 themes
65
+ prompt: prompt
66
+ };
67
+
68
+ // Add image URL if provided
69
+ if (imageUrl) {
70
+ inputData.image_url = imageUrl;
71
+ }
72
+
73
+ const form = {
74
+ av: ctx.userID,
75
+ __aaid: 0,
76
+ __user: ctx.userID,
77
+ __a: 1,
78
+ __req: utils.getSignatureID(),
79
+ __hs: "20358.HYP:comet_pkg.2.1...0",
80
+ dpr: 1,
81
+ __ccg: "EXCELLENT",
82
+ __rev: "1027673511",
83
+ __s: utils.getSignatureID(),
84
+ __hsi: "7554561631547849479",
85
+ __comet_req: 15,
86
+ fb_dtsg: ctx.fb_dtsg,
87
+ jazoest: ctx.ttstamp,
88
+ lsd: ctx.fb_dtsg,
89
+ __spin_r: "1027673511",
90
+ __spin_b: "trunk",
91
+ __spin_t: Date.now(),
92
+ __crn: "comet.fbweb.MWInboxHomeRoute",
93
+ qpl_active_flow_ids: "25309433,521485406",
94
+ fb_api_caller_class: "RelayModern",
95
+ fb_api_req_friendly_name: "useGenerateAIThemeMutation",
96
+ variables: JSON.stringify({ input: inputData }),
97
+ server_timestamps: true,
98
+ doc_id: "23873748445608673",
99
+ fb_api_analytics_tags: JSON.stringify(["qpl_active_flow_ids=25309433,521485406"])
100
+ };
101
+
102
+ defaultFuncs
103
+ .post("https://www.facebook.com/api/graphql/", ctx.jar, form)
104
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
105
+ .then(function (resData) {
106
+ if (resData.errors) {
107
+ throw resData.errors;
108
+ }
109
+
110
+ if (resData.data && resData.data.xfb_generate_ai_themes_from_prompt) {
111
+ const themeData = resData.data.xfb_generate_ai_themes_from_prompt;
112
+ if (themeData.success && themeData.themes && themeData.themes.length > 0) {
113
+ const themes = themeData.themes.map((theme, index) => ({
114
+ success: true,
115
+ themeId: theme.id,
116
+ name: theme.accessibility_label,
117
+ description: theme.description,
118
+ serialNumber: index + 1,
119
+ colors: {
120
+ composerBackground: theme.composer_background_color,
121
+ backgroundGradient: theme.background_gradient_colors,
122
+ titleBarButton: theme.title_bar_button_tint_color,
123
+ inboundMessageGradient: theme.inbound_message_gradient_colors,
124
+ titleBarText: theme.title_bar_text_color,
125
+ composerTint: theme.composer_tint_color,
126
+ messageText: theme.message_text_color,
127
+ primaryButton: theme.primary_button_background_color,
128
+ titleBarBackground: theme.title_bar_background_color,
129
+ fallback: theme.fallback_color,
130
+ gradient: theme.gradient_colors
131
+ },
132
+ backgroundImage: theme.background_asset ? theme.background_asset.image.uri : null,
133
+ iconImage: theme.icon_asset ? theme.icon_asset.image.uri : null,
134
+ images: {
135
+ background: theme.background_asset ? theme.background_asset.image.uri : null,
136
+ icon: theme.icon_asset ? theme.icon_asset.image.uri : null
137
+ },
138
+ alternativeThemes: theme.alternative_themes ? theme.alternative_themes.map(alt => ({
139
+ id: alt.id,
140
+ name: alt.accessibility_label,
141
+ backgroundImage: alt.background_asset ? alt.background_asset.image.uri : null,
142
+ iconImage: alt.icon_asset ? alt.icon_asset.image.uri : null
143
+ })) : []
144
+ }));
145
+
146
+ const result = {
147
+ success: true,
148
+ count: themes.length,
149
+ themes: themes,
150
+ // For backward compatibility, include first theme data at root level
151
+ ...themes[0]
152
+ };
153
+ return callback(null, result);
154
+ } else {
155
+ throw new Error("No themes generated for the given prompt");
156
+ }
157
+ } else {
158
+ throw new Error("Invalid response from AI theme generation");
159
+ }
160
+ })
161
+ .catch(function (err) {
162
+ log.error("metaTheme", err);
163
+
164
+ // Check for specific error conditions
165
+ let errorMessage = "An error occurred while generating themes";
166
+
167
+ if (err.message && err.message.includes("not authorized")) {
168
+ errorMessage = "Your account is not authorized to generate AI themes. This feature may not be available for your account type.";
169
+ } else if (err.message && err.message.includes("rate limit")) {
170
+ errorMessage = "Rate limit exceeded. Please wait a moment before trying again.";
171
+ } else if (err.message && err.message.includes("Invalid")) {
172
+ errorMessage = "Invalid request parameters. Please check your input.";
173
+ } else if (err.statusCode === 403) {
174
+ errorMessage = "Access denied. Your account may not support Meta AI theme generation.";
175
+ } else if (err.statusCode === 429) {
176
+ errorMessage = "Too many requests. Please wait before trying again.";
177
+ }
178
+
179
+ return callback({
180
+ error: errorMessage,
181
+ originalError: err.message || err,
182
+ statusCode: err.statusCode || null
183
+ });
184
+ });
185
+
186
+ return returnPromise;
187
+ };
188
+ };
189
+
190
+ /** © Sheikh Tamim - Please give proper credits if you copy or reuse this code. */
@@ -0,0 +1,276 @@
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
+ "use strict";
12
+
13
+ var utils = require("../utils");
14
+ var log = require("npmlog");
15
+
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
+ };
275
+ };
276
+ /** Developed by Sheikh Tamim | GitHub: sheikhtamimlover | Please give credits if reused. */