@lazyneoaz/metachat 4.0.4 → 4.0.6

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/dist/index.cjs CHANGED
@@ -13550,7 +13550,7 @@ var require_agent = __commonJS({
13550
13550
  var agent_base_1 = require_src2();
13551
13551
  var parse_proxy_response_1 = __importDefault(require_parse_proxy_response());
13552
13552
  var debug2 = debug_1.default("https-proxy-agent:agent");
13553
- var HttpsProxyAgent5 = class extends agent_base_1.Agent {
13553
+ var HttpsProxyAgent4 = class extends agent_base_1.Agent {
13554
13554
  constructor(_opts) {
13555
13555
  let opts;
13556
13556
  if (typeof _opts === "string") {
@@ -13644,7 +13644,7 @@ var require_agent = __commonJS({
13644
13644
  });
13645
13645
  }
13646
13646
  };
13647
- exports.default = HttpsProxyAgent5;
13647
+ exports.default = HttpsProxyAgent4;
13648
13648
  function resume(socket) {
13649
13649
  socket.resume();
13650
13650
  }
@@ -21887,94 +21887,6 @@ var require_form_data2 = __commonJS({
21887
21887
  }
21888
21888
  });
21889
21889
 
21890
- // src/utils/headers.ts
21891
- function sanitizeHeaderValue2(value) {
21892
- if (value === null || value === void 0) return "";
21893
- let str = String(value);
21894
- if (str.trim().startsWith("[") && str.trim().endsWith("]")) {
21895
- try {
21896
- const parsed = JSON.parse(str);
21897
- if (Array.isArray(parsed)) {
21898
- return "";
21899
- }
21900
- } catch {
21901
- }
21902
- }
21903
- str = str.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\r\n\[\]]/g, "").trim();
21904
- return str;
21905
- }
21906
- function sanitizeHeaderName(name) {
21907
- if (!name || typeof name !== "string") return "";
21908
- return name.replace(/[^\x21-\x7E]/g, "").trim();
21909
- }
21910
- function getHeaders(url2, options, ctx, customHeader) {
21911
- const u = new URL(url2);
21912
- const ua = options?.userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36";
21913
- const referer = options?.referer || "https://www.facebook.com/";
21914
- const origin2 = referer.replace(/\/+$/, "");
21915
- const contentType = options?.contentType || "application/x-www-form-urlencoded";
21916
- const acceptLang = options?.acceptLanguage || "en-US,en;q=0.9,vi;q=0.8";
21917
- const headers = {
21918
- Host: sanitizeHeaderValue2(u.host),
21919
- Origin: sanitizeHeaderValue2(origin2),
21920
- Referer: sanitizeHeaderValue2(referer),
21921
- "User-Agent": sanitizeHeaderValue2(ua),
21922
- Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,application/json;q=0.8,*/*;q=0.7",
21923
- "Accept-Language": sanitizeHeaderValue2(acceptLang),
21924
- "Accept-Encoding": "gzip, deflate, br",
21925
- "Content-Type": sanitizeHeaderValue2(contentType),
21926
- Connection: "keep-alive",
21927
- DNT: "1",
21928
- "Upgrade-Insecure-Requests": "1",
21929
- "sec-ch-ua": '"Chromium";v="139", "Not;A=Brand";v="24", "Google Chrome";v="139"',
21930
- "sec-ch-ua-mobile": "?0",
21931
- "sec-ch-ua-platform": '"Windows"',
21932
- "sec-ch-ua-arch": '"x86"',
21933
- "sec-ch-ua-bitness": '"64"',
21934
- "sec-ch-ua-full-version-list": '"Chromium";v="139.0.0.0", "Not;A=Brand";v="24.0.0.0", "Google Chrome";v="139.0.0.0"',
21935
- "sec-ch-ua-platform-version": '"15.0.0"',
21936
- "Sec-Fetch-Site": "same-origin",
21937
- "Sec-Fetch-Mode": "cors",
21938
- "Sec-Fetch-Dest": "empty",
21939
- "X-Requested-With": "XMLHttpRequest",
21940
- Pragma: "no-cache",
21941
- "Cache-Control": "no-cache"
21942
- };
21943
- if (ctx?.region) {
21944
- const regionValue = sanitizeHeaderValue2(ctx.region);
21945
- if (regionValue) headers["X-MSGR-Region"] = regionValue;
21946
- }
21947
- if (customHeader && typeof customHeader === "object") {
21948
- for (const [key, value] of Object.entries(customHeader)) {
21949
- if (value === null || value === void 0 || typeof value === "function") continue;
21950
- if (typeof value === "object") continue;
21951
- const sanitizedKey = sanitizeHeaderName(key);
21952
- const sanitizedValue = sanitizeHeaderValue2(value);
21953
- if (sanitizedKey && sanitizedValue !== "") {
21954
- const existingKey = Object.keys(headers).find(
21955
- (headerKey) => headerKey.toLowerCase() === sanitizedKey.toLowerCase()
21956
- );
21957
- headers[existingKey || sanitizedKey] = sanitizedValue;
21958
- }
21959
- }
21960
- }
21961
- const sanitizedHeaders = {};
21962
- for (const [key, value] of Object.entries(headers)) {
21963
- const sanitizedKey = sanitizeHeaderName(key);
21964
- const sanitizedValue = sanitizeHeaderValue2(value);
21965
- if (sanitizedKey && sanitizedValue !== "") {
21966
- sanitizedHeaders[sanitizedKey] = sanitizedValue;
21967
- }
21968
- }
21969
- return sanitizedHeaders;
21970
- }
21971
- var meta;
21972
- var init_headers = __esm({
21973
- "src/utils/headers.ts"() {
21974
- meta = (prop2) => new RegExp(`<meta property="${prop2}" content="([^"]*)"`);
21975
- }
21976
- });
21977
-
21978
21890
  // node_modules/color-name/index.js
21979
21891
  var require_color_name = __commonJS({
21980
21892
  "node_modules/color-name/index.js"(exports, module) {
@@ -24853,14 +24765,12 @@ function getGUID() {
24853
24765
  });
24854
24766
  }
24855
24767
  function getFrom(str, startToken, endToken) {
24856
- const start = str.indexOf(startToken) + startToken.length;
24857
- if (start < startToken.length) return "";
24858
- const lastHalf = str.substring(start);
24859
- const end2 = lastHalf.indexOf(endToken);
24860
- if (end2 === -1) {
24861
- throw Error("Could not find endTime `" + endToken + "` in the given string.");
24862
- }
24863
- return lastHalf.substring(0, end2);
24768
+ const startIndex = str.indexOf(startToken);
24769
+ if (startIndex < 0) return "";
24770
+ const start = startIndex + startToken.length;
24771
+ const end2 = str.indexOf(endToken, start);
24772
+ if (end2 < 0) return str.slice(start);
24773
+ return str.slice(start, end2);
24864
24774
  }
24865
24775
  function makeParsable(html3) {
24866
24776
  const withoutForLoop = html3.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/, "");
@@ -24989,6 +24899,483 @@ var init_constants = __esm({
24989
24899
  }
24990
24900
  });
24991
24901
 
24902
+ // src/utils/user-agents.ts
24903
+ function buildProfile(major, plat) {
24904
+ const full = `${major}.0.0.0`;
24905
+ const brands = [
24906
+ `"Not;A=Brand";v="24"`,
24907
+ `"Chromium";v="${major}"`,
24908
+ `"Google Chrome";v="${major}"`
24909
+ ];
24910
+ const fullVersionList = [
24911
+ `"Not;A=Brand";v="24.0.0.0"`,
24912
+ `"Chromium";v="${full}"`,
24913
+ `"Google Chrome";v="${full}"`
24914
+ ];
24915
+ const screen = getRandom(SCREENS);
24916
+ const language = getRandom(LANGUAGES);
24917
+ const isMac = /Macintosh/.test(plat.platform);
24918
+ const devicePixelRatio = isMac ? 2 : getRandom([1, 1.25, 1.5]) === 1 ? 1 : 1.25;
24919
+ return {
24920
+ userAgent: `Mozilla/5.0 (${plat.platform}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${full} Safari/537.36`,
24921
+ secChUa: brands.join(", "),
24922
+ secChUaFullVersionList: fullVersionList.join(", "),
24923
+ secChUaPlatform: plat.chPlatform,
24924
+ secChUaPlatformVersion: plat.chPlatformVersion,
24925
+ secChUaArch: plat.chArch,
24926
+ secChUaBitness: plat.chBitness,
24927
+ secChUaModel: '""',
24928
+ secChUaWow64: plat.chWow64,
24929
+ secChUaFormFactors: plat.formFactors,
24930
+ secChUaMobile: "?0",
24931
+ acceptLanguage: language === "en-GB" ? "en-GB,en;q=0.9" : "en-US,en;q=0.9",
24932
+ language,
24933
+ timezone: getRandom(TIMEOZONES),
24934
+ screen: {
24935
+ ...screen,
24936
+ colorDepth: 24,
24937
+ pixelDepth: 24
24938
+ },
24939
+ devicePixelRatio,
24940
+ hardwareConcurrency: getRandom([4, 8, 12, 16]),
24941
+ deviceMemory: getRandom([8, 8, 16]),
24942
+ label: plat.label
24943
+ };
24944
+ }
24945
+ function randomUserAgent() {
24946
+ return buildProfile(getRandom(CHROME_MAJORS), getRandom(DESKTOP_PLATFORMS));
24947
+ }
24948
+ function normalizeBrowserProfile(input) {
24949
+ if (!input) return exports.defaultBrowserProfile;
24950
+ const base = exports.defaultBrowserProfile;
24951
+ const ua = input.userAgent || base.userAgent;
24952
+ const major = (ua.match(/Chrome\/(\d+)/) || [])[1] || CHROME_MAJORS[0];
24953
+ const inferred = buildProfile(
24954
+ major,
24955
+ /Macintosh/.test(ua) ? DESKTOP_PLATFORMS.find((p) => /Macintosh/.test(p.platform)) : DESKTOP_PLATFORMS[0]
24956
+ );
24957
+ return { ...inferred, ...input, userAgent: ua };
24958
+ }
24959
+ var CHROME_MAJORS, DESKTOP_PLATFORMS, SCREENS, TIMEOZONES, LANGUAGES; exports.defaultBrowserProfile = void 0; var defaultUserAgent, windowsUserAgent;
24960
+ var init_user_agents = __esm({
24961
+ "src/utils/user-agents.ts"() {
24962
+ init_constants();
24963
+ CHROME_MAJORS = ["141", "140", "139"];
24964
+ DESKTOP_PLATFORMS = [
24965
+ {
24966
+ platform: "Windows NT 10.0; Win64; x64",
24967
+ chPlatform: '"Windows"',
24968
+ chPlatformVersion: '"15.0.0"',
24969
+ chArch: '"x86"',
24970
+ chBitness: '"64"',
24971
+ chWow64: "?0",
24972
+ formFactors: '"Desktop"',
24973
+ label: "Chrome/Windows-11"
24974
+ },
24975
+ {
24976
+ platform: "Windows NT 10.0; Win64; x64",
24977
+ chPlatform: '"Windows"',
24978
+ chPlatformVersion: '"10.0.0"',
24979
+ chArch: '"x86"',
24980
+ chBitness: '"64"',
24981
+ chWow64: "?0",
24982
+ formFactors: '"Desktop"',
24983
+ label: "Chrome/Windows-10"
24984
+ },
24985
+ {
24986
+ platform: "Macintosh; Intel Mac OS X 10_15_7",
24987
+ chPlatform: '"macOS"',
24988
+ chPlatformVersion: '"14.6.1"',
24989
+ chArch: '"x86"',
24990
+ chBitness: '"64"',
24991
+ chWow64: "?0",
24992
+ formFactors: '"Desktop"',
24993
+ label: "Chrome/macOS-14"
24994
+ },
24995
+ {
24996
+ platform: "Macintosh; Intel Mac OS X 10_15_7",
24997
+ chPlatform: '"macOS"',
24998
+ chPlatformVersion: '"15.1.0"',
24999
+ chArch: '"arm"',
25000
+ chBitness: '"64"',
25001
+ chWow64: "?0",
25002
+ formFactors: '"Desktop"',
25003
+ label: "Chrome/macOS-15-arm"
25004
+ }
25005
+ ];
25006
+ SCREENS = [
25007
+ { width: 1920, height: 1080, availWidth: 1920, availHeight: 1053 },
25008
+ { width: 2560, height: 1440, availWidth: 2560, availHeight: 1400 },
25009
+ { width: 1536, height: 864, availWidth: 1536, availHeight: 824 },
25010
+ { width: 1440, height: 900, availWidth: 1440, availHeight: 860 },
25011
+ { width: 1366, height: 768, availWidth: 1366, availHeight: 728 }
25012
+ ];
25013
+ TIMEOZONES = [
25014
+ "America/New_York",
25015
+ "America/Chicago",
25016
+ "America/Los_Angeles",
25017
+ "Europe/London",
25018
+ "Europe/Berlin",
25019
+ "Asia/Singapore"
25020
+ ];
25021
+ LANGUAGES = ["en-US", "en-GB"];
25022
+ exports.defaultBrowserProfile = buildProfile(
25023
+ CHROME_MAJORS[0],
25024
+ DESKTOP_PLATFORMS[0]
25025
+ );
25026
+ defaultUserAgent = exports.defaultBrowserProfile.userAgent;
25027
+ windowsUserAgent = defaultUserAgent;
25028
+ }
25029
+ });
25030
+
25031
+ // src/utils/headers.ts
25032
+ function sanitizeHeaderValue2(value) {
25033
+ if (value === null || value === void 0) return "";
25034
+ const str = String(value);
25035
+ return str.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\r\n]/g, "").trim();
25036
+ }
25037
+ function sanitizeHeaderName(name) {
25038
+ if (!name || typeof name !== "string") return "";
25039
+ return name.replace(/[^\x21-\x7E]/g, "").trim();
25040
+ }
25041
+ function originOf(referer) {
25042
+ try {
25043
+ return new URL(referer).origin;
25044
+ } catch {
25045
+ return "https://www.facebook.com";
25046
+ }
25047
+ }
25048
+ function isMessengerHost(host) {
25049
+ return /(^|\.)messenger\.com$/i.test(host);
25050
+ }
25051
+ function isEdgeChatHost(host) {
25052
+ return /(^|\.)edge-chat\.messenger\.com$/i.test(host) || /(^|\.)edge-chat\.facebook\.com$/i.test(host);
25053
+ }
25054
+ function isBusinessHost(host) {
25055
+ return /(^|\.)business\.facebook\.com$/i.test(host);
25056
+ }
25057
+ function isFacebookHost(host) {
25058
+ return /(^|\.)facebook\.com$/i.test(host);
25059
+ }
25060
+ function isGraphQlPath(pathname) {
25061
+ return /\/api\/graphql/i.test(pathname) || /graphqlbatch/i.test(pathname);
25062
+ }
25063
+ function resolveProfile(options) {
25064
+ const base = options?.browser || options?.browserProfile || exports.defaultBrowserProfile;
25065
+ const merged = {
25066
+ ...base,
25067
+ userAgent: options?.userAgent || base.userAgent,
25068
+ secChUa: options?.secChUa || base.secChUa,
25069
+ secChUaFullVersionList: options?.secChUaFullVersionList || base.secChUaFullVersionList,
25070
+ secChUaPlatform: options?.secChUaPlatform || base.secChUaPlatform,
25071
+ secChUaPlatformVersion: options?.secChUaPlatformVersion || base.secChUaPlatformVersion,
25072
+ secChUaArch: options?.secChUaArch || base.secChUaArch,
25073
+ secChUaBitness: options?.secChUaBitness || base.secChUaBitness,
25074
+ secChUaWow64: options?.secChUaWow64 || base.secChUaWow64,
25075
+ secChUaFormFactors: options?.secChUaFormFactors || base.secChUaFormFactors,
25076
+ secChUaMobile: options?.secChUaMobile || base.secChUaMobile,
25077
+ acceptLanguage: options?.acceptLanguage || base.acceptLanguage
25078
+ };
25079
+ if (options?.userAgent && !options?.browser && !options?.browserProfile) {
25080
+ return normalizeBrowserProfile(merged);
25081
+ }
25082
+ return merged;
25083
+ }
25084
+ function shouldSendOrigin(method, isXhr) {
25085
+ const m = (method || "GET").toUpperCase();
25086
+ if (m === "GET" || m === "HEAD" || m === "OPTIONS") return false;
25087
+ return true;
25088
+ }
25089
+ function getHeaders(url2, options, ctx, customHeader) {
25090
+ const u = new URL(url2);
25091
+ const profile = resolveProfile(options);
25092
+ const method = String(options?.method || customHeader?.method || "GET").toUpperCase();
25093
+ const defaultReferer = isMessengerHost(u.hostname) ? "https://www.messenger.com/" : isBusinessHost(u.hostname) ? "https://business.facebook.com/" : "https://www.facebook.com/";
25094
+ const referer = options?.referer || defaultReferer;
25095
+ const origin2 = options?.origin || originOf(referer);
25096
+ const contentType = options?.contentType || (customHeader?.["Content-Type"] || customHeader?.["content-type"]) || "application/x-www-form-urlencoded";
25097
+ const isGraphQl = isGraphQlPath(u.pathname);
25098
+ const isXhr = isGraphQl || contentType.includes("json") || !!options?.xhr;
25099
+ const isDocument2 = !isXhr && (method === "GET" || method === "HEAD");
25100
+ const secFetchSite = (() => {
25101
+ if (isDocument2) return "none";
25102
+ let refererHost = referer;
25103
+ try {
25104
+ refererHost = new URL(referer).hostname;
25105
+ } catch {
25106
+ }
25107
+ if (isMessengerHost(u.hostname) && !isMessengerHost(refererHost)) return "same-site";
25108
+ if (isFacebookHost(u.hostname) && !isFacebookHost(refererHost)) return "cross-site";
25109
+ return "same-origin";
25110
+ })();
25111
+ const accept = isGraphQl ? "*/*" : isXhr ? "*/*" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
25112
+ const headers = {
25113
+ Referer: sanitizeHeaderValue2(referer),
25114
+ "User-Agent": sanitizeHeaderValue2(profile.userAgent),
25115
+ Accept: accept,
25116
+ "Accept-Language": sanitizeHeaderValue2(profile.acceptLanguage),
25117
+ "Accept-Encoding": "gzip, deflate, br",
25118
+ Connection: "keep-alive",
25119
+ "Upgrade-Insecure-Requests": "1",
25120
+ "sec-ch-ua": sanitizeHeaderValue2(profile.secChUa),
25121
+ "sec-ch-ua-mobile": sanitizeHeaderValue2(profile.secChUaMobile),
25122
+ "sec-ch-ua-platform": sanitizeHeaderValue2(profile.secChUaPlatform),
25123
+ "sec-ch-ua-platform-version": sanitizeHeaderValue2(profile.secChUaPlatformVersion),
25124
+ "sec-ch-ua-arch": sanitizeHeaderValue2(profile.secChUaArch),
25125
+ "sec-ch-ua-bitness": sanitizeHeaderValue2(profile.secChUaBitness),
25126
+ "sec-ch-ua-model": sanitizeHeaderValue2(profile.secChUaModel),
25127
+ "sec-ch-ua-wow64": sanitizeHeaderValue2(profile.secChUaWow64),
25128
+ "sec-ch-ua-form-factors": sanitizeHeaderValue2(profile.secChUaFormFactors),
25129
+ "sec-ch-ua-full-version-list": sanitizeHeaderValue2(profile.secChUaFullVersionList),
25130
+ "Sec-Fetch-Site": secFetchSite,
25131
+ "Sec-Fetch-Mode": isXhr ? "cors" : "navigate",
25132
+ "Sec-Fetch-Dest": isXhr ? "empty" : "document"
25133
+ };
25134
+ if (method !== "GET" && method !== "HEAD") {
25135
+ headers["Content-Type"] = sanitizeHeaderValue2(contentType);
25136
+ }
25137
+ if (shouldSendOrigin(method)) {
25138
+ headers["Origin"] = sanitizeHeaderValue2(origin2);
25139
+ }
25140
+ if (isDocument2) {
25141
+ headers["Sec-Fetch-User"] = "?1";
25142
+ headers["priority"] = "u=0, i";
25143
+ }
25144
+ if (isXhr) {
25145
+ headers["X-Requested-With"] = "XMLHttpRequest";
25146
+ headers["Pragma"] = "no-cache";
25147
+ headers["Cache-Control"] = "no-cache";
25148
+ headers["priority"] = "u=1, i";
25149
+ }
25150
+ if (isGraphQl) {
25151
+ headers["x-asbd-id"] = "129477";
25152
+ const lsd = ctx?.lsd || ctx?.fb_lsd;
25153
+ if (lsd) headers["x-fb-lsd"] = sanitizeHeaderValue2(lsd);
25154
+ const friendlyName = customHeader?.["x-fb-friendly-name"] || customHeader?.["X-Fb-Friendly-Name"];
25155
+ if (friendlyName) headers["x-fb-friendly-name"] = sanitizeHeaderValue2(friendlyName);
25156
+ }
25157
+ if (ctx?.region && (isMessengerHost(u.hostname) || isEdgeChatHost(u.hostname))) {
25158
+ const regionValue = sanitizeHeaderValue2(ctx.region);
25159
+ if (regionValue) headers["X-MSGR-Region"] = regionValue;
25160
+ }
25161
+ if (customHeader && typeof customHeader === "object") {
25162
+ for (const [key, value] of Object.entries(customHeader)) {
25163
+ if (value === null || value === void 0 || typeof value === "function") continue;
25164
+ if (typeof value === "object") continue;
25165
+ const sanitizedKey = sanitizeHeaderName(key);
25166
+ let sanitizedValue = sanitizeHeaderValue2(value);
25167
+ if (!sanitizedKey || sanitizedValue === "") continue;
25168
+ if (sanitizedKey.toLowerCase() === "referer") {
25169
+ headers["Referer"] = sanitizedValue;
25170
+ if (!customHeader.origin && !customHeader.Origin && shouldSendOrigin(method)) {
25171
+ headers["Origin"] = originOf(sanitizedValue);
25172
+ }
25173
+ continue;
25174
+ }
25175
+ const existingKey = Object.keys(headers).find(
25176
+ (headerKey) => headerKey.toLowerCase() === sanitizedKey.toLowerCase()
25177
+ );
25178
+ headers[existingKey || sanitizedKey] = sanitizedValue;
25179
+ }
25180
+ }
25181
+ const sanitizedHeaders = {};
25182
+ for (const [key, value] of Object.entries(headers)) {
25183
+ if (value === void 0 || value === null) continue;
25184
+ const sanitizedKey = sanitizeHeaderName(key);
25185
+ const sanitizedValue = sanitizeHeaderValue2(value);
25186
+ if (sanitizedKey && sanitizedValue !== "") {
25187
+ sanitizedHeaders[sanitizedKey] = sanitizedValue;
25188
+ }
25189
+ }
25190
+ return sanitizedHeaders;
25191
+ }
25192
+ function getWebSocketHeaders(url2, options, ctx) {
25193
+ const profile = resolveProfile(options);
25194
+ const u = new URL(url2);
25195
+ const origin2 = isMessengerHost(u.hostname) ? "https://www.messenger.com" : isBusinessHost(u.hostname) ? "https://business.facebook.com" : "https://www.facebook.com";
25196
+ const referer = options?.referer || (origin2 === "https://www.messenger.com" ? "https://www.messenger.com/" : `${origin2}/`);
25197
+ return {
25198
+ Origin: origin2,
25199
+ Referer: referer,
25200
+ "User-Agent": profile.userAgent,
25201
+ "Accept-Language": profile.acceptLanguage,
25202
+ "Accept-Encoding": "gzip, deflate, br, zstd",
25203
+ "Cache-Control": "no-cache",
25204
+ Pragma: "no-cache",
25205
+ "sec-ch-ua": profile.secChUa,
25206
+ "sec-ch-ua-mobile": profile.secChUaMobile,
25207
+ "sec-ch-ua-platform": profile.secChUaPlatform,
25208
+ "sec-ch-ua-platform-version": profile.secChUaPlatformVersion,
25209
+ "sec-ch-ua-arch": profile.secChUaArch,
25210
+ "sec-ch-ua-bitness": profile.secChUaBitness,
25211
+ "sec-ch-ua-model": profile.secChUaModel,
25212
+ "sec-ch-ua-wow64": profile.secChUaWow64,
25213
+ "sec-ch-ua-full-version-list": profile.secChUaFullVersionList
25214
+ };
25215
+ }
25216
+ function getFingerprintParams(options) {
25217
+ const profile = resolveProfile(options);
25218
+ return {
25219
+ dpr: String(profile.devicePixelRatio)
25220
+ };
25221
+ }
25222
+ var meta;
25223
+ var init_headers = __esm({
25224
+ "src/utils/headers.ts"() {
25225
+ init_user_agents();
25226
+ meta = (prop2) => new RegExp(`<meta property="${prop2}" content="([^"]*)"`);
25227
+ }
25228
+ });
25229
+
25230
+ // src/utils/pacing.ts
25231
+ function pacingState(ctx) {
25232
+ if (!ctx.__pacing) {
25233
+ ctx.__pacing = { lastRequestAt: 0, chain: Promise.resolve(), inflight: 0 };
25234
+ }
25235
+ return ctx.__pacing;
25236
+ }
25237
+ function humanDelay(baseMs = TYPICAL_GAP_MS, spreadMs = 220) {
25238
+ const u = Math.random() * Math.random();
25239
+ const jitter = Math.floor(u * spreadMs * 2) - spreadMs;
25240
+ return Math.max(MIN_GAP_MS, Math.min(MAX_GAP_MS, baseMs + jitter));
25241
+ }
25242
+ function sleep(ms) {
25243
+ return new Promise((resolve) => setTimeout(resolve, Math.max(0, Math.floor(ms))));
25244
+ }
25245
+ async function paceRequest(ctx, weight = "normal") {
25246
+ const state = pacingState(ctx);
25247
+ const base = weight === "light" ? TYPICAL_GAP_MS * 0.5 : weight === "heavy" ? TYPICAL_GAP_MS * 2.2 : TYPICAL_GAP_MS;
25248
+ const turn = state.chain.then(async () => {
25249
+ const now = Date.now();
25250
+ const elapsed = now - state.lastRequestAt;
25251
+ if (elapsed < MIN_GAP_MS) {
25252
+ await sleep(humanDelay(Math.max(base, MIN_GAP_MS - elapsed)));
25253
+ } else if (elapsed < base) {
25254
+ await sleep(humanDelay(base - elapsed, 160));
25255
+ } else {
25256
+ await sleep(humanDelay(MIN_GAP_MS, 60));
25257
+ }
25258
+ state.lastRequestAt = Date.now();
25259
+ });
25260
+ state.chain = turn.catch(() => {
25261
+ });
25262
+ return turn;
25263
+ }
25264
+ function retryDelay(attempt, baseMs = 1200, capMs = 45e3) {
25265
+ const exp = Math.min(capMs, baseMs * Math.pow(1.7, Math.max(0, attempt)));
25266
+ const jitter = 0.5 + Math.random() * 0.75;
25267
+ return Math.min(capMs, Math.floor(exp * jitter));
25268
+ }
25269
+ function noteAction(ctx, weight = "heavy") {
25270
+ const state = pacingState(ctx);
25271
+ state.lastRequestAt = Date.now() + (weight === "heavy" ? 350 : 120);
25272
+ }
25273
+ var MIN_GAP_MS, TYPICAL_GAP_MS, MAX_GAP_MS;
25274
+ var init_pacing = __esm({
25275
+ "src/utils/pacing.ts"() {
25276
+ MIN_GAP_MS = 120;
25277
+ TYPICAL_GAP_MS = 420;
25278
+ MAX_GAP_MS = 2500;
25279
+ }
25280
+ });
25281
+
25282
+ // src/utils/safety.ts
25283
+ function safetyState(ctx) {
25284
+ if (!ctx.__safety) {
25285
+ ctx.__safety = { window: [], openedAt: 0, authFailures: 0, cappedCount: 0, trips: [] };
25286
+ }
25287
+ const state = ctx.__safety;
25288
+ if (!Array.isArray(state.window)) state.window = [];
25289
+ if (!Array.isArray(state.trips)) state.trips = [];
25290
+ return state;
25291
+ }
25292
+ function cooldownFor(state) {
25293
+ const factor = Math.pow(1.8, Math.max(0, state.trips.length - 1));
25294
+ return Math.min(MAX_COOLDOWN_MS, Math.floor(BASE_COOLDOWN_MS * factor));
25295
+ }
25296
+ function isBreakerOpen(ctx) {
25297
+ const state = safetyState(ctx);
25298
+ if (!state.openedAt) return false;
25299
+ if (Date.now() - state.openedAt >= cooldownFor(state)) {
25300
+ state.openedAt = 0;
25301
+ state.authFailures = 0;
25302
+ return false;
25303
+ }
25304
+ return true;
25305
+ }
25306
+ function tripBreaker(ctx, reason = "manual") {
25307
+ const state = safetyState(ctx);
25308
+ if (state.openedAt && state.reason === reason) return;
25309
+ state.openedAt = Date.now();
25310
+ state.reason = reason;
25311
+ state.authFailures = 0;
25312
+ state.trips.push(Date.now());
25313
+ if (ctx.__onSafetyTrip) {
25314
+ try {
25315
+ ctx.__onSafetyTrip({ reason, cooldownMs: cooldownFor(state) });
25316
+ } catch {
25317
+ }
25318
+ }
25319
+ }
25320
+ function resetBreaker(ctx) {
25321
+ const state = safetyState(ctx);
25322
+ state.openedAt = 0;
25323
+ state.reason = void 0;
25324
+ state.authFailures = 0;
25325
+ }
25326
+ function noteAuthFailure(ctx) {
25327
+ const state = safetyState(ctx);
25328
+ state.authFailures += 1;
25329
+ if (state.authFailures >= AUTH_FAILURE_THRESHOLD) {
25330
+ tripBreaker(ctx, "auth-failure");
25331
+ }
25332
+ }
25333
+ function noteRateLimit(ctx) {
25334
+ tripBreaker(ctx, "rate-limit");
25335
+ }
25336
+ function noteCheckpoint(ctx) {
25337
+ tripBreaker(ctx, "checkpoint");
25338
+ }
25339
+ function reserveRequest(ctx) {
25340
+ const state = safetyState(ctx);
25341
+ if (isBreakerOpen(ctx)) {
25342
+ return cooldownFor(state) - (Date.now() - state.openedAt);
25343
+ }
25344
+ const now = Date.now();
25345
+ state.window = state.window.filter((t) => now - t < WINDOW_MS);
25346
+ if (state.window.length >= MAX_REQUESTS_IN_WINDOW) {
25347
+ state.cappedCount += 1;
25348
+ const oldest = state.window[0];
25349
+ return Math.max(0, WINDOW_MS - (now - oldest));
25350
+ }
25351
+ state.window.push(now);
25352
+ return 0;
25353
+ }
25354
+ function safetySnapshot(ctx) {
25355
+ const state = safetyState(ctx);
25356
+ const now = Date.now();
25357
+ state.window = state.window.filter((t) => now - t < WINDOW_MS);
25358
+ const open = isBreakerOpen(ctx);
25359
+ return {
25360
+ closed: !open,
25361
+ reason: open ? state.reason : void 0,
25362
+ cooldownRemainingMs: open ? cooldownFor(state) - (now - state.openedAt) : 0,
25363
+ requestsInWindow: state.window.length,
25364
+ authFailures: state.authFailures,
25365
+ cappedCount: state.cappedCount
25366
+ };
25367
+ }
25368
+ var MAX_REQUESTS_IN_WINDOW, WINDOW_MS, BASE_COOLDOWN_MS, MAX_COOLDOWN_MS, AUTH_FAILURE_THRESHOLD;
25369
+ var init_safety = __esm({
25370
+ "src/utils/safety.ts"() {
25371
+ MAX_REQUESTS_IN_WINDOW = 28;
25372
+ WINDOW_MS = 2e4;
25373
+ BASE_COOLDOWN_MS = 3 * 60 * 1e3;
25374
+ MAX_COOLDOWN_MS = 30 * 60 * 1e3;
25375
+ AUTH_FAILURE_THRESHOLD = 3;
25376
+ }
25377
+ });
25378
+
24992
25379
  // src/utils/axios.ts
24993
25380
  var axios_exports = {};
24994
25381
  __export(axios_exports, {
@@ -25054,18 +25441,37 @@ function adaptResponse(res) {
25054
25441
  }
25055
25442
  };
25056
25443
  }
25444
+ function looksLikeCheckpoint(res) {
25445
+ const location = res?.headers?.location || res?.headers?.Location || "";
25446
+ if (typeof location === "string" && /\/checkpoint\/|two_factor|\/consent|\/recover|account_disabled/i.test(location)) {
25447
+ return true;
25448
+ }
25449
+ const body = typeof res?.body === "string" ? res.body : "";
25450
+ return /"error":1357004|account has been (?:disabled|suspended)|confirm your identity|security check/i.test(body.slice(0, 400));
25451
+ }
25057
25452
  async function requestWithRetry(requestFunction, retries = 3, baseDelay = 1e3, ctx) {
25058
25453
  const emit2 = (event, payload) => {
25059
25454
  try {
25060
- if (ctx?._emitter && typeof ctx._emitter.emit === "function") ;
25455
+ if (ctx?._emitter && typeof ctx._emitter.emit === "function") {
25456
+ ctx._emitter.emit(event, payload);
25457
+ }
25061
25458
  } catch {
25062
25459
  }
25063
25460
  };
25064
25461
  let lastError;
25065
25462
  for (let i2 = 0; i2 < retries; i2++) {
25066
25463
  try {
25464
+ const safetyWait = reserveRequest(ctx);
25465
+ if (safetyWait > 0) await delay(safetyWait);
25466
+ await paceRequest(ctx, "normal");
25067
25467
  const res = await requestFunction();
25068
- return adaptResponse(res);
25468
+ const adapted = adaptResponse(res);
25469
+ if (looksLikeCheckpoint(adapted)) {
25470
+ noteCheckpoint(ctx);
25471
+ } else {
25472
+ resetBreaker(ctx);
25473
+ }
25474
+ return adapted;
25069
25475
  } catch (rawError) {
25070
25476
  const e = rawError || {};
25071
25477
  lastError = e;
@@ -25081,6 +25487,7 @@ async function requestWithRetry(requestFunction, retries = 3, baseDelay = 1e3, c
25081
25487
  const method = String(e?.config?.method || "").toUpperCase();
25082
25488
  if (status === 429) {
25083
25489
  emit2("rateLimit", { status, url: url2, method });
25490
+ noteRateLimit(ctx);
25084
25491
  }
25085
25492
  if (status >= 400 && status < 500 && status !== 429) {
25086
25493
  if (e.response) return adaptResponse(e.response);
@@ -25095,8 +25502,7 @@ async function requestWithRetry(requestFunction, retries = 3, baseDelay = 1e3, c
25095
25502
  if (!status && (netCode === "UND_ERR_CONNECT_TIMEOUT" || netCode === "ETIMEDOUT" || netCode === "ECONNRESET" || netCode === "ECONNREFUSED" || netCode === "ENOTFOUND" || /timeout|connect timeout|network error|fetch failed/i.test(msg))) {
25096
25503
  emit2("networkError", { code: netCode, message: msg, url: url2, method });
25097
25504
  }
25098
- const backoffDelay = Math.min(baseDelay * Math.pow(2, i2) + Math.floor(Math.random() * 200), 3e4);
25099
- await delay(backoffDelay);
25505
+ await delay(retryDelay(i2, baseDelay, 3e4));
25100
25506
  }
25101
25507
  }
25102
25508
  throw lastError || new Error("Request failed after retries");
@@ -25119,16 +25525,16 @@ function cleanGet(url2) {
25119
25525
  }
25120
25526
  async function get(url2, reqJar, qs2, options, ctx, customHeader) {
25121
25527
  const config = {
25122
- headers: getHeaders(url2, options, ctx, customHeader),
25528
+ headers: getHeaders(url2, { ...options, method: "GET" }, ctx, customHeader),
25123
25529
  timeout: 6e4,
25124
25530
  params: qs2,
25125
25531
  ...getRequestProxy(options),
25126
25532
  validateStatus: (status) => status >= 200 && status < 600
25127
25533
  };
25128
- return requestWithRetry(async () => await getClient(reqJar).get(url2, config));
25534
+ return requestWithRetry(async () => await getClient(reqJar).get(url2, config), 3, 1e3, ctx);
25129
25535
  }
25130
25536
  async function post(url2, reqJar, form, options, ctx, customHeader) {
25131
- const headers = getHeaders(url2, options, ctx, customHeader);
25537
+ const headers = getHeaders(url2, { ...options, method: "POST" }, ctx, customHeader);
25132
25538
  let data2 = form;
25133
25539
  const contentType = headers["Content-Type"] || "application/x-www-form-urlencoded";
25134
25540
  if (contentType.includes("json")) {
@@ -25153,7 +25559,7 @@ async function post(url2, reqJar, form, options, ctx, customHeader) {
25153
25559
  ...getRequestProxy(options),
25154
25560
  validateStatus: (status) => status >= 200 && status < 600
25155
25561
  };
25156
- return requestWithRetry(async () => await getClient(reqJar).post(url2, data2, config));
25562
+ return requestWithRetry(async () => await getClient(reqJar).post(url2, data2, config), 3, 1e3, ctx);
25157
25563
  }
25158
25564
  async function postMultipart(url2, reqJar, formData, qs2, options, ctx, customHeader) {
25159
25565
  const multipartHeader = {
@@ -25161,7 +25567,7 @@ async function postMultipart(url2, reqJar, formData, qs2, options, ctx, customHe
25161
25567
  ...customHeader || {}
25162
25568
  };
25163
25569
  const config = {
25164
- headers: getHeaders(url2, options, ctx, multipartHeader),
25570
+ headers: getHeaders(url2, { ...options, method: "POST" }, ctx, multipartHeader),
25165
25571
  timeout: 12e4,
25166
25572
  params: qs2,
25167
25573
  maxContentLength: Infinity,
@@ -25169,7 +25575,7 @@ async function postMultipart(url2, reqJar, formData, qs2, options, ctx, customHe
25169
25575
  ...getRequestProxy(options),
25170
25576
  validateStatus: (status) => status >= 200 && status < 600
25171
25577
  };
25172
- return requestWithRetry(async () => await getClient(reqJar).post(url2, formData, config));
25578
+ return requestWithRetry(async () => await getClient(reqJar).post(url2, formData, config), 3, 1e3, ctx);
25173
25579
  }
25174
25580
  async function postFormData(url2, reqJar, form, qs2, options, ctx, customHeader) {
25175
25581
  const formData = new import_form_data2.default();
@@ -25183,13 +25589,13 @@ async function postFormData(url2, reqJar, form, qs2, options, ctx, customHeader)
25183
25589
  ...customHeader || {}
25184
25590
  };
25185
25591
  const config = {
25186
- headers: getHeaders(url2, options, ctx, multipartHeader),
25592
+ headers: getHeaders(url2, { ...options, method: "POST" }, ctx, multipartHeader),
25187
25593
  timeout: 6e4,
25188
25594
  params: qs2,
25189
25595
  ...getRequestProxy(options),
25190
25596
  validateStatus: (status) => status >= 200 && status < 600
25191
25597
  };
25192
- return requestWithRetry(async () => await getClient(reqJar).post(url2, formData, config));
25598
+ return requestWithRetry(async () => await getClient(reqJar).post(url2, formData, config), 3, 1e3, ctx);
25193
25599
  }
25194
25600
  function getJar() {
25195
25601
  return new import_tough_cookie.CookieJar();
@@ -25203,6 +25609,8 @@ var init_axios3 = __esm({
25203
25609
  import_form_data2 = __toESM(require_form_data2());
25204
25610
  init_headers();
25205
25611
  init_constants();
25612
+ init_pacing();
25613
+ init_safety();
25206
25614
  jar = new import_tough_cookie.CookieJar();
25207
25615
  client = wrapper(axios_default.create({ jar }));
25208
25616
  clients = /* @__PURE__ */ new WeakMap();
@@ -69556,7 +69964,7 @@ var require_dist3 = __commonJS({
69556
69964
  }
69557
69965
  return options;
69558
69966
  };
69559
- var HttpsProxyAgent5 = class extends agent_base_1.Agent {
69967
+ var HttpsProxyAgent4 = class extends agent_base_1.Agent {
69560
69968
  constructor(proxy, opts) {
69561
69969
  super(opts);
69562
69970
  this.options = { path: void 0 };
@@ -69635,8 +70043,8 @@ var require_dist3 = __commonJS({
69635
70043
  return fakeSocket;
69636
70044
  }
69637
70045
  };
69638
- HttpsProxyAgent5.protocols = ["http", "https"];
69639
- exports.HttpsProxyAgent = HttpsProxyAgent5;
70046
+ HttpsProxyAgent4.protocols = ["http", "https"];
70047
+ exports.HttpsProxyAgent = HttpsProxyAgent4;
69640
70048
  function resume(socket) {
69641
70049
  socket.resume();
69642
70050
  }
@@ -75137,34 +75545,57 @@ var require_lodash = __commonJS({
75137
75545
  var utils_exports2 = {};
75138
75546
  __export(utils_exports2, {
75139
75547
  AUTHOR: () => AUTHOR,
75548
+ AUTH_ERROR_CODES: () => AUTH_ERROR_CODES,
75549
+ AUTH_FAILURE_THRESHOLD: () => AUTH_FAILURE_THRESHOLD,
75140
75550
  AuthenticationError: () => AuthenticationError,
75551
+ BASE_COOLDOWN_MS: () => BASE_COOLDOWN_MS,
75141
75552
  BRAND: () => BRAND,
75553
+ CHROME_MAJORS: () => CHROME_MAJORS,
75142
75554
  ConfigurationError: () => ConfigurationError,
75555
+ DESKTOP_PLATFORMS: () => DESKTOP_PLATFORMS,
75143
75556
  FCAError: () => FCAError,
75557
+ LS_DOC_TOKEN_ERRORS: () => LS_DOC_TOKEN_ERRORS,
75558
+ MAX_REQUESTS_IN_WINDOW: () => MAX_REQUESTS_IN_WINDOW,
75144
75559
  NUM_TO_DAY: () => NUM_TO_DAY,
75145
75560
  NUM_TO_MONTH: () => NUM_TO_MONTH,
75146
75561
  NetworkError: () => NetworkError,
75147
75562
  NotFoundError: () => NotFoundError,
75148
75563
  PermissionError: () => PermissionError,
75149
75564
  RateLimitError: () => RateLimitError,
75565
+ SESSION_COOKIE_NAMES: () => SESSION_COOKIE_NAMES,
75150
75566
  TimeoutError: () => TimeoutError,
75151
75567
  ValidationError: () => ValidationError,
75568
+ WINDOW_MS: () => WINDOW_MS,
75152
75569
  _formatAttachment: () => _formatAttachment,
75570
+ applySetCookie: () => applySetCookie,
75153
75571
  arrToForm: () => arrToForm,
75154
75572
  arrayToObject: () => arrayToObject2,
75573
+ awaitProactiveSlot: () => awaitProactiveSlot,
75155
75574
  banner: () => banner,
75156
75575
  binaryToDecimal: () => binaryToDecimal,
75157
75576
  brandTag: () => brandTag,
75577
+ buildProfile: () => buildProfile,
75158
75578
  buildWsTaskContent: () => buildWsTaskContent,
75579
+ canActProactively: () => canActProactively,
75159
75580
  cleanGet: () => cleanGet,
75160
75581
  cleanJsonResponse: () => cleanJsonResponse,
75582
+ collectSessionCookies: () => collectSessionCookies,
75161
75583
  debug: () => debug,
75162
75584
  decodeClientPayload: () => decodeClientPayload,
75585
+ defaultBrowserProfile: () => exports.defaultBrowserProfile,
75163
75586
  defaultUserAgent: () => defaultUserAgent,
75164
75587
  delay: () => delay2,
75165
75588
  ensureCometTokens: () => ensureCometTokens,
75166
75589
  error: () => error,
75167
75590
  extractAttachmentIds: () => extractAttachmentIds,
75591
+ extractCookies: () => extractCookies,
75592
+ extractCookiesFromBody: () => extractCookiesFromBody,
75593
+ extractCookiesFromJar: () => extractCookiesFromJar,
75594
+ extractCookiesFromSetCookie: () => extractCookiesFromSetCookie,
75595
+ extractDtsg: () => extractDtsg,
75596
+ extractLsd: () => extractLsd,
75597
+ extractSpin: () => extractSpin,
75598
+ formatAppStateCookie: () => formatAppStateCookie,
75168
75599
  formatAttachment: () => formatAttachment,
75169
75600
  formatCookie: () => formatCookie2,
75170
75601
  formatDate: () => formatDate,
@@ -75191,6 +75622,7 @@ __export(utils_exports2, {
75191
75622
  getAccessFromBusiness: () => getAccessFromBusiness,
75192
75623
  getAdminTextMessageType: () => getAdminTextMessageType,
75193
75624
  getAppState: () => getAppState,
75625
+ getFingerprintParams: () => getFingerprintParams,
75194
75626
  getFrom: () => getFrom,
75195
75627
  getGUID: () => getGUID,
75196
75628
  getHeaders: () => getHeaders,
@@ -75198,14 +75630,28 @@ __export(utils_exports2, {
75198
75630
  getRandom: () => getRandom,
75199
75631
  getSignatureID: () => getSignatureID,
75200
75632
  getType: () => getType,
75633
+ getWebSocketHeaders: () => getWebSocketHeaders,
75634
+ hasAuthenticatedSession: () => hasAuthenticatedSession,
75635
+ humanDelay: () => humanDelay,
75201
75636
  info: () => info,
75637
+ invalidateCometTokens: () => invalidateCometTokens,
75638
+ isAuthFailure: () => isAuthFailure,
75639
+ isBreakerOpen: () => isBreakerOpen,
75202
75640
  isReadableStream: () => isReadableStream2,
75641
+ isStaleTokenError: () => isStaleTokenError,
75203
75642
  json: () => json2,
75204
75643
  log: () => log,
75205
75644
  logOptions: () => logOptions,
75206
75645
  makeDefaults: () => makeDefaults,
75207
75646
  makeParsable: () => makeParsable,
75208
75647
  meta: () => meta,
75648
+ missingSessionCookies: () => missingSessionCookies,
75649
+ normalizeBrowserProfile: () => normalizeBrowserProfile,
75650
+ noteAction: () => noteAction,
75651
+ noteAuthFailure: () => noteAuthFailure,
75652
+ noteCheckpoint: () => noteCheckpoint,
75653
+ noteRateLimit: () => noteRateLimit,
75654
+ paceRequest: () => paceRequest,
75209
75655
  padZeros: () => padZeros,
75210
75656
  parseAndCheckLogin: () => parseAndCheckLogin,
75211
75657
  post: () => post,
@@ -75216,16 +75662,31 @@ __export(utils_exports2, {
75216
75662
  promisify: () => promisify,
75217
75663
  publishLsRequestWithAck: () => publishLsRequestWithAck,
75218
75664
  randomUserAgent: () => randomUserAgent,
75665
+ refreshSessionCookies: () => refreshSessionCookies,
75666
+ repairSession: () => repairSession,
75667
+ reserveRequest: () => reserveRequest,
75668
+ resetBreaker: () => resetBreaker,
75669
+ resolveProfile: () => resolveProfile,
75670
+ retryDelay: () => retryDelay,
75671
+ safetySnapshot: () => safetySnapshot,
75219
75672
  saveCookies: () => saveCookies,
75673
+ scheduleSessionKeepAlive: () => scheduleSessionKeepAlive,
75220
75674
  setProxy: () => setProxy2,
75675
+ sleep: () => sleep,
75676
+ startLiveness: () => startLiveness,
75221
75677
  success: () => success,
75678
+ tripBreaker: () => tripBreaker,
75222
75679
  uploadGroupImage: () => uploadGroupImage,
75223
75680
  uploadMercuryAttachment: () => uploadMercuryAttachment,
75681
+ warmUpSession: () => warmUpSession,
75224
75682
  warn: () => warn,
75225
75683
  windowsUserAgent: () => windowsUserAgent,
75684
+ withCometTokens: () => withCometTokens,
75685
+ withSessionRetry: () => withSessionRetry,
75226
75686
  ws: () => ws
75227
75687
  });
75228
75688
  init_axios3();
75689
+ init_headers();
75229
75690
  init_constants();
75230
75691
 
75231
75692
  // node_modules/cheerio/dist/esm/options.js
@@ -89434,8 +89895,34 @@ init_headers();
89434
89895
 
89435
89896
  // src/utils/clients.ts
89436
89897
  init_constants();
89898
+ function formatAppStateCookie(cookie) {
89899
+ const name = cookie.name || cookie.key;
89900
+ const value = String(cookie.value);
89901
+ const parts = [`${name}=${value}`];
89902
+ const path2 = cookie.path || "/";
89903
+ parts.push(`Path=${path2}`);
89904
+ const domain = cookie.domain || ".facebook.com";
89905
+ parts.push(`Domain=${domain}`);
89906
+ if (cookie.secure) parts.push("Secure");
89907
+ if (cookie.httpOnly) parts.push("HttpOnly");
89908
+ const sameSite = normalizeSameSite(cookie.sameSite);
89909
+ if (sameSite) parts.push(`SameSite=${sameSite}`);
89910
+ if (cookie.expirationDate && !cookie.session) {
89911
+ parts.push(`Expires=${new Date(cookie.expirationDate * 1e3).toUTCString()}`);
89912
+ }
89913
+ return parts.join("; ");
89914
+ }
89915
+ function normalizeSameSite(value) {
89916
+ if (!value) return null;
89917
+ const v = String(value).toLowerCase();
89918
+ if (v === "no_restriction" || v === "none") return "None";
89919
+ if (v === "lax") return "Lax";
89920
+ if (v === "strict") return "Strict";
89921
+ return null;
89922
+ }
89437
89923
  function formatCookie(arr, url2) {
89438
- return arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=" + url2 + ".com";
89924
+ const host = url2.replace(/^\./, "");
89925
+ return arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=." + host + "; Secure; SameSite=None";
89439
89926
  }
89440
89927
  function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89441
89928
  const delay3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -89444,7 +89931,7 @@ function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89444
89931
  throw new Error("parseAndCheckLogin received an invalid response.");
89445
89932
  }
89446
89933
  if (data2.statusCode >= 500 && data2.statusCode < 600) {
89447
- if (noRetry || retryCount >= 5) {
89934
+ if (noRetry || retryCount >= 3) {
89448
89935
  const err = new Error(
89449
89936
  "Request retry failed. Check the `res` and `statusCode` property on this error."
89450
89937
  );
@@ -89454,7 +89941,7 @@ function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89454
89941
  throw err;
89455
89942
  }
89456
89943
  retryCount++;
89457
- const retryTime = Math.floor(Math.random() * 5e3);
89944
+ const retryTime = Math.min(3e4, Math.floor(800 * Math.pow(1.7, retryCount) * (0.5 + Math.random())));
89458
89945
  const request = data2.request || {};
89459
89946
  const uri = request.uri || {};
89460
89947
  const url2 = request.url || (uri.protocol && uri.hostname ? uri.protocol + "//" + uri.hostname + (uri.port ? ":" + uri.port : "") + (uri.pathname || "") : "");
@@ -89504,17 +89991,17 @@ function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89504
89991
  } else {
89505
89992
  throw new Error("Unknown response body type: " + typeof data2.body);
89506
89993
  }
89507
- if (res.redirect && data2.request.method === "GET") {
89994
+ if (res.redirect && data2.request.method === "GET" && retryCount < 5) {
89508
89995
  const redirectRes = await http5.get(res.redirect, ctx.jar);
89509
- return await parseAndCheckLogin(ctx, http5)(redirectRes);
89996
+ return await parseAndCheckLogin(ctx, http5, retryCount + 1)(redirectRes);
89510
89997
  }
89511
89998
  if (res.jsmods && res.jsmods.require && Array.isArray(res.jsmods.require[0]) && res.jsmods.require[0][0] === "Cookie") {
89512
89999
  const requireCookie = res.jsmods.require[0][3];
89513
90000
  if (Array.isArray(requireCookie) && requireCookie.length >= 4) {
89514
90001
  const cookieValue = String(requireCookie[0]).replace("_js_", "");
89515
90002
  const normalizedCookie = [cookieValue, requireCookie[1], requireCookie[2], requireCookie[3]];
89516
- ctx.jar.setCookie(formatCookie(normalizedCookie, "facebook"), "https://www.facebook.com");
89517
- ctx.jar.setCookie(formatCookie(normalizedCookie, "messenger"), "https://www.messenger.com");
90003
+ ctx.jar.setCookieSync(formatCookie(normalizedCookie, "facebook"), "https://www.facebook.com");
90004
+ ctx.jar.setCookieSync(formatCookie(normalizedCookie, "messenger"), "https://www.messenger.com");
89518
90005
  }
89519
90006
  }
89520
90007
  if (res.jsmods && Array.isArray(res.jsmods.require)) {
@@ -89539,13 +90026,27 @@ function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89539
90026
  }
89540
90027
  function saveCookies(jar2) {
89541
90028
  return function(res) {
89542
- const cookies = res?.headers?.["set-cookie"] || [];
90029
+ const headers = res?.headers || {};
90030
+ const raw = headers["set-cookie"] || headers["Set-Cookie"] || [];
90031
+ const cookies = Array.isArray(raw) ? raw : [raw];
89543
90032
  cookies.forEach(function(c) {
89544
- if (c.indexOf(".facebook.com") > -1) {
89545
- jar2.setCookie(c, "https://www.facebook.com");
90033
+ if (!c || typeof c !== "string") return;
90034
+ if (/domain=\.?facebook\.com/i.test(c) || /domain=\.?messenger\.com/i.test(c)) {
90035
+ try {
90036
+ jar2.setCookieSync(c, "https://www.facebook.com");
90037
+ } catch {
90038
+ }
90039
+ try {
90040
+ const mirrored = c.replace(/domain=\.?facebook\.com/i, "domain=.messenger.com").replace(/domain=\.?messenger\.com/i, "domain=.facebook.com");
90041
+ jar2.setCookieSync(mirrored, "https://www.messenger.com");
90042
+ } catch {
90043
+ }
90044
+ } else {
90045
+ try {
90046
+ jar2.setCookieSync(`${c}; domain=.facebook.com; path=/`, "https://www.facebook.com");
90047
+ } catch {
90048
+ }
89546
90049
  }
89547
- const c2 = c.replace(/domain=\.facebook\.com/, "domain=.messenger.com");
89548
- jar2.setCookie(c2, "https://www.messenger.com");
89549
90050
  });
89550
90051
  return res;
89551
90052
  };
@@ -90075,43 +90576,8 @@ function formatProxyPresence(presence, userID) {
90075
90576
  };
90076
90577
  }
90077
90578
 
90078
- // src/utils/user-agents.ts
90079
- init_constants();
90080
- var BROWSER_DATA = {
90081
- windows: {
90082
- platform: "Windows NT 10.0; Win64; x64",
90083
- chromeVersions: ["126.0.0.0", "125.0.0.0", "124.0.0.0"],
90084
- platformVersion: '"15.0.0"'
90085
- },
90086
- mac: {
90087
- platform: "Macintosh; Intel Mac OS X 10_15_7",
90088
- chromeVersions: ["126.0.0.0", "125.0.0.0", "124.0.0.0"],
90089
- platformVersion: '"15.7.9"'
90090
- }
90091
- };
90092
- var defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36";
90093
- var windowsUserAgent = defaultUserAgent;
90094
- function randomUserAgent() {
90095
- const os = getRandom(Object.keys(BROWSER_DATA));
90096
- const data2 = BROWSER_DATA[os];
90097
- const version = getRandom(data2.chromeVersions);
90098
- const majorVersion = version.split(".")[0];
90099
- const userAgent = `Mozilla/5.0 (${data2.platform}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`;
90100
- const brands = [
90101
- `"Not/A)Brand";v="8"`,
90102
- `"Chromium";v="${majorVersion}"`,
90103
- `"Google Chrome";v="${majorVersion}"`
90104
- ];
90105
- const secChUa = brands.join(", ");
90106
- const secChUaFullVersionList = brands.map((b) => b.replace(/"$/, `.0.0.0"`)).join(", ");
90107
- return {
90108
- userAgent,
90109
- secChUa,
90110
- secChUaFullVersionList,
90111
- secChUaPlatform: `"${os === "windows" ? "Windows" : "macOS"}"`,
90112
- secChUaPlatformVersion: data2.platformVersion
90113
- };
90114
- }
90579
+ // src/utils/index.ts
90580
+ init_user_agents();
90115
90581
 
90116
90582
  // src/utils/errors.ts
90117
90583
  var FCAError = class extends Error {
@@ -90275,6 +90741,7 @@ function buildWsTaskContent(ctx, tasks, versionId) {
90275
90741
  // src/utils/attachments.ts
90276
90742
  var import_form_data3 = __toESM(require_form_data2());
90277
90743
  init_constants();
90744
+ init_user_agents();
90278
90745
  function cleanJsonResponse(value) {
90279
90746
  if (typeof value !== "string") return value;
90280
90747
  const normalized = value.replace(/^for\s*\(;;\);\s*/i, "");
@@ -90416,7 +90883,7 @@ function normalizeFilename(filename, mime) {
90416
90883
  return ext ? `${base}.${ext}` : base;
90417
90884
  }
90418
90885
  async function uploadMercuryAttachment(ctx, defaultFuncs, attachment) {
90419
- const normalized = await normalizeAttachmentInput(attachment);
90886
+ const normalized = await normalizeAttachmentInput(attachment, ctx);
90420
90887
  const url2 = "https://www.facebook.com/ajax/mercury/upload.php";
90421
90888
  await ensureUploadTokens(ctx, defaultFuncs);
90422
90889
  const formData = new import_form_data3.default();
@@ -90428,7 +90895,7 @@ async function uploadMercuryAttachment(ctx, defaultFuncs, attachment) {
90428
90895
  const data2 = cleanJsonResponse(res && res.body !== void 0 ? res.body : res);
90429
90896
  return finalizeUpload(data2);
90430
90897
  }
90431
- async function normalizeAttachmentInput(attachment) {
90898
+ async function normalizeAttachmentInput(attachment, ctx) {
90432
90899
  if (Buffer.isBuffer(attachment)) {
90433
90900
  const mime = sniffMime(attachment);
90434
90901
  return {
@@ -90440,7 +90907,11 @@ async function normalizeAttachmentInput(attachment) {
90440
90907
  const url2 = typeof attachment === "string" ? attachment : attachment && (attachment.url || attachment.href);
90441
90908
  if (typeof url2 === "string" && /^https?:\/\//i.test(url2)) {
90442
90909
  const resp = await fetch(url2, {
90443
- headers: { "User-Agent": "Mozilla/5.0", Accept: "*/*" }
90910
+ headers: {
90911
+ "User-Agent": ctx?.globalOptions && ctx.globalOptions.userAgent || exports.defaultBrowserProfile.userAgent,
90912
+ Accept: "image/avif,image/webp,image/apng,image/svg+xml,image/*,video/*,audio/*,*/*;q=0.8",
90913
+ "Accept-Language": ctx?.globalOptions && ctx.globalOptions.browser?.acceptLanguage || "en-US,en;q=0.9"
90914
+ }
90444
90915
  });
90445
90916
  if (!resp.ok) {
90446
90917
  throw new Error(`Failed to download attachment url (HTTP ${resp.status})`);
@@ -90530,7 +91001,21 @@ async function uploadGroupImage(ctx, defaultFuncs, image) {
90530
91001
  }
90531
91002
 
90532
91003
  // src/utils/lsd.ts
90533
- var TOKEN_TTL_MS = 30 * 60 * 1e3;
91004
+ var TOKEN_TTL_MS = 10 * 60 * 1e3;
91005
+ var STALE_TOKEN_ERRORS = /* @__PURE__ */ new Set([
91006
+ 1357004,
91007
+ // "Sorry, something went wrong / close and re-open your browser window"
91008
+ 1357031,
91009
+ // document token invalid
91010
+ 1357051
91011
+ // token mismatch
91012
+ ]);
91013
+ var MAX_BACKOFF_MS = 60 * 1e3;
91014
+ function tokenState(ctx) {
91015
+ const state = ctx.__cometTokens || (ctx.__cometTokens = {});
91016
+ if (typeof state.failures !== "number") state.failures = 0;
91017
+ return state;
91018
+ }
90534
91019
  function getFrom3(html3, startToken, endToken) {
90535
91020
  const startIndex = html3.indexOf(startToken);
90536
91021
  if (startIndex < 0) return "";
@@ -90545,34 +91030,544 @@ function extractLsd(html3) {
90545
91030
  function extractDtsg(html3) {
90546
91031
  return getFrom3(html3, '["DTSGInitialData",[],{"token":"', '"}') || getFrom3(html3, 'name="fb_dtsg" value="', '"') || (html3.match(/"DTSGInitialData",\[\],\{"token":"([^"]+)"/) || [])[1] || "";
90547
91032
  }
91033
+ function extractSpin(html3) {
91034
+ const out = {};
91035
+ const spinB = (html3.match(/"__spin_b":"([^"]+)"/) || [])[1];
91036
+ const spinR = (html3.match(/"__spin_r":(\d+)/) || [])[1];
91037
+ const spinT = (html3.match(/"__spin_t":(\d+)/) || [])[1];
91038
+ const rev = (html3.match(/"__rev":(\d+)/) || [])[1] || getFrom3(html3, 'revision":', ",");
91039
+ if (spinB) out.__spin_b = spinB;
91040
+ if (spinR) out.__spin_r = spinR;
91041
+ if (spinT) out.__spin_t = spinT;
91042
+ if (rev) out.__rev = rev;
91043
+ return out;
91044
+ }
91045
+ function recomputeJazoest(fbDtsg) {
91046
+ let sum = 0;
91047
+ for (let i2 = 0; i2 < fbDtsg.length; i2++) sum += fbDtsg.charCodeAt(i2);
91048
+ return "2" + String(sum);
91049
+ }
91050
+ function tokenPairFresh(state) {
91051
+ return Boolean(
91052
+ state.lsd && state.fb_dtsg && state.fetchedAt && Date.now() - state.fetchedAt < TOKEN_TTL_MS
91053
+ );
91054
+ }
91055
+ function htmlOf(res) {
91056
+ if (typeof res === "string") return res;
91057
+ if (res && typeof res.body === "string") return res.body;
91058
+ if (res && res.body != null) return String(res.body);
91059
+ return "";
91060
+ }
90548
91061
  async function ensureCometTokens(ctx, defaultFuncs, force = false) {
90549
- const state = ctx.__cometTokens || (ctx.__cometTokens = {});
90550
- const fresh = state.fetchedAt && Date.now() - state.fetchedAt < TOKEN_TTL_MS;
90551
- if (!force && fresh && state.lsd && state.fb_dtsg) {
91062
+ const state = tokenState(ctx);
91063
+ if (!force && tokenPairFresh(state)) {
90552
91064
  ctx.lsd = state.lsd;
90553
91065
  ctx.fb_dtsg = state.fb_dtsg;
90554
91066
  return;
90555
91067
  }
91068
+ if (!force && state.failures > 0) {
91069
+ const backoff = Math.min(1e3 * Math.pow(2, state.failures), MAX_BACKOFF_MS);
91070
+ if (state.attemptedAt && Date.now() - state.attemptedAt < backoff) {
91071
+ if (state.lsd && state.fb_dtsg) {
91072
+ ctx.lsd = state.lsd;
91073
+ ctx.fb_dtsg = state.fb_dtsg;
91074
+ }
91075
+ return;
91076
+ }
91077
+ }
91078
+ state.attemptedAt = Date.now();
90556
91079
  try {
90557
91080
  const res = await defaultFuncs.get("https://www.facebook.com/", ctx.jar);
90558
- const html3 = typeof res === "string" ? res : res && res.body;
90559
- if (typeof html3 !== "string") return;
91081
+ const html3 = htmlOf(res);
91082
+ if (!html3) {
91083
+ state.failures++;
91084
+ return;
91085
+ }
90560
91086
  const lsd = extractLsd(html3);
90561
91087
  const dtsg = extractDtsg(html3);
90562
- if (lsd) state.lsd = lsd;
90563
- if (dtsg) state.fb_dtsg = dtsg;
91088
+ if (!lsd || !dtsg) {
91089
+ state.failures++;
91090
+ return;
91091
+ }
91092
+ state.lsd = lsd;
91093
+ state.fb_dtsg = dtsg;
90564
91094
  state.fetchedAt = Date.now();
90565
- if (state.lsd) ctx.lsd = state.lsd;
90566
- if (state.fb_dtsg) {
90567
- ctx.fb_dtsg = state.fb_dtsg;
90568
- if (typeof ctx.jazoest !== "string" || !ctx.jazoest) {
90569
- let sum = 0;
90570
- for (let i2 = 0; i2 < ctx.fb_dtsg.length; i2++) sum += ctx.fb_dtsg.charCodeAt(i2);
90571
- ctx.jazoest = "2" + String(sum);
91095
+ state.failures = 0;
91096
+ const spin = extractSpin(html3);
91097
+ if (Object.keys(spin).length) ctx.__spin = { ...ctx.__spin || {}, ...spin };
91098
+ if (spin.__rev) ctx.revision = spin.__rev;
91099
+ ctx.lsd = lsd;
91100
+ ctx.fb_dtsg = dtsg;
91101
+ ctx.jazoest = recomputeJazoest(dtsg);
91102
+ } catch {
91103
+ state.failures++;
91104
+ }
91105
+ }
91106
+ function invalidateCometTokens(ctx) {
91107
+ const state = tokenState(ctx);
91108
+ state.lsd = void 0;
91109
+ state.fb_dtsg = void 0;
91110
+ state.fetchedAt = void 0;
91111
+ state.failures = 0;
91112
+ state.attemptedAt = 0;
91113
+ delete ctx.lsd;
91114
+ delete ctx.fb_dtsg;
91115
+ }
91116
+ function isStaleTokenError(value) {
91117
+ if (value == null) return false;
91118
+ if (typeof value === "number") return STALE_TOKEN_ERRORS.has(value);
91119
+ if (typeof value === "object") {
91120
+ const code = Number(value.error ?? value.code ?? value.errorCode);
91121
+ if (STALE_TOKEN_ERRORS.has(code)) return true;
91122
+ const text3 = String(value.errorDescription || value.errorSummary || value.message || "");
91123
+ return /clos(?:e|ing) (?:and|then) re-?open|invalid document|invalid token|stale token|re-?open your browser/i.test(
91124
+ text3
91125
+ );
91126
+ }
91127
+ return false;
91128
+ }
91129
+ var LS_DOC_TOKEN_ERRORS = STALE_TOKEN_ERRORS;
91130
+ async function withCometTokens(ctx, defaultFuncs, run, options = {}) {
91131
+ const retries = Math.max(1, options.retries ?? 2);
91132
+ let last2;
91133
+ for (let attempt = 0; attempt < retries; attempt++) {
91134
+ await ensureCometTokens(ctx, defaultFuncs, attempt > 0);
91135
+ last2 = await run();
91136
+ if (!isStaleTokenError(last2)) return last2;
91137
+ invalidateCometTokens(ctx);
91138
+ }
91139
+ return last2;
91140
+ }
91141
+
91142
+ // src/utils/session.ts
91143
+ init_safety();
91144
+ var SESSION_COOKIE_NAMES = /* @__PURE__ */ new Set([
91145
+ "c_user",
91146
+ "xs",
91147
+ "fr",
91148
+ "datr",
91149
+ "sb",
91150
+ "presence",
91151
+ "wd",
91152
+ "dpr",
91153
+ "locale"
91154
+ ]);
91155
+ var AUTH_ERROR_CODES = /* @__PURE__ */ new Set([
91156
+ 1357001,
91157
+ // "Facebook blocked the login"
91158
+ 1357002,
91159
+ // not logged in
91160
+ 1357031,
91161
+ // document token invalid (treated as auth-adjacent here)
91162
+ 1357046,
91163
+ 1357036
91164
+ ]);
91165
+ function isCookieJar(jar2) {
91166
+ return Boolean(jar2) && typeof jar2.getCookiesSync === "function";
91167
+ }
91168
+ function extractCookiesFromJar(jar2) {
91169
+ const out = {};
91170
+ if (!isCookieJar(jar2)) return out;
91171
+ const origins = [
91172
+ "https://www.facebook.com",
91173
+ "https://facebook.com",
91174
+ "https://mbasic.facebook.com",
91175
+ "https://web.facebook.com",
91176
+ "https://www.messenger.com",
91177
+ "https://messenger.com"
91178
+ ];
91179
+ for (const origin2 of origins) {
91180
+ try {
91181
+ const cookies = jar2.getCookiesSync(origin2) || [];
91182
+ for (const cookie of cookies) {
91183
+ const key = cookie && (cookie.key || cookie.name);
91184
+ const value = cookie && cookie.value;
91185
+ if (!key || value == null) continue;
91186
+ if (!(key in out) || /facebook\.com$/.test(cookie.domain || "")) {
91187
+ out[key] = String(value);
91188
+ }
91189
+ }
91190
+ } catch {
91191
+ }
91192
+ }
91193
+ return out;
91194
+ }
91195
+ function extractCookiesFromSetCookie(header) {
91196
+ const out = {};
91197
+ if (!header) return out;
91198
+ const list = Array.isArray(header) ? header : [String(header)];
91199
+ for (const raw of list) {
91200
+ const parts = String(raw).split(/,(?=\s*[^=;,\s]+\s*=)/);
91201
+ for (const part of parts) {
91202
+ const firstSegment = part.split(";")[0].trim();
91203
+ const eq2 = firstSegment.indexOf("=");
91204
+ if (eq2 <= 0) continue;
91205
+ const name = firstSegment.slice(0, eq2).trim();
91206
+ const value = firstSegment.slice(eq2 + 1).trim();
91207
+ if (name) out[name] = value;
91208
+ }
91209
+ }
91210
+ return out;
91211
+ }
91212
+ function extractCookiesFromBody(body) {
91213
+ const out = {};
91214
+ if (body == null) return out;
91215
+ const text3 = typeof body === "string" ? body : JSON.stringify(body);
91216
+ if (!text3) return out;
91217
+ const re = /(?:document\.cookie\s*=\s*|setCookie\(\s*)["'\\]*([A-Za-z0-9_]+)=([^"';\s\\]+)/g;
91218
+ let match;
91219
+ while ((match = re.exec(text3)) !== null) {
91220
+ out[match[1]] = match[2];
91221
+ }
91222
+ return out;
91223
+ }
91224
+ function extractCookies(sources) {
91225
+ const merged = {};
91226
+ const seen = [];
91227
+ const fromJar = extractCookiesFromJar(sources.jar);
91228
+ if (Object.keys(fromJar).length) {
91229
+ Object.assign(merged, fromJar);
91230
+ seen.push("jar");
91231
+ }
91232
+ const fromHeader = extractCookiesFromSetCookie(sources.setCookie);
91233
+ if (Object.keys(fromHeader).length) {
91234
+ Object.assign(merged, fromHeader);
91235
+ seen.push("set-cookie");
91236
+ }
91237
+ const fromBody = extractCookiesFromBody(sources.body);
91238
+ if (Object.keys(fromBody).length) {
91239
+ Object.assign(merged, fromBody);
91240
+ seen.push("body");
91241
+ }
91242
+ return { cookies: merged, count: Object.keys(merged).length, sources: seen };
91243
+ }
91244
+ function applySetCookie(jar2, header) {
91245
+ if (!isCookieJar(jar2) || !header) return 0;
91246
+ const list = Array.isArray(header) ? header : [String(header)];
91247
+ let applied = 0;
91248
+ for (const raw of list) {
91249
+ if (!raw || typeof raw !== "string") continue;
91250
+ try {
91251
+ jar2.setCookieSync(raw, "https://www.facebook.com");
91252
+ applied++;
91253
+ } catch {
91254
+ try {
91255
+ const normalized = raw.replace(/domain=\.?facebook\.com/i, "Domain=.facebook.com").replace(/;\s*$/, "");
91256
+ jar2.setCookieSync(normalized, "https://www.facebook.com");
91257
+ applied++;
91258
+ } catch {
91259
+ }
91260
+ }
91261
+ if (/domain=\.?facebook\.com/i.test(raw)) {
91262
+ try {
91263
+ jar2.setCookieSync(raw.replace(/domain=\.?facebook\.com/i, "domain=.messenger.com"), "https://www.messenger.com");
91264
+ } catch {
91265
+ }
91266
+ }
91267
+ }
91268
+ return applied;
91269
+ }
91270
+ function hasAuthenticatedSession(jar2) {
91271
+ const cookies = extractCookiesFromJar(jar2);
91272
+ return Boolean(cookies.c_user && (cookies.xs || cookies.fr));
91273
+ }
91274
+ function collectSessionCookies(ctx, host) {
91275
+ const origins = /* @__PURE__ */ new Set([
91276
+ "https://www.facebook.com",
91277
+ "https://facebook.com",
91278
+ "https://web.facebook.com",
91279
+ "https://mbasic.facebook.com",
91280
+ "https://www.messenger.com",
91281
+ "https://messenger.com",
91282
+ "https://edge-chat.messenger.com",
91283
+ "https://gateway.facebook.com"
91284
+ ]);
91285
+ if (host) {
91286
+ try {
91287
+ origins.add(new URL(host).origin);
91288
+ } catch {
91289
+ }
91290
+ }
91291
+ const seen = {};
91292
+ const parts = [];
91293
+ for (const origin2 of origins) {
91294
+ let list = [];
91295
+ try {
91296
+ list = ctx?.jar?.getCookiesSync(origin2) || [];
91297
+ } catch {
91298
+ list = [];
91299
+ }
91300
+ for (const cookie of list) {
91301
+ const name = cookie?.key || cookie?.name;
91302
+ if (!name || seen[name]) continue;
91303
+ seen[name] = true;
91304
+ try {
91305
+ parts.push(cookie.cookieString ? cookie.cookieString() : `${name}=${cookie.value}`);
91306
+ } catch {
91307
+ parts.push(`${name}=${cookie.value}`);
91308
+ }
91309
+ }
91310
+ }
91311
+ return parts.join("; ");
91312
+ }
91313
+ function missingSessionCookies(jar2) {
91314
+ const cookies = extractCookiesFromJar(jar2);
91315
+ const missing = [];
91316
+ if (!cookies.c_user) missing.push("c_user");
91317
+ if (!cookies.xs) missing.push("xs");
91318
+ if (!cookies.fr) missing.push("fr");
91319
+ if (!cookies.datr) missing.push("datr");
91320
+ return missing;
91321
+ }
91322
+ function defaultFuncsGet(defaultFuncs, url2, jar2) {
91323
+ return defaultFuncs.get(url2, jar2);
91324
+ }
91325
+ async function refreshSessionCookies(ctx, defaultFuncs, options = {}) {
91326
+ const surfaces = options.surfaces || [
91327
+ "https://www.facebook.com/",
91328
+ "https://www.messenger.com/"
91329
+ ];
91330
+ let applied = 0;
91331
+ const errors = [];
91332
+ for (const url2 of surfaces) {
91333
+ try {
91334
+ const res = await defaultFuncsGet(defaultFuncs, url2, ctx.jar);
91335
+ const headers = res && res.headers || {};
91336
+ const setCookie = headers["set-cookie"] || headers["Set-Cookie"];
91337
+ applied += applySetCookie(ctx.jar, setCookie);
91338
+ const embedded = extractCookiesFromBody(res && (res.body ?? res));
91339
+ for (const [name, value] of Object.entries(embedded)) {
91340
+ try {
91341
+ ctx.jar.setCookieSync(`${name}=${value}; domain=.facebook.com; path=/; Secure; SameSite=None`, "https://www.facebook.com");
91342
+ applied++;
91343
+ } catch {
91344
+ }
91345
+ }
91346
+ if (typeof res?.body === "string" && res.body.includes("DTSGInitialData")) {
91347
+ invalidateCometTokens(ctx);
91348
+ }
91349
+ } catch (error2) {
91350
+ errors.push(`${url2}: ${error2 && (error2.message || error2.error || error2)}`);
91351
+ }
91352
+ }
91353
+ const extracted = extractCookies({ jar: ctx.jar });
91354
+ const authenticated = hasAuthenticatedSession(ctx.jar);
91355
+ if (applied > 0) ctx.__lastCookieRefreshAt = Date.now();
91356
+ return { ...extracted, applied, authenticated, errors };
91357
+ }
91358
+ function isAuthFailure(value) {
91359
+ if (value == null) return false;
91360
+ if (typeof value === "number") return AUTH_ERROR_CODES.has(value);
91361
+ if (typeof value === "object") {
91362
+ const code = Number(value.error ?? value.code ?? value.errorCode ?? value.statusCode);
91363
+ if (AUTH_ERROR_CODES.has(code)) return true;
91364
+ const text3 = String(value.error || value.message || value.errorDescription || "");
91365
+ return /not logged in|blocked the login|session (?:has )?expired|requires_reauth|please log in again/i.test(text3);
91366
+ }
91367
+ return false;
91368
+ }
91369
+ async function withSessionRetry(ctx, defaultFuncs, operation, options = {}) {
91370
+ const attempts = Math.max(1, options.attempts ?? 2);
91371
+ let lastError;
91372
+ for (let i2 = 0; i2 < attempts; i2++) {
91373
+ try {
91374
+ const result = await operation();
91375
+ if (isAuthFailure(result)) {
91376
+ lastError = result;
91377
+ noteAuthFailure(ctx);
91378
+ if (i2 === attempts - 1) throw result;
91379
+ if (options.onRecover) options.onRecover({ attempt: i2 + 1, error: result });
91380
+ await repairSession(ctx, defaultFuncs);
91381
+ continue;
90572
91382
  }
91383
+ resetBreaker(ctx);
91384
+ return result;
91385
+ } catch (error2) {
91386
+ lastError = error2;
91387
+ if (!isAuthFailure(error2) || i2 === attempts - 1) throw error2;
91388
+ noteAuthFailure(ctx);
91389
+ if (options.onRecover) options.onRecover({ attempt: i2 + 1, error: error2 });
91390
+ await repairSession(ctx, defaultFuncs);
90573
91391
  }
91392
+ }
91393
+ throw lastError || new Error("Operation failed after session retries.");
91394
+ }
91395
+ async function repairSession(ctx, defaultFuncs) {
91396
+ invalidateCometTokens(ctx);
91397
+ let ok = false;
91398
+ try {
91399
+ const refresh = await refreshSessionCookies(ctx, defaultFuncs);
91400
+ ok = refresh.authenticated;
90574
91401
  } catch {
91402
+ ok = false;
91403
+ }
91404
+ if (typeof ctx.__resetMqttBackoff === "function") {
91405
+ try {
91406
+ ctx.__resetMqttBackoff();
91407
+ } catch {
91408
+ }
90575
91409
  }
91410
+ return ok;
91411
+ }
91412
+ function scheduleSessionKeepAlive(ctx, defaultFuncs, intervalMs = 15 * 60 * 1e3) {
91413
+ if (ctx.__cookieKeepAliveTimer) {
91414
+ clearInterval(ctx.__cookieKeepAliveTimer);
91415
+ ctx.__cookieKeepAliveTimer = null;
91416
+ }
91417
+ const jitter = () => intervalMs * (0.85 + Math.random() * 0.3);
91418
+ let stopped = false;
91419
+ const tick = async () => {
91420
+ if (stopped || ctx.loggedIn === false) return;
91421
+ try {
91422
+ await refreshSessionCookies(ctx, defaultFuncs);
91423
+ } catch {
91424
+ } finally {
91425
+ if (!stopped) ctx.__cookieKeepAliveTimer = setTimeout(tick, jitter());
91426
+ }
91427
+ };
91428
+ ctx.__cookieKeepAliveTimer = setTimeout(tick, jitter());
91429
+ return () => {
91430
+ stopped = true;
91431
+ if (ctx.__cookieKeepAliveTimer) {
91432
+ clearTimeout(ctx.__cookieKeepAliveTimer);
91433
+ ctx.__cookieKeepAliveTimer = null;
91434
+ }
91435
+ };
91436
+ }
91437
+
91438
+ // src/utils/index.ts
91439
+ init_pacing();
91440
+
91441
+ // src/utils/warmup.ts
91442
+ init_pacing();
91443
+ var SURFACES = [
91444
+ "https://www.facebook.com/",
91445
+ "https://www.facebook.com/messages/t/",
91446
+ "https://www.messenger.com/"
91447
+ ];
91448
+ async function warmUpSession(ctx, getter, options = {}) {
91449
+ const visited = [];
91450
+ const errors = [];
91451
+ let cookiesApplied = 0;
91452
+ let tokensSeeded = false;
91453
+ if (!hasAuthenticatedSession(ctx.jar)) {
91454
+ return { visited, cookiesApplied, authenticated: false, tokensSeeded, errors: ["no authenticated session cookies"] };
91455
+ }
91456
+ const surfaces = options.includeMessenger === false ? SURFACES.slice(0, 2) : SURFACES;
91457
+ for (const url2 of surfaces) {
91458
+ try {
91459
+ const res = await getter(url2, ctx.jar, null, ctx.globalOptions, ctx, { noRef: true });
91460
+ visited.push(url2);
91461
+ const headers = res && res.headers || {};
91462
+ cookiesApplied += applySetCookie(ctx.jar, headers["set-cookie"] || headers["Set-Cookie"]);
91463
+ const html3 = typeof res === "string" ? res : res && res.body;
91464
+ if (typeof html3 === "string" && html3.includes("DTSGInitialData")) {
91465
+ const lsd = extractLsd(html3);
91466
+ const dtsg = extractDtsg(html3);
91467
+ if (lsd && dtsg) {
91468
+ ctx.__cometTokens = { lsd, fb_dtsg: dtsg, fetchedAt: Date.now(), failures: 0 };
91469
+ ctx.lsd = lsd;
91470
+ ctx.fb_dtsg = dtsg;
91471
+ ctx.jazoest = "2" + Array.from(dtsg).reduce((a, b) => a + b.charCodeAt(0), 0);
91472
+ const spin = extractSpin(html3);
91473
+ if (Object.keys(spin).length) ctx.__spin = { ...ctx.__spin || {}, ...spin };
91474
+ if (spin.__rev) ctx.revision = spin.__rev;
91475
+ tokensSeeded = true;
91476
+ }
91477
+ } else if (url2.includes("/messages")) {
91478
+ invalidateCometTokens(ctx);
91479
+ }
91480
+ await sleep(humanDelay(650, 420));
91481
+ } catch (error2) {
91482
+ errors.push(`${url2}: ${error2 && (error2.message || error2.error || error2)}`);
91483
+ }
91484
+ }
91485
+ const extracted = extractCookies({ jar: ctx.jar });
91486
+ return {
91487
+ visited,
91488
+ cookiesApplied,
91489
+ authenticated: hasAuthenticatedSession(ctx.jar),
91490
+ tokensSeeded,
91491
+ errors: [...errors, ...extracted.count ? [] : ["no cookies extracted"]]
91492
+ };
91493
+ }
91494
+
91495
+ // src/utils/index.ts
91496
+ init_safety();
91497
+
91498
+ // src/utils/liveness.ts
91499
+ init_pacing();
91500
+ init_safety();
91501
+ var ACTIVE_MIN_MS = 6 * 60 * 1e3;
91502
+ var ACTIVE_MAX_MS = 14 * 60 * 1e3;
91503
+ var IDLE_MIN_MS = 2 * 60 * 1e3;
91504
+ var IDLE_MAX_MS = 7 * 60 * 1e3;
91505
+ function randBetween(min, max) {
91506
+ return Math.floor(min + Math.random() * (max - min));
91507
+ }
91508
+ function startLiveness(ctx, options = {}) {
91509
+ if (ctx.__livenessStop) {
91510
+ try {
91511
+ ctx.__livenessStop();
91512
+ } catch {
91513
+ }
91514
+ }
91515
+ ctx.__requestsPaced = ctx.__requestsPaced || 0;
91516
+ let stopped = false;
91517
+ let active = true;
91518
+ let nextAt = Date.now() + randBetween(ACTIVE_MIN_MS, ACTIVE_MAX_MS);
91519
+ let timer = null;
91520
+ ctx.__foreground = true;
91521
+ const schedule = () => {
91522
+ if (stopped) return;
91523
+ const wait = Math.max(1e3, nextAt - Date.now());
91524
+ timer = setTimeout(tick, wait);
91525
+ if (timer && typeof timer.unref === "function") timer.unref();
91526
+ };
91527
+ const tick = () => {
91528
+ if (stopped) return;
91529
+ active = !active;
91530
+ ctx.__foreground = active ? !!ctx.globalOptions?.online : false;
91531
+ try {
91532
+ if (active) options.foregroundPing?.();
91533
+ else options.backgroundPing?.();
91534
+ } catch {
91535
+ }
91536
+ nextAt = Date.now() + (active ? randBetween(ACTIVE_MIN_MS, ACTIVE_MAX_MS) : randBetween(IDLE_MIN_MS, IDLE_MAX_MS));
91537
+ schedule();
91538
+ };
91539
+ schedule();
91540
+ const stop = () => {
91541
+ stopped = true;
91542
+ if (timer) {
91543
+ clearTimeout(timer);
91544
+ timer = null;
91545
+ }
91546
+ ctx.__livenessStop = null;
91547
+ };
91548
+ ctx.__livenessStop = stop;
91549
+ return {
91550
+ stop,
91551
+ state: () => ({
91552
+ active,
91553
+ nextTransitionMs: Math.max(0, nextAt - Date.now()),
91554
+ requests: ctx.__requestsPaced || 0,
91555
+ breakerOpen: isBreakerOpen(ctx)
91556
+ })
91557
+ };
91558
+ }
91559
+ function canActProactively(ctx) {
91560
+ if (isBreakerOpen(ctx)) return false;
91561
+ if (ctx.__foreground === false) return false;
91562
+ return true;
91563
+ }
91564
+ async function awaitProactiveSlot(ctx, maxWaitMs = 15 * 60 * 1e3) {
91565
+ const deadline = Date.now() + maxWaitMs;
91566
+ while (Date.now() < deadline) {
91567
+ if (canActProactively(ctx)) return true;
91568
+ await sleep(humanDelay(4e3, 3e3));
91569
+ }
91570
+ return false;
90576
91571
  }
90577
91572
 
90578
91573
  // src/utils/index.ts
@@ -90604,19 +91599,32 @@ async function json2(url2, jar2, qs2, options, ctx, customHeader) {
90604
91599
  }
90605
91600
  }
90606
91601
  function makeDefaults(html3, userID, ctx) {
90607
- let reqCounter = 1;
90608
91602
  const revision = getFrom(html3, 'revision":', ",");
90609
91603
  function mergeWithDefaults(obj) {
91604
+ const reqId = (() => {
91605
+ ctx.__reqCounter = (typeof ctx.__reqCounter === "number" ? ctx.__reqCounter : 0) + 1;
91606
+ return ctx.__reqCounter.toString(36);
91607
+ })();
91608
+ const spin = ctx.__spin || {};
90610
91609
  const newObj = {
90611
91610
  av: userID,
90612
91611
  __user: userID,
90613
- __req: (reqCounter++).toString(36),
90614
- __rev: revision,
91612
+ __req: reqId,
91613
+ __rev: ctx.revision || revision,
90615
91614
  __a: 1,
90616
91615
  ...ctx && {
90617
91616
  fb_dtsg: ctx.fb_dtsg,
90618
91617
  jazoest: ctx.jazoest
90619
- }
91618
+ },
91619
+ // The Comet document token and its spin siblings gate GraphQL; include
91620
+ // them whenever they are known so no module has to remember.
91621
+ ...ctx && ctx.lsd ? { lsd: ctx.lsd } : {},
91622
+ ...spin.__spin_b ? { __spin_b: spin.__spin_b } : {},
91623
+ ...spin.__spin_r ? { __spin_r: spin.__spin_r } : {},
91624
+ ...spin.__spin_t ? { __spin_t: spin.__spin_t } : {},
91625
+ // Device pixel ratio must match the Client Hints profile the headers
91626
+ // advertise, otherwise the form and the headers disagree.
91627
+ ...getFingerprintParams(ctx?.globalOptions)
90620
91628
  };
90621
91629
  if (!obj) return newObj;
90622
91630
  for (const prop2 in obj) {
@@ -90627,13 +91635,18 @@ function makeDefaults(html3, userID, ctx) {
90627
91635
  return newObj;
90628
91636
  }
90629
91637
  return {
90630
- get: (url2, jar2, qs2, ctxx, customHeader = {}) => get(url2, jar2, mergeWithDefaults(qs2), ctx.globalOptions, ctxx || ctx, customHeader),
91638
+ // GET carries only caller-supplied query parameters. The shared form
91639
+ // defaults (av/__user/fb_dtsg/jazoest/lsd/…) are a POST body and must never
91640
+ // be appended to a document URL: Facebook treats a document GET that
91641
+ // carries form state as an AJAX call and answers with a 1357004 JSON error
91642
+ // instead of the page, which is exactly the "stale token" symptom.
91643
+ get: (url2, jar2, qs2, ctxx, customHeader = {}) => get(url2, jar2, qs2, ctx.globalOptions, ctxx || ctx, customHeader),
90631
91644
  post: (url2, jar2, form, ctxx, customHeader = {}) => post(url2, jar2, mergeWithDefaults(form), ctx.globalOptions, ctxx || ctx, customHeader),
90632
91645
  postFormData: (url2, jar2, form, qs2, ctxx, customHeader) => postFormData(
90633
91646
  url2,
90634
91647
  jar2,
90635
91648
  mergeWithDefaults(form),
90636
- mergeWithDefaults(qs2),
91649
+ qs2,
90637
91650
  ctx.globalOptions,
90638
91651
  ctxx || ctx,
90639
91652
  customHeader
@@ -90657,7 +91670,19 @@ async function setOptions(globalOptions, options = {}) {
90657
91670
  listenEvents: (value) => globalOptions.listenEvents = Boolean(value),
90658
91671
  updatePresence: (value) => globalOptions.updatePresence = Boolean(value),
90659
91672
  forceLogin: (value) => globalOptions.forceLogin = Boolean(value),
90660
- userAgent: (value) => globalOptions.userAgent = value,
91673
+ userAgent: (value) => {
91674
+ globalOptions.userAgent = value;
91675
+ globalOptions.browser = normalizeBrowserProfile({
91676
+ ...globalOptions.browser || exports.defaultBrowserProfile,
91677
+ userAgent: value
91678
+ });
91679
+ },
91680
+ browser: (value) => {
91681
+ if (!value || typeof value !== "object") return;
91682
+ const profile = normalizeBrowserProfile(value);
91683
+ globalOptions.browser = profile;
91684
+ globalOptions.userAgent = profile.userAgent;
91685
+ },
90661
91686
  autoMarkDelivery: (value) => globalOptions.autoMarkDelivery = Boolean(value),
90662
91687
  autoMarkRead: (value) => globalOptions.autoMarkRead = Boolean(value),
90663
91688
  listenTyping: (value) => globalOptions.listenTyping = Boolean(value),
@@ -90675,8 +91700,9 @@ async function setOptions(globalOptions, options = {}) {
90675
91700
  randomUserAgent(value) {
90676
91701
  globalOptions.randomUserAgent = Boolean(value);
90677
91702
  if (value) {
90678
- const ua = randomUserAgent();
90679
- globalOptions.userAgent = ua.userAgent;
91703
+ const profile = randomUserAgent();
91704
+ globalOptions.browser = profile;
91705
+ globalOptions.userAgent = profile.userAgent;
90680
91706
  }
90681
91707
  },
90682
91708
  bypassRegion(value) {
@@ -90694,7 +91720,20 @@ async function setOptions(globalOptions, options = {}) {
90694
91720
  // src/core/models/buildAPI.ts
90695
91721
  async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRetrievingMsg) {
90696
91722
  const userID = (() => {
90697
- const cookies = jar2.getCookiesSync(fbLinkFunc());
91723
+ const origins = [
91724
+ "https://www.facebook.com",
91725
+ "https://facebook.com",
91726
+ "https://web.facebook.com",
91727
+ "https://mbasic.facebook.com",
91728
+ "https://www.messenger.com"
91729
+ ];
91730
+ let cookies = [];
91731
+ for (const origin2 of origins) {
91732
+ try {
91733
+ cookies = cookies.concat(jar2.getCookiesSync(origin2) || []);
91734
+ } catch {
91735
+ }
91736
+ }
90698
91737
  const primaryProfile = cookies.find(
90699
91738
  (val2) => val2.cookieString().startsWith("c_user=")
90700
91739
  );
@@ -90702,6 +91741,13 @@ async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRe
90702
91741
  (val2) => val2.cookieString().startsWith("i_user=")
90703
91742
  );
90704
91743
  if (!primaryProfile && !secondaryProfile) {
91744
+ const hasXs = cookies.some((val2) => val2.cookieString().startsWith("xs="));
91745
+ const hasDatr = cookies.some((val2) => val2.cookieString().startsWith("datr="));
91746
+ if (hasXs || hasDatr) {
91747
+ throw new Error(
91748
+ "Facebook session expired or invalid (cookies present but no c_user). Export a fresh appState from a logged-in browser and try again."
91749
+ );
91750
+ }
90705
91751
  throw new Error(errorRetrievingMsg);
90706
91752
  }
90707
91753
  return secondaryProfile?.cookieString().split("=")[1] || primaryProfile.cookieString().split("=")[1];
@@ -90726,7 +91772,7 @@ async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRe
90726
91772
  return null;
90727
91773
  };
90728
91774
  const dtsgData = findConfig("DTSGInitialData");
90729
- const dtsg = dtsgData ? dtsgData.token : getFrom(html3, '"token":"', '"');
91775
+ const dtsg = dtsgData ? dtsgData.token : extractDtsg(html3) || getFrom(html3, '"token":"', '"');
90730
91776
  if (typeof dtsg !== "string" || dtsg.length === 0) {
90731
91777
  throw new Error("Unable to retrieve Facebook form security token (fb_dtsg).");
90732
91778
  }
@@ -90737,6 +91783,10 @@ async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRe
90737
91783
  0
90738
91784
  )}`
90739
91785
  };
91786
+ const lsdConfig = findConfig("LSD");
91787
+ const lsd = lsdConfig && lsdConfig.token || extractLsd(html3) || void 0;
91788
+ const spin = extractSpin(html3);
91789
+ const revision = spin.__rev || getFrom(html3, 'revision":', ",").trim();
90740
91790
  const clientIDData = findConfig("MqttWebDeviceID");
90741
91791
  const clientID = clientIDData ? clientIDData.clientID : void 0;
90742
91792
  const mqttConfigData = findConfig("MqttWebConfig");
@@ -90775,8 +91825,14 @@ async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRe
90775
91825
  callback_Task: {},
90776
91826
  region,
90777
91827
  firstListen: true,
90778
- ...dtsgResult
91828
+ ...dtsgResult,
91829
+ ...lsd ? { lsd } : {},
91830
+ ...Object.keys(spin).length ? { __spin: spin } : {},
91831
+ ...revision ? { revision } : {}
90779
91832
  };
91833
+ if (lsd && dtsg) {
91834
+ ctx.__cometTokens = { lsd, fb_dtsg: dtsg, fetchedAt: Date.now(), failures: 0 };
91835
+ }
90780
91836
  const defaultFuncs = makeDefaults(html3, userID, ctx);
90781
91837
  return [ctx, defaultFuncs, {}];
90782
91838
  }
@@ -91050,29 +92106,78 @@ var getBotInitialData_default = (defaultFuncs, api, ctx) => {
91050
92106
  };
91051
92107
  }
91052
92108
  log("Fetching account info...");
91053
- api.httpGet(`https://www.facebook.com/profile.php?id=${ctx.userID}`, null, {
91054
- customUserAgent: windowsUserAgent
91055
- }, (err, data2) => {
91056
- if (err) return callback(err);
91057
- try {
91058
- const profileMatch = data2.match(/"CurrentUserInitialData",\[\],\{(.*?)\},(.*?)\]/);
91059
- if (profileMatch && profileMatch[1]) {
91060
- const accountJson = JSON.parse(`{${profileMatch[1]}}`);
91061
- accountJson.name = accountJson.NAME;
91062
- accountJson.uid = accountJson.USER_ID;
91063
- delete accountJson.NAME;
91064
- delete accountJson.USER_ID;
92109
+ const locale = (ctx.globalOptions?.browser?.language || "en-US").replace("-", "_");
92110
+ const url2 = `https://www.facebook.com/profile.php?id=${ctx.userID}&sk=about&locale=${locale}`;
92111
+ api.httpGet(
92112
+ url2,
92113
+ null,
92114
+ {},
92115
+ (err, data2) => {
92116
+ if (err) return callback(err);
92117
+ try {
92118
+ const accountJson = extractCurrentUser(data2);
92119
+ if (accountJson) {
92120
+ return callback(null, {
92121
+ ...accountJson,
92122
+ name: accountJson.NAME ?? accountJson.name,
92123
+ uid: accountJson.USER_ID ?? accountJson.userID ?? ctx.userID
92124
+ });
92125
+ }
91065
92126
  return callback(null, {
91066
- ...accountJson
92127
+ error: "Something went wrong. Maybe its possible that it has a limitation due to spam requests. You can try again later."
91067
92128
  });
91068
- } else return callback(null, { error: "Something went wrong. Maybe its possible that it has a limitation due to spam requests. You can try again later." });
91069
- } catch (e) {
91070
- return callback(e);
91071
- }
91072
- }, true);
92129
+ } catch (e) {
92130
+ return callback(e);
92131
+ }
92132
+ },
92133
+ true
92134
+ );
91073
92135
  return returnPromise;
91074
92136
  };
91075
92137
  };
92138
+ function extractCurrentUser(html3) {
92139
+ if (typeof html3 !== "string") return null;
92140
+ const marker = '"CurrentUserInitialData",[],';
92141
+ const markerIndex = html3.indexOf(marker);
92142
+ const anchor = markerIndex >= 0 ? markerIndex + marker.length : html3.indexOf('"CurrentUserInitialData"');
92143
+ if (anchor < 0) return null;
92144
+ const start = html3.indexOf("{", anchor);
92145
+ if (start < 0) return null;
92146
+ let depth = 0;
92147
+ let inString = false;
92148
+ let escaped = false;
92149
+ for (let i2 = start; i2 < html3.length; i2++) {
92150
+ const ch = html3[i2];
92151
+ if (inString) {
92152
+ if (escaped) {
92153
+ escaped = false;
92154
+ } else if (ch === "\\") {
92155
+ escaped = true;
92156
+ } else if (ch === '"') {
92157
+ inString = false;
92158
+ }
92159
+ continue;
92160
+ }
92161
+ if (ch === '"') {
92162
+ inString = true;
92163
+ } else if (ch === "{") {
92164
+ depth++;
92165
+ } else if (ch === "}") {
92166
+ depth--;
92167
+ if (depth === 0) {
92168
+ try {
92169
+ const parsed = JSON.parse(html3.slice(start, i2 + 1));
92170
+ parsed.name = parsed.NAME;
92171
+ parsed.uid = parsed.USER_ID;
92172
+ return parsed;
92173
+ } catch {
92174
+ return null;
92175
+ }
92176
+ }
92177
+ }
92178
+ }
92179
+ return null;
92180
+ }
91076
92181
 
91077
92182
  // src/deltas/apis/login/logout.ts
91078
92183
  function logout_default(defaultFuncs, api, ctx) {
@@ -91082,6 +92187,13 @@ function logout_default(defaultFuncs, api, ctx) {
91082
92187
  if (ctx.globalOptions) {
91083
92188
  ctx.globalOptions.autoReconnect = false;
91084
92189
  }
92190
+ if (typeof ctx.__stopCookieKeepAlive === "function") {
92191
+ try {
92192
+ ctx.__stopCookieKeepAlive();
92193
+ } catch {
92194
+ }
92195
+ ctx.__stopCookieKeepAlive = null;
92196
+ }
91085
92197
  if (ctx.presenceInterval) {
91086
92198
  clearInterval(ctx.presenceInterval);
91087
92199
  ctx.presenceInterval = null;
@@ -93133,7 +94245,7 @@ init_constants();
93133
94245
  var SEARCH_DOC_ID = "23943555345255534";
93134
94246
  var SEARCH_FRIENDLY_NAME = "StoriesCreateMusicSelectorMainPageQuery";
93135
94247
  var GRAPHQL_URL = "https://www.facebook.com/api/graphql/";
93136
- var PRODUCT = "FB_COMPOSER";
94248
+ var PRODUCT = "FB_CAMERA";
93137
94249
  function textOf(node) {
93138
94250
  if (node == null) return "";
93139
94251
  if (typeof node === "string") return node;
@@ -93191,6 +94303,10 @@ function collectTracks(payload) {
93191
94303
  }
93192
94304
 
93193
94305
  // src/deltas/apis/music/searchMusic.ts
94306
+ function nextRequestId(ctx) {
94307
+ ctx.__reqCounter = (typeof ctx.__reqCounter === "number" ? ctx.__reqCounter : 0) + 1;
94308
+ return ctx.__reqCounter.toString(36);
94309
+ }
93194
94310
  function normalizeError(error2) {
93195
94311
  if (!error2 || typeof error2 !== "object") {
93196
94312
  const message2 = String(error2);
@@ -93212,32 +94328,53 @@ function normalizeError(error2) {
93212
94328
  }
93213
94329
  function searchMusic_default(defaultFuncs, _api, ctx) {
93214
94330
  async function runSearch(text3, count, selectedOptions, callback) {
93215
- await ensureCometTokens(ctx, defaultFuncs);
93216
94331
  const params = { first: count };
93217
94332
  if (text3) params.search_text = text3;
93218
94333
  if (selectedOptions.cursor) params.after = String(selectedOptions.cursor);
93219
- const form = {
93220
- av: ctx.userID,
93221
- __user: ctx.userID,
93222
- __a: "1",
93223
- __req: Math.floor(Math.random() * 1296).toString(36),
93224
- fb_api_caller_class: "RelayModern",
93225
- fb_api_req_friendly_name: SEARCH_FRIENDLY_NAME,
93226
- doc_id: SEARCH_DOC_ID,
93227
- variables: JSON.stringify({
93228
- params,
93229
- product: selectedOptions.product || PRODUCT
93230
- }),
93231
- server_timestamps: "true"
93232
- };
93233
- if (ctx.fb_dtsg) form.fb_dtsg = ctx.fb_dtsg;
93234
- if (ctx.jazoest) form.jazoest = ctx.jazoest;
93235
- if (ctx.lsd) form.lsd = ctx.lsd;
93236
- const customHeader = {};
93237
- if (ctx.lsd) customHeader["X-Fb-Lsd"] = ctx.lsd;
93238
- customHeader["X-Fb-Friendly-Name"] = SEARCH_FRIENDLY_NAME;
93239
- const parsed = await defaultFuncs.post(GRAPHQL_URL, ctx.jar, form, {}, ctx, customHeader).then(parseAndCheckLogin(ctx, defaultFuncs));
94334
+ const attempt = async (forceRefresh) => {
94335
+ await ensureCometTokens(ctx, defaultFuncs, forceRefresh);
94336
+ const form = {
94337
+ av: ctx.userID,
94338
+ __user: ctx.userID,
94339
+ __a: "1",
94340
+ __req: nextRequestId(ctx),
94341
+ fb_api_caller_class: "RelayModern",
94342
+ fb_api_req_friendly_name: SEARCH_FRIENDLY_NAME,
94343
+ doc_id: SEARCH_DOC_ID,
94344
+ variables: JSON.stringify({
94345
+ params,
94346
+ product: selectedOptions.product || PRODUCT
94347
+ }),
94348
+ server_timestamps: "true"
94349
+ };
94350
+ if (ctx.fb_dtsg) form.fb_dtsg = ctx.fb_dtsg;
94351
+ if (ctx.jazoest) form.jazoest = ctx.jazoest;
94352
+ if (ctx.lsd) form.lsd = ctx.lsd;
94353
+ const spin = ctx.__spin || {};
94354
+ if (spin.__spin_b) form.__spin_b = spin.__spin_b;
94355
+ if (spin.__spin_r) form.__spin_r = spin.__spin_r;
94356
+ if (spin.__spin_t) form.__spin_t = spin.__spin_t;
94357
+ if (ctx.revision) form.__rev = ctx.revision;
94358
+ const customHeader = {};
94359
+ if (ctx.lsd) customHeader["X-Fb-Lsd"] = ctx.lsd;
94360
+ customHeader["X-Fb-Friendly-Name"] = SEARCH_FRIENDLY_NAME;
94361
+ const raw = await defaultFuncs.post(GRAPHQL_URL, ctx.jar, form, ctx, customHeader).then(parseAndCheckLogin(ctx, defaultFuncs));
94362
+ return raw;
94363
+ };
94364
+ let parsed = await attempt(false);
94365
+ if (isStaleTokenError(parsed)) {
94366
+ invalidateCometTokens(ctx);
94367
+ parsed = await attempt(true);
94368
+ }
93240
94369
  if (!parsed) throw { error: "searchMusic returned empty object.", code: "BAD_RESPONSE" };
94370
+ if (isStaleTokenError(parsed)) {
94371
+ throw {
94372
+ error: parsed.error,
94373
+ errorSummary: parsed.errorSummary,
94374
+ errorDescription: parsed.errorDescription,
94375
+ code: "STALE_TOKEN"
94376
+ };
94377
+ }
93241
94378
  if (parsed.error) {
93242
94379
  throw {
93243
94380
  error: parsed.error,
@@ -93259,6 +94396,20 @@ function searchMusic_default(defaultFuncs, _api, ctx) {
93259
94396
  const page = collectTracks(parsed);
93260
94397
  const tracks = page.tracks.slice(0, count);
93261
94398
  if (tracks.length === 0) {
94399
+ invalidateCometTokens(ctx);
94400
+ const retried = await attempt(true);
94401
+ if (!isStaleTokenError(retried) && !retried.error && !(retried.errors || []).length) {
94402
+ const retryPage = collectTracks(retried);
94403
+ const retryTracks = retryPage.tracks.slice(0, count);
94404
+ if (retryTracks.length) {
94405
+ const result2 = retryTracks.slice();
94406
+ result2.tracks = retryTracks;
94407
+ result2.endCursor = retryPage.endCursor;
94408
+ result2.hasNextPage = retryPage.hasNextPage;
94409
+ result2.query = text3;
94410
+ return result2;
94411
+ }
94412
+ }
93262
94413
  throw {
93263
94414
  error: `No music results found for "${text3}". The Facebook music catalog may be unavailable for this account or region.`,
93264
94415
  code: "NO_RESULTS",
@@ -93542,8 +94693,9 @@ function connectLightspeed(ctx, globalCallback) {
93542
94693
  const chatOn = ctx.globalOptions.online;
93543
94694
  const foreground = false;
93544
94695
  const sessionID = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1;
93545
- const cookies = ctx.jar.getCookiesSync("https://www.facebook.com").join("; ");
94696
+ const cookies = collectSessionCookies(ctx, "https://gateway.facebook.com");
93546
94697
  const cid = ctx.clientID;
94698
+ const appId = ctx.mqttAppID || ctx.appID || "2220391788200892";
93547
94699
  const username = {
93548
94700
  u: ctx.userID,
93549
94701
  s: sessionID,
@@ -93551,7 +94703,7 @@ function connectLightspeed(ctx, globalCallback) {
93551
94703
  fg: foreground,
93552
94704
  d: cid,
93553
94705
  ct: "websocket",
93554
- aid: "2220391788200892",
94706
+ aid: appId,
93555
94707
  mqtt_sid: "",
93556
94708
  cp: 3,
93557
94709
  ecp: 10,
@@ -93561,10 +94713,12 @@ function connectLightspeed(ctx, globalCallback) {
93561
94713
  no_auto_fg: true,
93562
94714
  gas: null,
93563
94715
  pack: [],
93564
- a: ctx.globalOptions.userAgent
94716
+ a: ctx.globalOptions.userAgent || exports.defaultBrowserProfile.userAgent,
94717
+ vi: "3",
94718
+ lc: "en_US"
93565
94719
  };
93566
94720
  const queryParams = new URLSearchParams({
93567
- "x-dgw-appid": "2220391788200892",
94721
+ "x-dgw-appid": appId,
93568
94722
  "x-dgw-appversion": "0",
93569
94723
  "x-dgw-authtype": "1:0",
93570
94724
  "x-dgw-version": "5",
@@ -93575,6 +94729,7 @@ function connectLightspeed(ctx, globalCallback) {
93575
94729
  "x-dgw-deviceid": ctx.clientID
93576
94730
  });
93577
94731
  const host = `wss://gateway.facebook.com/ws/lightspeed?${queryParams.toString()}`;
94732
+ const wsHeaders = getWebSocketHeaders(host, ctx.globalOptions);
93578
94733
  const options = {
93579
94734
  clientId: "mqttwsclient",
93580
94735
  protocolId: "MQIsdp",
@@ -93582,15 +94737,12 @@ function connectLightspeed(ctx, globalCallback) {
93582
94737
  username: JSON.stringify(username),
93583
94738
  clean: true,
93584
94739
  wsOptions: {
93585
- headers: {
93586
- "Cookie": cookies,
93587
- "Origin": "https://www.facebook.com",
93588
- "User-Agent": username.a,
93589
- "Referer": "https://www.facebook.com/",
93590
- "Host": new URL(host).hostname
93591
- }
94740
+ headers: { ...wsHeaders, Cookie: cookies },
94741
+ origin: wsHeaders.Origin,
94742
+ protocolVersion: 13,
94743
+ binaryType: "arraybuffer"
93592
94744
  },
93593
- keepalive: 10,
94745
+ keepalive: 10 + Math.floor(Math.random() * 10),
93594
94746
  reconnectPeriod: 0
93595
94747
  };
93596
94748
  if (ctx.globalOptions.proxy) {
@@ -93642,9 +94794,9 @@ function connectLightspeed(ctx, globalCallback) {
93642
94794
  }
93643
94795
  function reconnect(retryCount) {
93644
94796
  if (isStopped || reconnectTimer || ctx.loggedIn === false || ctx.globalOptions.autoReconnect === false) return;
93645
- const delay3 = Math.min(3e3 * Math.pow(2, retryCount), 6e4);
93646
- log(`[Lightspeed] Reconnecting in ${delay3 / 1e3} seconds...`);
93647
- reconnectTimer = setTimeout(() => startConnection(retryCount), delay3);
94797
+ const delay3 = retryDelay(retryCount, 4e3, 12e4);
94798
+ log(`[Lightspeed] Reconnecting in ${(delay3 / 1e3).toFixed(1)} seconds...`);
94799
+ reconnectTimer = setTimeout(() => startConnection(retryCount + 1), delay3);
93648
94800
  }
93649
94801
  startConnection();
93650
94802
  return {
@@ -98668,11 +99820,15 @@ function themeQuery_default(defaultFuncs, _api, ctx) {
98668
99820
  doc_id: "24474714052117636"
98669
99821
  };
98670
99822
  const referer = threadID ? `https://www.facebook.com/messages/t/${threadID}` : "https://www.facebook.com/messages";
98671
- const resData = await defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form, null, {
98672
- "x-fb-friendly-name": "MWPThreadThemeQuery_AllThemesQuery",
98673
- "x-fb-lsd": ctx.lsd,
98674
- referer
98675
- }).then(parseAndCheckLogin(ctx, defaultFuncs));
99823
+ const resData = await withCometTokens(
99824
+ ctx,
99825
+ defaultFuncs,
99826
+ () => defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form, null, {
99827
+ "x-fb-friendly-name": "MWPThreadThemeQuery_AllThemesQuery",
99828
+ "x-fb-lsd": ctx.lsd,
99829
+ referer
99830
+ }).then(parseAndCheckLogin(ctx, defaultFuncs))
99831
+ );
98676
99832
  if (resData?.errors) {
98677
99833
  throw new Error(JSON.stringify(resData.errors));
98678
99834
  }
@@ -98713,6 +99869,7 @@ function getHealthStatus_default(_defaultFuncs, _api, ctx) {
98713
99869
  return function getHealthStatus() {
98714
99870
  const mqtt3 = ctx.mqttClient;
98715
99871
  const connected = !!mqtt3 && (typeof mqtt3.connected === "boolean" ? mqtt3.connected : mqtt3.readyState === 1 || !!(mqtt3.stream && !mqtt3.stream.destroyed));
99872
+ const safety = typeof ctx.__safetySnapshot === "function" ? ctx.__safetySnapshot() : null;
98716
99873
  return {
98717
99874
  userID: ctx.userID || null,
98718
99875
  loggedIn: !!ctx.userID,
@@ -98723,8 +99880,13 @@ function getHealthStatus_default(_defaultFuncs, _api, ctx) {
98723
99880
  lastMessageAt: ctx.__mqttLastMessageAt || null
98724
99881
  },
98725
99882
  antiSuspension: {
98726
- enabled: false,
98727
- circuitBreakerOpen: false
99883
+ enabled: true,
99884
+ // The breaker is open when Facebook has signalled it is unhappy and
99885
+ // the session is deliberately pausing rather than risking a lockdown.
99886
+ circuitBreakerOpen: safety ? !safety.closed : false,
99887
+ reason: safety ? safety.reason : void 0,
99888
+ cooldownRemainingMs: safety ? safety.cooldownRemainingMs : 0,
99889
+ requestsInWindow: safety ? safety.requestsInWindow : 0
98728
99890
  },
98729
99891
  uptimeMs: typeof ctx.__startedAt === "number" ? Date.now() - ctx.__startedAt : null,
98730
99892
  timestamp: Date.now()
@@ -98785,7 +99947,6 @@ function getFriendsList_default(defaultFuncs, api, ctx) {
98785
99947
 
98786
99948
  // src/deltas/apis/mqtt/realtime.ts
98787
99949
  var import_undici = __toESM(require_undici());
98788
- var import_https_proxy_agent3 = __toESM(require_dist3());
98789
99950
  function formatNotification(data2) {
98790
99951
  if (!data2.data || !data2.data.viewer) return null;
98791
99952
  const notifEdge = data2.data.viewer.notifications_page?.edges?.[1]?.node?.notif;
@@ -98800,6 +99961,31 @@ function formatNotification(data2) {
98800
99961
  seenState: notifEdge.seen_state
98801
99962
  };
98802
99963
  }
99964
+ function collectRealtimeCookies(ctx) {
99965
+ const origins = [
99966
+ "https://www.facebook.com",
99967
+ "https://facebook.com",
99968
+ "https://www.messenger.com",
99969
+ "https://gateway.facebook.com"
99970
+ ];
99971
+ const seen = {};
99972
+ const parts = [];
99973
+ for (const origin2 of origins) {
99974
+ let list = [];
99975
+ try {
99976
+ list = ctx.jar.getCookiesSync(origin2) || [];
99977
+ } catch {
99978
+ list = [];
99979
+ }
99980
+ for (const cookie of list) {
99981
+ const name = cookie?.key;
99982
+ if (!name || seen[name]) continue;
99983
+ seen[name] = true;
99984
+ parts.push(cookie.cookieString());
99985
+ }
99986
+ }
99987
+ return parts.join("; ");
99988
+ }
98803
99989
  function realtime_default(defaultFuncs, api, ctx) {
98804
99990
  return function listenRealtime() {
98805
99991
  const emitter = new EventEmitter2__default.default();
@@ -98807,6 +99993,7 @@ function realtime_default(defaultFuncs, api, ctx) {
98807
99993
  let reconnectTimeout;
98808
99994
  let keepAliveInterval;
98809
99995
  let stopped = false;
99996
+ let retries = 0;
98810
99997
  const subscriptions = [
98811
99998
  '{"x-dgw-app-XRSS-method":"Falco","x-dgw-app-xrs-body":"true","x-dgw-app-XRS-Accept-Ack":"RSAck","x-dgw-app-XRSS-http_referer":"https://www.facebook.com/friends"}',
98812
99999
  '{"x-dgw-app-XRSS-method":"FBGQLS:USER_ACTIVITY_UPDATE_SUBSCRIBE","x-dgw-app-XRSS-doc_id":"9525970914181809","x-dgw-app-XRSS-routing_hint":"UserActivitySubscription","x-dgw-app-xrs-body":"true","x-dgw-app-XRS-Accept-Ack":"RSAck","x-dgw-app-XRSS-http_referer":"https://www.facebook.com/friends"}',
@@ -98858,8 +100045,9 @@ function realtime_default(defaultFuncs, api, ctx) {
98858
100045
  async function connect() {
98859
100046
  if (stopped) return;
98860
100047
  try {
100048
+ const appId = ctx.mqttAppID || ctx.appID || "2220391788200892";
98861
100049
  const queryParams = new URLSearchParams({
98862
- "x-dgw-appid": "2220391788200892",
100050
+ "x-dgw-appid": String(appId),
98863
100051
  "x-dgw-appversion": "0",
98864
100052
  "x-dgw-authtype": "1:0",
98865
100053
  "x-dgw-version": "5",
@@ -98869,23 +100057,22 @@ function realtime_default(defaultFuncs, api, ctx) {
98869
100057
  "x-dgw-app-stream-group": "group1"
98870
100058
  });
98871
100059
  const url2 = `wss://gateway.facebook.com/ws/realtime?${queryParams.toString()}`;
98872
- const cookies = ctx.jar.getCookiesSync("https://www.facebook.com").join("; ");
100060
+ const cookies = collectRealtimeCookies(ctx);
100061
+ const wsHeaders = getWebSocketHeaders(url2, ctx.globalOptions, ctx);
98873
100062
  const baseHeaders = {
98874
- "Cookie": cookies,
98875
- "Origin": "https://www.facebook.com",
98876
- "User-Agent": ctx.globalOptions.userAgent,
98877
- "Referer": "https://www.facebook.com",
98878
- "Host": new URL(url2).hostname,
98879
- "Accept-Encoding": "gzip, deflate, br",
98880
- "Accept-Language": "en-US,en;q=0.9"
100063
+ ...wsHeaders,
100064
+ "Referer": "https://www.facebook.com/friends",
100065
+ "Cookie": cookies
98881
100066
  };
98882
100067
  const wsOptions = { headers: baseHeaders };
98883
100068
  if (ctx.globalOptions.proxy) {
98884
- wsOptions.agent = new import_https_proxy_agent3.HttpsProxyAgent(ctx.globalOptions.proxy);
100069
+ const { ProxyAgent } = await Promise.resolve().then(() => __toESM(require_undici()));
100070
+ wsOptions.dispatcher = new ProxyAgent(ctx.globalOptions.proxy);
98885
100071
  }
98886
100072
  ws2 = new import_undici.WebSocket(url2, wsOptions);
98887
100073
  ws2.onopen = () => {
98888
100074
  log("Connected via undici.WebSocket");
100075
+ retries = 0;
98889
100076
  subscriptions.forEach((payload, index3) => {
98890
100077
  const prefix = Buffer.from([14, index3, 0, payload.length]);
98891
100078
  const suffix = Buffer.from([0, 0]);
@@ -98917,7 +100104,7 @@ function realtime_default(defaultFuncs, api, ctx) {
98917
100104
  clearInterval(keepAliveInterval);
98918
100105
  keepAliveInterval = void 0;
98919
100106
  clearTimeout(reconnectTimeout);
98920
- reconnectTimeout = setTimeout(connect, 1e3);
100107
+ reconnectTimeout = setTimeout(connect, retryDelay(++retries, 2e3, 6e4));
98921
100108
  };
98922
100109
  } catch (err) {
98923
100110
  if (stopped) return;
@@ -98925,7 +100112,7 @@ function realtime_default(defaultFuncs, api, ctx) {
98925
100112
  emitter.emit("error", err);
98926
100113
  clearInterval(keepAliveInterval);
98927
100114
  clearTimeout(reconnectTimeout);
98928
- reconnectTimeout = setTimeout(connect, 1e3);
100115
+ reconnectTimeout = setTimeout(connect, retryDelay(++retries, 2e3, 6e4));
98929
100116
  }
98930
100117
  }
98931
100118
  connect();
@@ -98944,7 +100131,7 @@ function realtime_default(defaultFuncs, api, ctx) {
98944
100131
  // src/deltas/apis/mqtt/listenMqtt.ts
98945
100132
  var import_mqtt2 = __toESM(require_mqtt2());
98946
100133
  var import_websocket_stream2 = __toESM(require_websocket_stream());
98947
- var import_https_proxy_agent4 = __toESM(require_dist3());
100134
+ var import_https_proxy_agent3 = __toESM(require_dist3());
98948
100135
 
98949
100136
  // src/deltas/apis/mqtt/deltas/value.ts
98950
100137
  function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
@@ -99168,9 +100355,15 @@ var MQTT_CONFIG = {
99168
100355
  },
99169
100356
  PROTOCOL_VERSION: 3,
99170
100357
  QOS_LEVEL: 1,
99171
- INITIAL_RETRY_DELAY: 2e3,
99172
- MAX_RETRY_DELAY: 6e4,
99173
- RETRY_MULTIPLIER: 1.6
100358
+ // A dropped socket deserves a quick retry; only a refused handshake
100359
+ // (explicit throttle) gets the long backoff. Both ramps are jittered.
100360
+ INITIAL_RETRY_DELAY: 4e3,
100361
+ MAX_RETRY_DELAY: 3e5,
100362
+ RETRY_MULTIPLIER: 2,
100363
+ // A refused handshake (connack returnCode != 0) means we are being
100364
+ // throttled, not that the network blipped: wait much longer before trying.
100365
+ THROTTLE_DELAY: 9e4,
100366
+ MAX_THROTTLE_DELAY: 9e5
99174
100367
  };
99175
100368
  var SYNC_CONFIG = {
99176
100369
  API_VERSION: 11,
@@ -99179,14 +100372,15 @@ var SYNC_CONFIG = {
99179
100372
  ENCODING: "JSON"
99180
100373
  };
99181
100374
  function buildMqttUsername(ctx, sessionID) {
100375
+ const profile = resolveProfile(ctx.globalOptions);
99182
100376
  return {
99183
100377
  u: ctx.userID,
99184
100378
  s: String(sessionID),
99185
- chat_on: ctx.globalOptions.online,
100379
+ chat_on: !!ctx.globalOptions.online,
99186
100380
  fg: false,
99187
100381
  d: ctx.clientID,
99188
100382
  ct: "websocket",
99189
- aid: ctx.mqttAppID || "218474845183941",
100383
+ aid: ctx.mqttAppID || ctx.appID || "2220391788200892",
99190
100384
  mqtt_sid: "",
99191
100385
  cp: 3,
99192
100386
  ecp: 10,
@@ -99196,13 +100390,14 @@ function buildMqttUsername(ctx, sessionID) {
99196
100390
  no_auto_fg: true,
99197
100391
  gas: null,
99198
100392
  pack: [],
99199
- a: ctx.globalOptions.userAgent,
100393
+ a: profile.userAgent,
99200
100394
  vi: "3",
99201
- lc: "en_US"
100395
+ lc: (profile.language || "en-US").replace("-", "_")
99202
100396
  };
99203
100397
  }
99204
100398
  function buildMqttOptions(ctx, host, username) {
99205
- const cookies = ctx.jar.getCookiesSync("https://www.facebook.com").join("; ");
100399
+ const cookies = collectSessionCookies(ctx, host);
100400
+ const wsHeaders = getWebSocketHeaders(host, ctx.globalOptions);
99206
100401
  const options = {
99207
100402
  clientId: "mqttwsclient",
99208
100403
  protocolId: "MQIsdp",
@@ -99210,14 +100405,8 @@ function buildMqttOptions(ctx, host, username) {
99210
100405
  username: JSON.stringify(username),
99211
100406
  clean: true,
99212
100407
  wsOptions: {
99213
- headers: {
99214
- "Cookie": cookies,
99215
- "Origin": "https://www.messenger.com",
99216
- "User-Agent": username.a,
99217
- "Referer": "https://www.messenger.com/",
99218
- "Host": new URL(host).hostname
99219
- },
99220
- origin: "https://www.messenger.com",
100408
+ headers: { ...wsHeaders, Cookie: cookies },
100409
+ origin: wsHeaders.Origin,
99221
100410
  protocolVersion: 13,
99222
100411
  binaryType: "arraybuffer"
99223
100412
  },
@@ -99227,7 +100416,7 @@ function buildMqttOptions(ctx, host, username) {
99227
100416
  reconnectPeriod: 0
99228
100417
  };
99229
100418
  if (ctx.globalOptions.proxy) {
99230
- options.wsOptions.agent = new import_https_proxy_agent4.HttpsProxyAgent(ctx.globalOptions.proxy);
100419
+ options.wsOptions.agent = new import_https_proxy_agent3.HttpsProxyAgent(ctx.globalOptions.proxy);
99231
100420
  }
99232
100421
  return options;
99233
100422
  }
@@ -99249,6 +100438,7 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99249
100438
  stopped: false,
99250
100439
  attempts: 0,
99251
100440
  delay: MQTT_CONFIG.INITIAL_RETRY_DELAY,
100441
+ throttleDelay: MQTT_CONFIG.THROTTLE_DELAY,
99252
100442
  generation: 0
99253
100443
  };
99254
100444
  const log2 = (...args) => log(...args);
@@ -99282,13 +100472,36 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99282
100472
  } catch (_3) {
99283
100473
  }
99284
100474
  }
99285
- function scheduleReconnect(reason) {
100475
+ function scheduleReconnect(reason, throttled = false) {
99286
100476
  if (lifecycle.stopped) return;
99287
100477
  if (ctx.loggedIn === false) return;
99288
100478
  if (ctx.globalOptions && ctx.globalOptions.autoReconnect === false) return;
100479
+ if (isBreakerOpen(ctx)) {
100480
+ const wait = Math.min(
100481
+ safetySnapshot(ctx).cooldownRemainingMs || MQTT_CONFIG.THROTTLE_DELAY,
100482
+ MQTT_CONFIG.MAX_THROTTLE_DELAY
100483
+ );
100484
+ clearReconnectTimer();
100485
+ lifecycle.reconnectTimer = setTimeout(() => {
100486
+ lifecycle.reconnectTimer = null;
100487
+ if (lifecycle.stopped || ctx.loggedIn === false) return;
100488
+ start();
100489
+ }, wait);
100490
+ log2(`MQTT ${reason}; safety breaker open, waiting ${(wait / 1e3).toFixed(1)}s`);
100491
+ return;
100492
+ }
99289
100493
  clearReconnectTimer();
99290
- const delay3 = Math.min(lifecycle.delay + getJitter(500), MQTT_CONFIG.MAX_RETRY_DELAY);
99291
- lifecycle.delay = Math.min(lifecycle.delay * MQTT_CONFIG.RETRY_MULTIPLIER, MQTT_CONFIG.MAX_RETRY_DELAY);
100494
+ let delay3;
100495
+ if (throttled) {
100496
+ delay3 = Math.min(lifecycle.throttleDelay + getJitter(8e3), MQTT_CONFIG.MAX_THROTTLE_DELAY);
100497
+ lifecycle.throttleDelay = Math.min(
100498
+ lifecycle.throttleDelay * MQTT_CONFIG.RETRY_MULTIPLIER,
100499
+ MQTT_CONFIG.MAX_THROTTLE_DELAY
100500
+ );
100501
+ } else {
100502
+ delay3 = Math.min(lifecycle.delay + getJitter(1500), MQTT_CONFIG.MAX_RETRY_DELAY);
100503
+ lifecycle.delay = Math.min(lifecycle.delay * MQTT_CONFIG.RETRY_MULTIPLIER, MQTT_CONFIG.MAX_RETRY_DELAY);
100504
+ }
99292
100505
  lifecycle.attempts++;
99293
100506
  log2(`MQTT ${reason}; reconnecting in ${(delay3 / 1e3).toFixed(1)}s (attempt ${lifecycle.attempts})`);
99294
100507
  lifecycle.reconnectTimer = setTimeout(() => {
@@ -99300,7 +100513,9 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99300
100513
  function resetBackoff() {
99301
100514
  lifecycle.attempts = 0;
99302
100515
  lifecycle.delay = MQTT_CONFIG.INITIAL_RETRY_DELAY;
100516
+ lifecycle.throttleDelay = MQTT_CONFIG.THROTTLE_DELAY;
99303
100517
  }
100518
+ ctx.__resetMqttBackoff = resetBackoff;
99304
100519
  async function fetchSeqId() {
99305
100520
  if (ctx.lastSeqId) return ctx.lastSeqId;
99306
100521
  const form = {
@@ -99367,9 +100582,18 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99367
100582
  ctx.mqttClient = client2;
99368
100583
  let connected = false;
99369
100584
  let closing = false;
100585
+ let throttled = false;
100586
+ let authFailure = false;
99370
100587
  client2.on("error", (err) => {
99371
100588
  ctx.lastMqttError = err;
99372
- error("listenMqtt", new NetworkError(`MQTT connection error: ${err?.message || err}`, { originalError: err, host }));
100589
+ const msg = String(err && err.message || err || "");
100590
+ if (/connection refused|not authorized|server unavailable|bad username|identifier rejected|unacceptable protocol/i.test(msg)) {
100591
+ throttled = true;
100592
+ }
100593
+ if (isAuthFailure && isAuthFailure(err)) {
100594
+ authFailure = true;
100595
+ }
100596
+ error("listenMqtt", new NetworkError(`MQTT connection error: ${msg}`, { originalError: err, host }));
99373
100597
  });
99374
100598
  client2.on("offline", () => {
99375
100599
  if (generation !== lifecycle.generation) return;
@@ -99383,7 +100607,17 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99383
100607
  ctx.mqttConnected = false;
99384
100608
  if (closing) return;
99385
100609
  closing = true;
99386
- scheduleReconnect("connection closed");
100610
+ if (authFailure) {
100611
+ noteAuthFailure(ctx);
100612
+ Promise.resolve().then(() => repairSession(ctx, defaultFuncs)).catch(() => {
100613
+ }).then(() => {
100614
+ if (generation !== lifecycle.generation) return;
100615
+ resetBackoff();
100616
+ scheduleReconnect("session repaired after auth error");
100617
+ });
100618
+ return;
100619
+ }
100620
+ scheduleReconnect(throttled ? "connection refused (throttled)" : "connection closed", throttled);
99387
100621
  });
99388
100622
  client2.on("connect", () => {
99389
100623
  if (generation !== lifecycle.generation) return;
@@ -99487,6 +100721,13 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99487
100721
  log2("Reconnecting MQTT...");
99488
100722
  clearTimers();
99489
100723
  destroyClient();
100724
+ try {
100725
+ const last2 = ctx.lastMqttError;
100726
+ if (last2 && isAuthFailure && isAuthFailure(last2)) {
100727
+ await repairSession(ctx, defaultFuncs);
100728
+ }
100729
+ } catch (_3) {
100730
+ }
99490
100731
  try {
99491
100732
  await ensureSeqId();
99492
100733
  } catch (err) {
@@ -99546,7 +100787,9 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99546
100787
  }
99547
100788
  }
99548
100789
  ctx.firstListen = false;
100790
+ let fetchedSeqId = false;
99549
100791
  try {
100792
+ fetchedSeqId = !ctx.lastSeqId;
99550
100793
  await ensureSeqId();
99551
100794
  } catch (err) {
99552
100795
  ctx.lastMqttError = err;
@@ -99554,6 +100797,7 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99554
100797
  scheduleReconnect("sequence id fetch failed");
99555
100798
  return;
99556
100799
  }
100800
+ if (fetchedSeqId) await sleep(humanDelay(700, 400));
99557
100801
  await start();
99558
100802
  })().catch((err) => {
99559
100803
  error("listenMqtt startup error:", err);
@@ -99685,7 +100929,7 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
99685
100929
  if (!name || c.value === void 0 || c.value === null) {
99686
100930
  throw new Error(`Invalid appState cookie at index ${index3}.`);
99687
100931
  }
99688
- return `${name}=${String(c.value)}`;
100932
+ return formatAppStateCookie(c);
99689
100933
  });
99690
100934
  } else if (typeof appState === "string") {
99691
100935
  cookieStrings = appState.split(";").map((s) => s.trim()).filter(Boolean);
@@ -99698,9 +100942,16 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
99698
100942
  if (cookieString.indexOf("=") <= 0) {
99699
100943
  throw new Error(`Invalid appState cookie at index ${index3}.`);
99700
100944
  }
99701
- const domain = ".facebook.com";
99702
- const str = `${cookieString}; domain=${domain}; path=/;`;
99703
- jar2.setCookie(str, "https://facebook.com");
100945
+ const normalized = cookieString.replace(/;\s*domain=facebook\.com/i, "; domain=.facebook.com").replace(/;\s*domain=messenger\.com/i, "; domain=.messenger.com");
100946
+ const str = /(^|;)\s*domain=/i.test(normalized) ? normalized : `${normalized}; domain=.facebook.com; path=/; Secure; SameSite=None`;
100947
+ try {
100948
+ jar2.setCookieSync(str, "https://facebook.com");
100949
+ } catch {
100950
+ try {
100951
+ jar2.setCookieSync(`${normalized}; domain=.facebook.com; path=/; Secure; SameSite=None`, "https://www.facebook.com");
100952
+ } catch {
100953
+ }
100954
+ }
99704
100955
  });
99705
100956
  } else if (credentials.email && credentials.password) {
99706
100957
  const url2 = "https://api.facebook.com/method/auth.login";
@@ -99717,15 +100968,25 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
99717
100968
  const query = qs__default.default.stringify(params);
99718
100969
  const xurl = `${url2}?${query}`;
99719
100970
  try {
99720
- const resp2 = await axios_default.get(xurl);
100971
+ const legacyHeaders = getHeaders(
100972
+ url2,
100973
+ globalOptions,
100974
+ null,
100975
+ { "Content-Type": "application/x-www-form-urlencoded" }
100976
+ );
100977
+ const resp2 = await axios_default.get(xurl, {
100978
+ headers: legacyHeaders,
100979
+ timeout: 6e4,
100980
+ validateStatus: (status) => status >= 200 && status < 600
100981
+ });
99721
100982
  if (resp2.status !== 200) {
99722
100983
  throw new Error("Wrong password / email");
99723
100984
  }
99724
100985
  const cstrs = resp2.data["session_cookies"].map((c) => `${c.name}=${c.value}`);
99725
100986
  cstrs.forEach((cstr) => {
99726
100987
  const domain = ".facebook.com";
99727
- const str = `${cstr}; domain=${domain}; path=/;`;
99728
- jar2.setCookie(str, "https://facebook.com");
100988
+ const str = `${cstr}; domain=${domain}; path=/; Secure; SameSite=None`;
100989
+ jar2.setCookieSync(str, "https://facebook.com");
99729
100990
  });
99730
100991
  } catch (e) {
99731
100992
  throw new Error("Wrong password / email");
@@ -99838,6 +101099,46 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
99838
101099
  api.ctx = ctx;
99839
101100
  api.defaultFuncs = defaultFuncs;
99840
101101
  api.globalOptions = globalOptions;
101102
+ api.extractCookies = () => extractCookies({ jar: jar2 });
101103
+ api.refreshSession = () => refreshSessionCookies(ctx, defaultFuncs);
101104
+ api.hasAuthenticatedSession = () => hasAuthenticatedSession(jar2);
101105
+ api.repairSession = () => repairSession(ctx, defaultFuncs);
101106
+ api.warmUpSession = () => warmUpSession(ctx, defaultFuncs.get);
101107
+ ctx.__startedAt = Date.now();
101108
+ ctx.__safetySnapshot = () => safetySnapshot(ctx);
101109
+ api.getSafetyStatus = () => safetySnapshot(ctx);
101110
+ api.pauseSession = (reason) => {
101111
+ tripBreaker(ctx, reason || "manual");
101112
+ return safetySnapshot(ctx);
101113
+ };
101114
+ api.resumeSession = () => {
101115
+ resetBreaker(ctx);
101116
+ return safetySnapshot(ctx);
101117
+ };
101118
+ ctx.__onSafetyTrip = (info2) => {
101119
+ warn(
101120
+ "Account safety",
101121
+ `pausing requests for ${Math.round((info2.cooldownMs || 0) / 1e3)}s (${info2.reason})`
101122
+ );
101123
+ };
101124
+ if (globalOptions.warmUp !== false) {
101125
+ try {
101126
+ await warmUpSession(ctx, defaultFuncs.get);
101127
+ } catch (warmUpError) {
101128
+ warn("Session warm-up skipped:", warmUpError?.message || warmUpError);
101129
+ }
101130
+ }
101131
+ ctx.__stopCookieKeepAlive = scheduleSessionKeepAlive(ctx, defaultFuncs, 15 * 60 * 1e3);
101132
+ if (globalOptions.liveness !== false) {
101133
+ const liveness = startLiveness(ctx, {
101134
+ foregroundPing: () => log("Session active"),
101135
+ backgroundPing: () => log("Session idle")
101136
+ });
101137
+ ctx.__livenessHandle = liveness;
101138
+ api.getLivenessState = () => liveness.state();
101139
+ api.canActProactively = () => canActProactively(ctx);
101140
+ api.awaitProactiveSlot = (maxWaitMs) => awaitProactiveSlot(ctx, maxWaitMs);
101141
+ }
99841
101142
  return callback(null, api);
99842
101143
  } catch (error2) {
99843
101144
  error("loginHelper", error2.error || error2);
@@ -99857,6 +101158,10 @@ async function login(credentials, options, callback) {
99857
101158
  if ("logging" in options) {
99858
101159
  logOptions(options.logging);
99859
101160
  }
101161
+ const browser = options.randomUserAgent ? randomUserAgent() : normalizeBrowserProfile({
101162
+ ...options.browser || exports.defaultBrowserProfile,
101163
+ ...options.userAgent ? { userAgent: options.userAgent } : {}
101164
+ });
99860
101165
  const defaultOptions2 = {
99861
101166
  selfListen: false,
99862
101167
  listenEvents: false,
@@ -99868,7 +101173,8 @@ async function login(credentials, options, callback) {
99868
101173
  autoReconnect: true,
99869
101174
  online: false,
99870
101175
  emitReady: false,
99871
- userAgent: options.userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
101176
+ userAgent: browser.userAgent,
101177
+ browser,
99872
101178
  advancedProtection: false,
99873
101179
  autoRotateSession: false,
99874
101180
  randomUserAgent: false
@@ -99911,6 +101217,10 @@ async function login(credentials, options, callback) {
99911
101217
  var public_exports = {};
99912
101218
 
99913
101219
  // index.ts
101220
+ init_headers();
101221
+ init_user_agents();
101222
+ init_pacing();
101223
+ init_safety();
99914
101224
  var metaChat = Object.assign(login, {
99915
101225
  login,
99916
101226
  publicTypes: public_exports,
@@ -100001,6 +101311,46 @@ lodash/lodash.js:
100001
101311
  *)
100002
101312
  */
100003
101313
 
101314
+ exports.applySetCookie = applySetCookie;
101315
+ exports.awaitProactiveSlot = awaitProactiveSlot;
101316
+ exports.canActProactively = canActProactively;
101317
+ exports.collectSessionCookies = collectSessionCookies;
100004
101318
  exports.default = index_default;
101319
+ exports.ensureCometTokens = ensureCometTokens;
101320
+ exports.extractCookies = extractCookies;
101321
+ exports.extractCookiesFromBody = extractCookiesFromBody;
101322
+ exports.extractCookiesFromJar = extractCookiesFromJar;
101323
+ exports.extractCookiesFromSetCookie = extractCookiesFromSetCookie;
101324
+ exports.extractCurrentUser = extractCurrentUser;
101325
+ exports.getFingerprintParams = getFingerprintParams;
101326
+ exports.getHeaders = getHeaders;
101327
+ exports.getWebSocketHeaders = getWebSocketHeaders;
101328
+ exports.hasAuthenticatedSession = hasAuthenticatedSession;
101329
+ exports.humanDelay = humanDelay;
101330
+ exports.invalidateCometTokens = invalidateCometTokens;
101331
+ exports.isAuthFailure = isAuthFailure;
101332
+ exports.isBreakerOpen = isBreakerOpen;
101333
+ exports.isStaleTokenError = isStaleTokenError;
100005
101334
  exports.login = login;
101335
+ exports.missingSessionCookies = missingSessionCookies;
101336
+ exports.normalizeBrowserProfile = normalizeBrowserProfile;
101337
+ exports.noteAction = noteAction;
101338
+ exports.noteAuthFailure = noteAuthFailure;
101339
+ exports.noteCheckpoint = noteCheckpoint;
101340
+ exports.noteRateLimit = noteRateLimit;
101341
+ exports.paceRequest = paceRequest;
100006
101342
  exports.publicTypes = public_exports;
101343
+ exports.randomUserAgent = randomUserAgent;
101344
+ exports.refreshSessionCookies = refreshSessionCookies;
101345
+ exports.repairSession = repairSession;
101346
+ exports.reserveRequest = reserveRequest;
101347
+ exports.resetBreaker = resetBreaker;
101348
+ exports.resolveProfile = resolveProfile;
101349
+ exports.retryDelay = retryDelay;
101350
+ exports.safetySnapshot = safetySnapshot;
101351
+ exports.sleep = sleep;
101352
+ exports.startLiveness = startLiveness;
101353
+ exports.tripBreaker = tripBreaker;
101354
+ exports.warmUpSession = warmUpSession;
101355
+ exports.withCometTokens = withCometTokens;
101356
+ exports.withSessionRetry = withSessionRetry;