stfca 1.0.10 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stfca",
3
- "version": "1.0.10",
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. */