@lazyneoaz/metachat 4.0.4 → 4.0.5

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.mjs CHANGED
@@ -13515,7 +13515,7 @@ var require_agent = __commonJS({
13515
13515
  var agent_base_1 = require_src2();
13516
13516
  var parse_proxy_response_1 = __importDefault(require_parse_proxy_response());
13517
13517
  var debug2 = debug_1.default("https-proxy-agent:agent");
13518
- var HttpsProxyAgent5 = class extends agent_base_1.Agent {
13518
+ var HttpsProxyAgent4 = class extends agent_base_1.Agent {
13519
13519
  constructor(_opts) {
13520
13520
  let opts;
13521
13521
  if (typeof _opts === "string") {
@@ -13609,7 +13609,7 @@ var require_agent = __commonJS({
13609
13609
  });
13610
13610
  }
13611
13611
  };
13612
- exports.default = HttpsProxyAgent5;
13612
+ exports.default = HttpsProxyAgent4;
13613
13613
  function resume(socket) {
13614
13614
  socket.resume();
13615
13615
  }
@@ -21852,94 +21852,6 @@ var require_form_data2 = __commonJS({
21852
21852
  }
21853
21853
  });
21854
21854
 
21855
- // src/utils/headers.ts
21856
- function sanitizeHeaderValue2(value) {
21857
- if (value === null || value === void 0) return "";
21858
- let str = String(value);
21859
- if (str.trim().startsWith("[") && str.trim().endsWith("]")) {
21860
- try {
21861
- const parsed = JSON.parse(str);
21862
- if (Array.isArray(parsed)) {
21863
- return "";
21864
- }
21865
- } catch {
21866
- }
21867
- }
21868
- str = str.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\r\n\[\]]/g, "").trim();
21869
- return str;
21870
- }
21871
- function sanitizeHeaderName(name) {
21872
- if (!name || typeof name !== "string") return "";
21873
- return name.replace(/[^\x21-\x7E]/g, "").trim();
21874
- }
21875
- function getHeaders(url2, options, ctx, customHeader) {
21876
- const u = new URL(url2);
21877
- 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";
21878
- const referer = options?.referer || "https://www.facebook.com/";
21879
- const origin2 = referer.replace(/\/+$/, "");
21880
- const contentType = options?.contentType || "application/x-www-form-urlencoded";
21881
- const acceptLang = options?.acceptLanguage || "en-US,en;q=0.9,vi;q=0.8";
21882
- const headers = {
21883
- Host: sanitizeHeaderValue2(u.host),
21884
- Origin: sanitizeHeaderValue2(origin2),
21885
- Referer: sanitizeHeaderValue2(referer),
21886
- "User-Agent": sanitizeHeaderValue2(ua),
21887
- Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,application/json;q=0.8,*/*;q=0.7",
21888
- "Accept-Language": sanitizeHeaderValue2(acceptLang),
21889
- "Accept-Encoding": "gzip, deflate, br",
21890
- "Content-Type": sanitizeHeaderValue2(contentType),
21891
- Connection: "keep-alive",
21892
- DNT: "1",
21893
- "Upgrade-Insecure-Requests": "1",
21894
- "sec-ch-ua": '"Chromium";v="139", "Not;A=Brand";v="24", "Google Chrome";v="139"',
21895
- "sec-ch-ua-mobile": "?0",
21896
- "sec-ch-ua-platform": '"Windows"',
21897
- "sec-ch-ua-arch": '"x86"',
21898
- "sec-ch-ua-bitness": '"64"',
21899
- "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"',
21900
- "sec-ch-ua-platform-version": '"15.0.0"',
21901
- "Sec-Fetch-Site": "same-origin",
21902
- "Sec-Fetch-Mode": "cors",
21903
- "Sec-Fetch-Dest": "empty",
21904
- "X-Requested-With": "XMLHttpRequest",
21905
- Pragma: "no-cache",
21906
- "Cache-Control": "no-cache"
21907
- };
21908
- if (ctx?.region) {
21909
- const regionValue = sanitizeHeaderValue2(ctx.region);
21910
- if (regionValue) headers["X-MSGR-Region"] = regionValue;
21911
- }
21912
- if (customHeader && typeof customHeader === "object") {
21913
- for (const [key, value] of Object.entries(customHeader)) {
21914
- if (value === null || value === void 0 || typeof value === "function") continue;
21915
- if (typeof value === "object") continue;
21916
- const sanitizedKey = sanitizeHeaderName(key);
21917
- const sanitizedValue = sanitizeHeaderValue2(value);
21918
- if (sanitizedKey && sanitizedValue !== "") {
21919
- const existingKey = Object.keys(headers).find(
21920
- (headerKey) => headerKey.toLowerCase() === sanitizedKey.toLowerCase()
21921
- );
21922
- headers[existingKey || sanitizedKey] = sanitizedValue;
21923
- }
21924
- }
21925
- }
21926
- const sanitizedHeaders = {};
21927
- for (const [key, value] of Object.entries(headers)) {
21928
- const sanitizedKey = sanitizeHeaderName(key);
21929
- const sanitizedValue = sanitizeHeaderValue2(value);
21930
- if (sanitizedKey && sanitizedValue !== "") {
21931
- sanitizedHeaders[sanitizedKey] = sanitizedValue;
21932
- }
21933
- }
21934
- return sanitizedHeaders;
21935
- }
21936
- var meta;
21937
- var init_headers = __esm({
21938
- "src/utils/headers.ts"() {
21939
- meta = (prop2) => new RegExp(`<meta property="${prop2}" content="([^"]*)"`);
21940
- }
21941
- });
21942
-
21943
21855
  // node_modules/color-name/index.js
21944
21856
  var require_color_name = __commonJS({
21945
21857
  "node_modules/color-name/index.js"(exports, module) {
@@ -24818,14 +24730,12 @@ function getGUID() {
24818
24730
  });
24819
24731
  }
24820
24732
  function getFrom(str, startToken, endToken) {
24821
- const start = str.indexOf(startToken) + startToken.length;
24822
- if (start < startToken.length) return "";
24823
- const lastHalf = str.substring(start);
24824
- const end2 = lastHalf.indexOf(endToken);
24825
- if (end2 === -1) {
24826
- throw Error("Could not find endTime `" + endToken + "` in the given string.");
24827
- }
24828
- return lastHalf.substring(0, end2);
24733
+ const startIndex = str.indexOf(startToken);
24734
+ if (startIndex < 0) return "";
24735
+ const start = startIndex + startToken.length;
24736
+ const end2 = str.indexOf(endToken, start);
24737
+ if (end2 < 0) return str.slice(start);
24738
+ return str.slice(start, end2);
24829
24739
  }
24830
24740
  function makeParsable(html3) {
24831
24741
  const withoutForLoop = html3.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/, "");
@@ -24954,6 +24864,480 @@ var init_constants = __esm({
24954
24864
  }
24955
24865
  });
24956
24866
 
24867
+ // src/utils/user-agents.ts
24868
+ function buildProfile(major, plat) {
24869
+ const full = `${major}.0.0.0`;
24870
+ const brands = [
24871
+ `"Not;A=Brand";v="24"`,
24872
+ `"Chromium";v="${major}"`,
24873
+ `"Google Chrome";v="${major}"`
24874
+ ];
24875
+ const fullVersionList = [
24876
+ `"Not;A=Brand";v="24.0.0.0"`,
24877
+ `"Chromium";v="${full}"`,
24878
+ `"Google Chrome";v="${full}"`
24879
+ ];
24880
+ const screen = getRandom(SCREENS);
24881
+ const language = getRandom(LANGUAGES);
24882
+ const isMac = /Macintosh/.test(plat.platform);
24883
+ const devicePixelRatio = isMac ? 2 : getRandom([1, 1.25, 1.5]) === 1 ? 1 : 1.25;
24884
+ return {
24885
+ userAgent: `Mozilla/5.0 (${plat.platform}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${full} Safari/537.36`,
24886
+ secChUa: brands.join(", "),
24887
+ secChUaFullVersionList: fullVersionList.join(", "),
24888
+ secChUaPlatform: plat.chPlatform,
24889
+ secChUaPlatformVersion: plat.chPlatformVersion,
24890
+ secChUaArch: plat.chArch,
24891
+ secChUaBitness: plat.chBitness,
24892
+ secChUaModel: '""',
24893
+ secChUaWow64: plat.chWow64,
24894
+ secChUaFormFactors: plat.formFactors,
24895
+ secChUaMobile: "?0",
24896
+ acceptLanguage: language === "en-GB" ? "en-GB,en;q=0.9" : "en-US,en;q=0.9",
24897
+ language,
24898
+ timezone: getRandom(TIMEOZONES),
24899
+ screen: {
24900
+ ...screen,
24901
+ colorDepth: 24,
24902
+ pixelDepth: 24
24903
+ },
24904
+ devicePixelRatio,
24905
+ hardwareConcurrency: getRandom([4, 8, 12, 16]),
24906
+ deviceMemory: getRandom([8, 8, 16]),
24907
+ label: plat.label
24908
+ };
24909
+ }
24910
+ function randomUserAgent() {
24911
+ return buildProfile(getRandom(CHROME_MAJORS), getRandom(DESKTOP_PLATFORMS));
24912
+ }
24913
+ function normalizeBrowserProfile(input) {
24914
+ if (!input) return defaultBrowserProfile;
24915
+ const base = defaultBrowserProfile;
24916
+ const ua = input.userAgent || base.userAgent;
24917
+ const major = (ua.match(/Chrome\/(\d+)/) || [])[1] || CHROME_MAJORS[0];
24918
+ const inferred = buildProfile(
24919
+ major,
24920
+ /Macintosh/.test(ua) ? DESKTOP_PLATFORMS.find((p) => /Macintosh/.test(p.platform)) : DESKTOP_PLATFORMS[0]
24921
+ );
24922
+ return { ...inferred, ...input, userAgent: ua };
24923
+ }
24924
+ var CHROME_MAJORS, DESKTOP_PLATFORMS, SCREENS, TIMEOZONES, LANGUAGES, defaultBrowserProfile, defaultUserAgent, windowsUserAgent;
24925
+ var init_user_agents = __esm({
24926
+ "src/utils/user-agents.ts"() {
24927
+ init_constants();
24928
+ CHROME_MAJORS = ["141", "140", "139"];
24929
+ DESKTOP_PLATFORMS = [
24930
+ {
24931
+ platform: "Windows NT 10.0; Win64; x64",
24932
+ chPlatform: '"Windows"',
24933
+ chPlatformVersion: '"15.0.0"',
24934
+ chArch: '"x86"',
24935
+ chBitness: '"64"',
24936
+ chWow64: "?0",
24937
+ formFactors: '"Desktop"',
24938
+ label: "Chrome/Windows-11"
24939
+ },
24940
+ {
24941
+ platform: "Windows NT 10.0; Win64; x64",
24942
+ chPlatform: '"Windows"',
24943
+ chPlatformVersion: '"10.0.0"',
24944
+ chArch: '"x86"',
24945
+ chBitness: '"64"',
24946
+ chWow64: "?0",
24947
+ formFactors: '"Desktop"',
24948
+ label: "Chrome/Windows-10"
24949
+ },
24950
+ {
24951
+ platform: "Macintosh; Intel Mac OS X 10_15_7",
24952
+ chPlatform: '"macOS"',
24953
+ chPlatformVersion: '"14.6.1"',
24954
+ chArch: '"x86"',
24955
+ chBitness: '"64"',
24956
+ chWow64: "?0",
24957
+ formFactors: '"Desktop"',
24958
+ label: "Chrome/macOS-14"
24959
+ },
24960
+ {
24961
+ platform: "Macintosh; Intel Mac OS X 10_15_7",
24962
+ chPlatform: '"macOS"',
24963
+ chPlatformVersion: '"15.1.0"',
24964
+ chArch: '"arm"',
24965
+ chBitness: '"64"',
24966
+ chWow64: "?0",
24967
+ formFactors: '"Desktop"',
24968
+ label: "Chrome/macOS-15-arm"
24969
+ }
24970
+ ];
24971
+ SCREENS = [
24972
+ { width: 1920, height: 1080, availWidth: 1920, availHeight: 1053 },
24973
+ { width: 2560, height: 1440, availWidth: 2560, availHeight: 1400 },
24974
+ { width: 1536, height: 864, availWidth: 1536, availHeight: 824 },
24975
+ { width: 1440, height: 900, availWidth: 1440, availHeight: 860 },
24976
+ { width: 1366, height: 768, availWidth: 1366, availHeight: 728 }
24977
+ ];
24978
+ TIMEOZONES = [
24979
+ "America/New_York",
24980
+ "America/Chicago",
24981
+ "America/Los_Angeles",
24982
+ "Europe/London",
24983
+ "Europe/Berlin",
24984
+ "Asia/Singapore"
24985
+ ];
24986
+ LANGUAGES = ["en-US", "en-GB"];
24987
+ defaultBrowserProfile = buildProfile(
24988
+ CHROME_MAJORS[0],
24989
+ DESKTOP_PLATFORMS[0]
24990
+ );
24991
+ defaultUserAgent = defaultBrowserProfile.userAgent;
24992
+ windowsUserAgent = defaultUserAgent;
24993
+ }
24994
+ });
24995
+
24996
+ // src/utils/headers.ts
24997
+ function sanitizeHeaderValue2(value) {
24998
+ if (value === null || value === void 0) return "";
24999
+ const str = String(value);
25000
+ return str.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\r\n]/g, "").trim();
25001
+ }
25002
+ function sanitizeHeaderName(name) {
25003
+ if (!name || typeof name !== "string") return "";
25004
+ return name.replace(/[^\x21-\x7E]/g, "").trim();
25005
+ }
25006
+ function originOf(referer) {
25007
+ try {
25008
+ return new URL(referer).origin;
25009
+ } catch {
25010
+ return "https://www.facebook.com";
25011
+ }
25012
+ }
25013
+ function isMessengerHost(host) {
25014
+ return /(^|\.)messenger\.com$/i.test(host);
25015
+ }
25016
+ function isBusinessHost(host) {
25017
+ return /(^|\.)business\.facebook\.com$/i.test(host);
25018
+ }
25019
+ function isFacebookHost(host) {
25020
+ return /(^|\.)facebook\.com$/i.test(host);
25021
+ }
25022
+ function isGraphQlPath(pathname) {
25023
+ return /\/api\/graphql/i.test(pathname) || /graphqlbatch/i.test(pathname);
25024
+ }
25025
+ function resolveProfile(options) {
25026
+ const base = options?.browser || options?.browserProfile || defaultBrowserProfile;
25027
+ const merged = {
25028
+ ...base,
25029
+ userAgent: options?.userAgent || base.userAgent,
25030
+ secChUa: options?.secChUa || base.secChUa,
25031
+ secChUaFullVersionList: options?.secChUaFullVersionList || base.secChUaFullVersionList,
25032
+ secChUaPlatform: options?.secChUaPlatform || base.secChUaPlatform,
25033
+ secChUaPlatformVersion: options?.secChUaPlatformVersion || base.secChUaPlatformVersion,
25034
+ secChUaArch: options?.secChUaArch || base.secChUaArch,
25035
+ secChUaBitness: options?.secChUaBitness || base.secChUaBitness,
25036
+ secChUaWow64: options?.secChUaWow64 || base.secChUaWow64,
25037
+ secChUaFormFactors: options?.secChUaFormFactors || base.secChUaFormFactors,
25038
+ secChUaMobile: options?.secChUaMobile || base.secChUaMobile,
25039
+ acceptLanguage: options?.acceptLanguage || base.acceptLanguage
25040
+ };
25041
+ if (options?.userAgent && !options?.browser && !options?.browserProfile) {
25042
+ return normalizeBrowserProfile(merged);
25043
+ }
25044
+ return merged;
25045
+ }
25046
+ function shouldSendOrigin(method, isXhr) {
25047
+ const m = (method || "GET").toUpperCase();
25048
+ if (m === "GET" || m === "HEAD" || m === "OPTIONS") return false;
25049
+ return true;
25050
+ }
25051
+ function getHeaders(url2, options, ctx, customHeader) {
25052
+ const u = new URL(url2);
25053
+ const profile = resolveProfile(options);
25054
+ const method = String(options?.method || customHeader?.method || "GET").toUpperCase();
25055
+ const defaultReferer = isMessengerHost(u.hostname) ? "https://www.messenger.com/" : isBusinessHost(u.hostname) ? "https://business.facebook.com/" : "https://www.facebook.com/";
25056
+ const referer = options?.referer || defaultReferer;
25057
+ const origin2 = options?.origin || originOf(referer);
25058
+ const contentType = options?.contentType || (customHeader?.["Content-Type"] || customHeader?.["content-type"]) || "application/x-www-form-urlencoded";
25059
+ const isGraphQl = isGraphQlPath(u.pathname);
25060
+ const isXhr = isGraphQl || contentType.includes("json") || !!options?.xhr;
25061
+ const isDocument2 = !isXhr && (method === "GET" || method === "HEAD");
25062
+ const secFetchSite = (() => {
25063
+ if (isDocument2) return "none";
25064
+ let refererHost = referer;
25065
+ try {
25066
+ refererHost = new URL(referer).hostname;
25067
+ } catch {
25068
+ }
25069
+ if (isMessengerHost(u.hostname) && !isMessengerHost(refererHost)) return "same-site";
25070
+ if (isFacebookHost(u.hostname) && !isFacebookHost(refererHost)) return "cross-site";
25071
+ return "same-origin";
25072
+ })();
25073
+ 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";
25074
+ const headers = {
25075
+ Referer: sanitizeHeaderValue2(referer),
25076
+ "User-Agent": sanitizeHeaderValue2(profile.userAgent),
25077
+ Accept: accept,
25078
+ "Accept-Language": sanitizeHeaderValue2(profile.acceptLanguage),
25079
+ "Accept-Encoding": "gzip, deflate, br",
25080
+ Connection: "keep-alive",
25081
+ "Upgrade-Insecure-Requests": "1",
25082
+ "sec-ch-ua": sanitizeHeaderValue2(profile.secChUa),
25083
+ "sec-ch-ua-mobile": sanitizeHeaderValue2(profile.secChUaMobile),
25084
+ "sec-ch-ua-platform": sanitizeHeaderValue2(profile.secChUaPlatform),
25085
+ "sec-ch-ua-platform-version": sanitizeHeaderValue2(profile.secChUaPlatformVersion),
25086
+ "sec-ch-ua-arch": sanitizeHeaderValue2(profile.secChUaArch),
25087
+ "sec-ch-ua-bitness": sanitizeHeaderValue2(profile.secChUaBitness),
25088
+ "sec-ch-ua-model": sanitizeHeaderValue2(profile.secChUaModel),
25089
+ "sec-ch-ua-wow64": sanitizeHeaderValue2(profile.secChUaWow64),
25090
+ "sec-ch-ua-form-factors": sanitizeHeaderValue2(profile.secChUaFormFactors),
25091
+ "sec-ch-ua-full-version-list": sanitizeHeaderValue2(profile.secChUaFullVersionList),
25092
+ "Sec-Fetch-Site": secFetchSite,
25093
+ "Sec-Fetch-Mode": isXhr ? "cors" : "navigate",
25094
+ "Sec-Fetch-Dest": isXhr ? "empty" : "document"
25095
+ };
25096
+ if (method !== "GET" && method !== "HEAD") {
25097
+ headers["Content-Type"] = sanitizeHeaderValue2(contentType);
25098
+ }
25099
+ if (shouldSendOrigin(method)) {
25100
+ headers["Origin"] = sanitizeHeaderValue2(origin2);
25101
+ }
25102
+ if (isDocument2) {
25103
+ headers["Sec-Fetch-User"] = "?1";
25104
+ headers["priority"] = "u=0, i";
25105
+ }
25106
+ if (isXhr) {
25107
+ headers["X-Requested-With"] = "XMLHttpRequest";
25108
+ headers["Pragma"] = "no-cache";
25109
+ headers["Cache-Control"] = "no-cache";
25110
+ headers["priority"] = "u=1, i";
25111
+ }
25112
+ if (isGraphQl) {
25113
+ headers["x-asbd-id"] = "129477";
25114
+ const lsd = ctx?.lsd || ctx?.fb_lsd;
25115
+ if (lsd) headers["x-fb-lsd"] = sanitizeHeaderValue2(lsd);
25116
+ const friendlyName = customHeader?.["x-fb-friendly-name"] || customHeader?.["X-Fb-Friendly-Name"];
25117
+ if (friendlyName) headers["x-fb-friendly-name"] = sanitizeHeaderValue2(friendlyName);
25118
+ }
25119
+ if (ctx?.region) {
25120
+ const regionValue = sanitizeHeaderValue2(ctx.region);
25121
+ if (regionValue) headers["X-MSGR-Region"] = regionValue;
25122
+ }
25123
+ if (customHeader && typeof customHeader === "object") {
25124
+ for (const [key, value] of Object.entries(customHeader)) {
25125
+ if (value === null || value === void 0 || typeof value === "function") continue;
25126
+ if (typeof value === "object") continue;
25127
+ const sanitizedKey = sanitizeHeaderName(key);
25128
+ let sanitizedValue = sanitizeHeaderValue2(value);
25129
+ if (!sanitizedKey || sanitizedValue === "") continue;
25130
+ if (sanitizedKey.toLowerCase() === "referer") {
25131
+ headers["Referer"] = sanitizedValue;
25132
+ if (!customHeader.origin && !customHeader.Origin && shouldSendOrigin(method)) {
25133
+ headers["Origin"] = originOf(sanitizedValue);
25134
+ }
25135
+ continue;
25136
+ }
25137
+ const existingKey = Object.keys(headers).find(
25138
+ (headerKey) => headerKey.toLowerCase() === sanitizedKey.toLowerCase()
25139
+ );
25140
+ headers[existingKey || sanitizedKey] = sanitizedValue;
25141
+ }
25142
+ }
25143
+ const sanitizedHeaders = {};
25144
+ for (const [key, value] of Object.entries(headers)) {
25145
+ if (value === void 0 || value === null) continue;
25146
+ const sanitizedKey = sanitizeHeaderName(key);
25147
+ const sanitizedValue = sanitizeHeaderValue2(value);
25148
+ if (sanitizedKey && sanitizedValue !== "") {
25149
+ sanitizedHeaders[sanitizedKey] = sanitizedValue;
25150
+ }
25151
+ }
25152
+ return sanitizedHeaders;
25153
+ }
25154
+ function getWebSocketHeaders(url2, options, ctx) {
25155
+ const profile = resolveProfile(options);
25156
+ const u = new URL(url2);
25157
+ const origin2 = isMessengerHost(u.hostname) ? "https://www.messenger.com" : isBusinessHost(u.hostname) ? "https://business.facebook.com" : "https://www.facebook.com";
25158
+ const referer = options?.referer || (origin2 === "https://www.messenger.com" ? "https://www.messenger.com/" : `${origin2}/`);
25159
+ return {
25160
+ Origin: origin2,
25161
+ Referer: referer,
25162
+ "User-Agent": profile.userAgent,
25163
+ "Accept-Language": profile.acceptLanguage,
25164
+ "Accept-Encoding": "gzip, deflate, br, zstd",
25165
+ "Cache-Control": "no-cache",
25166
+ Pragma: "no-cache",
25167
+ "sec-ch-ua": profile.secChUa,
25168
+ "sec-ch-ua-mobile": profile.secChUaMobile,
25169
+ "sec-ch-ua-platform": profile.secChUaPlatform,
25170
+ "sec-ch-ua-platform-version": profile.secChUaPlatformVersion,
25171
+ "sec-ch-ua-arch": profile.secChUaArch,
25172
+ "sec-ch-ua-bitness": profile.secChUaBitness,
25173
+ "sec-ch-ua-model": profile.secChUaModel,
25174
+ "sec-ch-ua-wow64": profile.secChUaWow64,
25175
+ "sec-ch-ua-full-version-list": profile.secChUaFullVersionList
25176
+ };
25177
+ }
25178
+ function getFingerprintParams(options) {
25179
+ const profile = resolveProfile(options);
25180
+ return {
25181
+ dpr: String(profile.devicePixelRatio)
25182
+ };
25183
+ }
25184
+ var meta;
25185
+ var init_headers = __esm({
25186
+ "src/utils/headers.ts"() {
25187
+ init_user_agents();
25188
+ meta = (prop2) => new RegExp(`<meta property="${prop2}" content="([^"]*)"`);
25189
+ }
25190
+ });
25191
+
25192
+ // src/utils/pacing.ts
25193
+ function pacingState(ctx) {
25194
+ if (!ctx.__pacing) {
25195
+ ctx.__pacing = { lastRequestAt: 0, chain: Promise.resolve(), inflight: 0 };
25196
+ }
25197
+ return ctx.__pacing;
25198
+ }
25199
+ function humanDelay(baseMs = TYPICAL_GAP_MS, spreadMs = 220) {
25200
+ const u = Math.random() * Math.random();
25201
+ const jitter = Math.floor(u * spreadMs * 2) - spreadMs;
25202
+ return Math.max(MIN_GAP_MS, Math.min(MAX_GAP_MS, baseMs + jitter));
25203
+ }
25204
+ function sleep(ms) {
25205
+ return new Promise((resolve) => setTimeout(resolve, Math.max(0, Math.floor(ms))));
25206
+ }
25207
+ async function paceRequest(ctx, weight = "normal") {
25208
+ const state = pacingState(ctx);
25209
+ const base = weight === "light" ? TYPICAL_GAP_MS * 0.5 : weight === "heavy" ? TYPICAL_GAP_MS * 2.2 : TYPICAL_GAP_MS;
25210
+ const turn = state.chain.then(async () => {
25211
+ const now = Date.now();
25212
+ const elapsed = now - state.lastRequestAt;
25213
+ if (elapsed < MIN_GAP_MS) {
25214
+ await sleep(humanDelay(Math.max(base, MIN_GAP_MS - elapsed)));
25215
+ } else if (elapsed < base) {
25216
+ await sleep(humanDelay(base - elapsed, 160));
25217
+ } else {
25218
+ await sleep(humanDelay(MIN_GAP_MS, 60));
25219
+ }
25220
+ state.lastRequestAt = Date.now();
25221
+ });
25222
+ state.chain = turn.catch(() => {
25223
+ });
25224
+ return turn;
25225
+ }
25226
+ function retryDelay(attempt, baseMs = 1200, capMs = 45e3) {
25227
+ const exp = Math.min(capMs, baseMs * Math.pow(1.7, Math.max(0, attempt)));
25228
+ const jitter = 0.5 + Math.random() * 0.75;
25229
+ return Math.min(capMs, Math.floor(exp * jitter));
25230
+ }
25231
+ function noteAction(ctx, weight = "heavy") {
25232
+ const state = pacingState(ctx);
25233
+ state.lastRequestAt = Date.now() + (weight === "heavy" ? 350 : 120);
25234
+ }
25235
+ var MIN_GAP_MS, TYPICAL_GAP_MS, MAX_GAP_MS;
25236
+ var init_pacing = __esm({
25237
+ "src/utils/pacing.ts"() {
25238
+ MIN_GAP_MS = 120;
25239
+ TYPICAL_GAP_MS = 420;
25240
+ MAX_GAP_MS = 2500;
25241
+ }
25242
+ });
25243
+
25244
+ // src/utils/safety.ts
25245
+ function safetyState(ctx) {
25246
+ if (!ctx.__safety) {
25247
+ ctx.__safety = { window: [], openedAt: 0, authFailures: 0, cappedCount: 0, trips: [] };
25248
+ }
25249
+ const state = ctx.__safety;
25250
+ if (!Array.isArray(state.window)) state.window = [];
25251
+ if (!Array.isArray(state.trips)) state.trips = [];
25252
+ return state;
25253
+ }
25254
+ function cooldownFor(state) {
25255
+ const factor = Math.pow(1.8, Math.max(0, state.trips.length - 1));
25256
+ return Math.min(MAX_COOLDOWN_MS, Math.floor(BASE_COOLDOWN_MS * factor));
25257
+ }
25258
+ function isBreakerOpen(ctx) {
25259
+ const state = safetyState(ctx);
25260
+ if (!state.openedAt) return false;
25261
+ if (Date.now() - state.openedAt >= cooldownFor(state)) {
25262
+ state.openedAt = 0;
25263
+ state.authFailures = 0;
25264
+ return false;
25265
+ }
25266
+ return true;
25267
+ }
25268
+ function tripBreaker(ctx, reason = "manual") {
25269
+ const state = safetyState(ctx);
25270
+ if (state.openedAt && state.reason === reason) return;
25271
+ state.openedAt = Date.now();
25272
+ state.reason = reason;
25273
+ state.authFailures = 0;
25274
+ state.trips.push(Date.now());
25275
+ if (ctx.__onSafetyTrip) {
25276
+ try {
25277
+ ctx.__onSafetyTrip({ reason, cooldownMs: cooldownFor(state) });
25278
+ } catch {
25279
+ }
25280
+ }
25281
+ }
25282
+ function resetBreaker(ctx) {
25283
+ const state = safetyState(ctx);
25284
+ state.openedAt = 0;
25285
+ state.reason = void 0;
25286
+ state.authFailures = 0;
25287
+ }
25288
+ function noteAuthFailure(ctx) {
25289
+ const state = safetyState(ctx);
25290
+ state.authFailures += 1;
25291
+ if (state.authFailures >= AUTH_FAILURE_THRESHOLD) {
25292
+ tripBreaker(ctx, "auth-failure");
25293
+ }
25294
+ }
25295
+ function noteRateLimit(ctx) {
25296
+ tripBreaker(ctx, "rate-limit");
25297
+ }
25298
+ function noteCheckpoint(ctx) {
25299
+ tripBreaker(ctx, "checkpoint");
25300
+ }
25301
+ function reserveRequest(ctx) {
25302
+ const state = safetyState(ctx);
25303
+ if (isBreakerOpen(ctx)) {
25304
+ return cooldownFor(state) - (Date.now() - state.openedAt);
25305
+ }
25306
+ const now = Date.now();
25307
+ state.window = state.window.filter((t) => now - t < WINDOW_MS);
25308
+ if (state.window.length >= MAX_REQUESTS_IN_WINDOW) {
25309
+ state.cappedCount += 1;
25310
+ const oldest = state.window[0];
25311
+ return Math.max(0, WINDOW_MS - (now - oldest));
25312
+ }
25313
+ state.window.push(now);
25314
+ return 0;
25315
+ }
25316
+ function safetySnapshot(ctx) {
25317
+ const state = safetyState(ctx);
25318
+ const now = Date.now();
25319
+ state.window = state.window.filter((t) => now - t < WINDOW_MS);
25320
+ const open = isBreakerOpen(ctx);
25321
+ return {
25322
+ closed: !open,
25323
+ reason: open ? state.reason : void 0,
25324
+ cooldownRemainingMs: open ? cooldownFor(state) - (now - state.openedAt) : 0,
25325
+ requestsInWindow: state.window.length,
25326
+ authFailures: state.authFailures,
25327
+ cappedCount: state.cappedCount
25328
+ };
25329
+ }
25330
+ var MAX_REQUESTS_IN_WINDOW, WINDOW_MS, BASE_COOLDOWN_MS, MAX_COOLDOWN_MS, AUTH_FAILURE_THRESHOLD;
25331
+ var init_safety = __esm({
25332
+ "src/utils/safety.ts"() {
25333
+ MAX_REQUESTS_IN_WINDOW = 28;
25334
+ WINDOW_MS = 2e4;
25335
+ BASE_COOLDOWN_MS = 3 * 60 * 1e3;
25336
+ MAX_COOLDOWN_MS = 30 * 60 * 1e3;
25337
+ AUTH_FAILURE_THRESHOLD = 3;
25338
+ }
25339
+ });
25340
+
24957
25341
  // src/utils/axios.ts
24958
25342
  var axios_exports = {};
24959
25343
  __export(axios_exports, {
@@ -25019,18 +25403,37 @@ function adaptResponse(res) {
25019
25403
  }
25020
25404
  };
25021
25405
  }
25406
+ function looksLikeCheckpoint(res) {
25407
+ const location = res?.headers?.location || res?.headers?.Location || "";
25408
+ if (typeof location === "string" && /\/checkpoint\/|two_factor|\/consent|\/recover|account_disabled/i.test(location)) {
25409
+ return true;
25410
+ }
25411
+ const body = typeof res?.body === "string" ? res.body : "";
25412
+ return /"error":1357004|account has been (?:disabled|suspended)|confirm your identity|security check/i.test(body.slice(0, 400));
25413
+ }
25022
25414
  async function requestWithRetry(requestFunction, retries = 3, baseDelay = 1e3, ctx) {
25023
25415
  const emit2 = (event, payload) => {
25024
25416
  try {
25025
- if (ctx?._emitter && typeof ctx._emitter.emit === "function") ;
25417
+ if (ctx?._emitter && typeof ctx._emitter.emit === "function") {
25418
+ ctx._emitter.emit(event, payload);
25419
+ }
25026
25420
  } catch {
25027
25421
  }
25028
25422
  };
25029
25423
  let lastError;
25030
25424
  for (let i2 = 0; i2 < retries; i2++) {
25031
25425
  try {
25426
+ const safetyWait = reserveRequest(ctx);
25427
+ if (safetyWait > 0) await delay(safetyWait);
25428
+ await paceRequest(ctx, "normal");
25032
25429
  const res = await requestFunction();
25033
- return adaptResponse(res);
25430
+ const adapted = adaptResponse(res);
25431
+ if (looksLikeCheckpoint(adapted)) {
25432
+ noteCheckpoint(ctx);
25433
+ } else {
25434
+ resetBreaker(ctx);
25435
+ }
25436
+ return adapted;
25034
25437
  } catch (rawError) {
25035
25438
  const e = rawError || {};
25036
25439
  lastError = e;
@@ -25046,6 +25449,7 @@ async function requestWithRetry(requestFunction, retries = 3, baseDelay = 1e3, c
25046
25449
  const method = String(e?.config?.method || "").toUpperCase();
25047
25450
  if (status === 429) {
25048
25451
  emit2("rateLimit", { status, url: url2, method });
25452
+ noteRateLimit(ctx);
25049
25453
  }
25050
25454
  if (status >= 400 && status < 500 && status !== 429) {
25051
25455
  if (e.response) return adaptResponse(e.response);
@@ -25060,8 +25464,7 @@ async function requestWithRetry(requestFunction, retries = 3, baseDelay = 1e3, c
25060
25464
  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))) {
25061
25465
  emit2("networkError", { code: netCode, message: msg, url: url2, method });
25062
25466
  }
25063
- const backoffDelay = Math.min(baseDelay * Math.pow(2, i2) + Math.floor(Math.random() * 200), 3e4);
25064
- await delay(backoffDelay);
25467
+ await delay(retryDelay(i2, baseDelay, 3e4));
25065
25468
  }
25066
25469
  }
25067
25470
  throw lastError || new Error("Request failed after retries");
@@ -25084,16 +25487,16 @@ function cleanGet(url2) {
25084
25487
  }
25085
25488
  async function get(url2, reqJar, qs2, options, ctx, customHeader) {
25086
25489
  const config = {
25087
- headers: getHeaders(url2, options, ctx, customHeader),
25490
+ headers: getHeaders(url2, { ...options, method: "GET" }, ctx, customHeader),
25088
25491
  timeout: 6e4,
25089
25492
  params: qs2,
25090
25493
  ...getRequestProxy(options),
25091
25494
  validateStatus: (status) => status >= 200 && status < 600
25092
25495
  };
25093
- return requestWithRetry(async () => await getClient(reqJar).get(url2, config));
25496
+ return requestWithRetry(async () => await getClient(reqJar).get(url2, config), 3, 1e3, ctx);
25094
25497
  }
25095
25498
  async function post(url2, reqJar, form, options, ctx, customHeader) {
25096
- const headers = getHeaders(url2, options, ctx, customHeader);
25499
+ const headers = getHeaders(url2, { ...options, method: "POST" }, ctx, customHeader);
25097
25500
  let data2 = form;
25098
25501
  const contentType = headers["Content-Type"] || "application/x-www-form-urlencoded";
25099
25502
  if (contentType.includes("json")) {
@@ -25118,7 +25521,7 @@ async function post(url2, reqJar, form, options, ctx, customHeader) {
25118
25521
  ...getRequestProxy(options),
25119
25522
  validateStatus: (status) => status >= 200 && status < 600
25120
25523
  };
25121
- return requestWithRetry(async () => await getClient(reqJar).post(url2, data2, config));
25524
+ return requestWithRetry(async () => await getClient(reqJar).post(url2, data2, config), 3, 1e3, ctx);
25122
25525
  }
25123
25526
  async function postMultipart(url2, reqJar, formData, qs2, options, ctx, customHeader) {
25124
25527
  const multipartHeader = {
@@ -25126,7 +25529,7 @@ async function postMultipart(url2, reqJar, formData, qs2, options, ctx, customHe
25126
25529
  ...customHeader || {}
25127
25530
  };
25128
25531
  const config = {
25129
- headers: getHeaders(url2, options, ctx, multipartHeader),
25532
+ headers: getHeaders(url2, { ...options, method: "POST" }, ctx, multipartHeader),
25130
25533
  timeout: 12e4,
25131
25534
  params: qs2,
25132
25535
  maxContentLength: Infinity,
@@ -25134,7 +25537,7 @@ async function postMultipart(url2, reqJar, formData, qs2, options, ctx, customHe
25134
25537
  ...getRequestProxy(options),
25135
25538
  validateStatus: (status) => status >= 200 && status < 600
25136
25539
  };
25137
- return requestWithRetry(async () => await getClient(reqJar).post(url2, formData, config));
25540
+ return requestWithRetry(async () => await getClient(reqJar).post(url2, formData, config), 3, 1e3, ctx);
25138
25541
  }
25139
25542
  async function postFormData(url2, reqJar, form, qs2, options, ctx, customHeader) {
25140
25543
  const formData = new import_form_data2.default();
@@ -25148,13 +25551,13 @@ async function postFormData(url2, reqJar, form, qs2, options, ctx, customHeader)
25148
25551
  ...customHeader || {}
25149
25552
  };
25150
25553
  const config = {
25151
- headers: getHeaders(url2, options, ctx, multipartHeader),
25554
+ headers: getHeaders(url2, { ...options, method: "POST" }, ctx, multipartHeader),
25152
25555
  timeout: 6e4,
25153
25556
  params: qs2,
25154
25557
  ...getRequestProxy(options),
25155
25558
  validateStatus: (status) => status >= 200 && status < 600
25156
25559
  };
25157
- return requestWithRetry(async () => await getClient(reqJar).post(url2, formData, config));
25560
+ return requestWithRetry(async () => await getClient(reqJar).post(url2, formData, config), 3, 1e3, ctx);
25158
25561
  }
25159
25562
  function getJar() {
25160
25563
  return new import_tough_cookie.CookieJar();
@@ -25168,6 +25571,8 @@ var init_axios3 = __esm({
25168
25571
  import_form_data2 = __toESM(require_form_data2());
25169
25572
  init_headers();
25170
25573
  init_constants();
25574
+ init_pacing();
25575
+ init_safety();
25171
25576
  jar = new import_tough_cookie.CookieJar();
25172
25577
  client = wrapper(axios_default.create({ jar }));
25173
25578
  clients = /* @__PURE__ */ new WeakMap();
@@ -69521,7 +69926,7 @@ var require_dist3 = __commonJS({
69521
69926
  }
69522
69927
  return options;
69523
69928
  };
69524
- var HttpsProxyAgent5 = class extends agent_base_1.Agent {
69929
+ var HttpsProxyAgent4 = class extends agent_base_1.Agent {
69525
69930
  constructor(proxy, opts) {
69526
69931
  super(opts);
69527
69932
  this.options = { path: void 0 };
@@ -69600,8 +70005,8 @@ var require_dist3 = __commonJS({
69600
70005
  return fakeSocket;
69601
70006
  }
69602
70007
  };
69603
- HttpsProxyAgent5.protocols = ["http", "https"];
69604
- exports.HttpsProxyAgent = HttpsProxyAgent5;
70008
+ HttpsProxyAgent4.protocols = ["http", "https"];
70009
+ exports.HttpsProxyAgent = HttpsProxyAgent4;
69605
70010
  function resume(socket) {
69606
70011
  socket.resume();
69607
70012
  }
@@ -75102,34 +75507,57 @@ var require_lodash = __commonJS({
75102
75507
  var utils_exports2 = {};
75103
75508
  __export(utils_exports2, {
75104
75509
  AUTHOR: () => AUTHOR,
75510
+ AUTH_ERROR_CODES: () => AUTH_ERROR_CODES,
75511
+ AUTH_FAILURE_THRESHOLD: () => AUTH_FAILURE_THRESHOLD,
75105
75512
  AuthenticationError: () => AuthenticationError,
75513
+ BASE_COOLDOWN_MS: () => BASE_COOLDOWN_MS,
75106
75514
  BRAND: () => BRAND,
75515
+ CHROME_MAJORS: () => CHROME_MAJORS,
75107
75516
  ConfigurationError: () => ConfigurationError,
75517
+ DESKTOP_PLATFORMS: () => DESKTOP_PLATFORMS,
75108
75518
  FCAError: () => FCAError,
75519
+ LS_DOC_TOKEN_ERRORS: () => LS_DOC_TOKEN_ERRORS,
75520
+ MAX_REQUESTS_IN_WINDOW: () => MAX_REQUESTS_IN_WINDOW,
75109
75521
  NUM_TO_DAY: () => NUM_TO_DAY,
75110
75522
  NUM_TO_MONTH: () => NUM_TO_MONTH,
75111
75523
  NetworkError: () => NetworkError,
75112
75524
  NotFoundError: () => NotFoundError,
75113
75525
  PermissionError: () => PermissionError,
75114
75526
  RateLimitError: () => RateLimitError,
75527
+ SESSION_COOKIE_NAMES: () => SESSION_COOKIE_NAMES,
75115
75528
  TimeoutError: () => TimeoutError,
75116
75529
  ValidationError: () => ValidationError,
75530
+ WINDOW_MS: () => WINDOW_MS,
75117
75531
  _formatAttachment: () => _formatAttachment,
75532
+ applySetCookie: () => applySetCookie,
75118
75533
  arrToForm: () => arrToForm,
75119
75534
  arrayToObject: () => arrayToObject2,
75535
+ awaitProactiveSlot: () => awaitProactiveSlot,
75120
75536
  banner: () => banner,
75121
75537
  binaryToDecimal: () => binaryToDecimal,
75122
75538
  brandTag: () => brandTag,
75539
+ buildProfile: () => buildProfile,
75123
75540
  buildWsTaskContent: () => buildWsTaskContent,
75541
+ canActProactively: () => canActProactively,
75124
75542
  cleanGet: () => cleanGet,
75125
75543
  cleanJsonResponse: () => cleanJsonResponse,
75544
+ collectSessionCookies: () => collectSessionCookies,
75126
75545
  debug: () => debug,
75127
75546
  decodeClientPayload: () => decodeClientPayload,
75547
+ defaultBrowserProfile: () => defaultBrowserProfile,
75128
75548
  defaultUserAgent: () => defaultUserAgent,
75129
75549
  delay: () => delay2,
75130
75550
  ensureCometTokens: () => ensureCometTokens,
75131
75551
  error: () => error,
75132
75552
  extractAttachmentIds: () => extractAttachmentIds,
75553
+ extractCookies: () => extractCookies,
75554
+ extractCookiesFromBody: () => extractCookiesFromBody,
75555
+ extractCookiesFromJar: () => extractCookiesFromJar,
75556
+ extractCookiesFromSetCookie: () => extractCookiesFromSetCookie,
75557
+ extractDtsg: () => extractDtsg,
75558
+ extractLsd: () => extractLsd,
75559
+ extractSpin: () => extractSpin,
75560
+ formatAppStateCookie: () => formatAppStateCookie,
75133
75561
  formatAttachment: () => formatAttachment,
75134
75562
  formatCookie: () => formatCookie2,
75135
75563
  formatDate: () => formatDate,
@@ -75156,6 +75584,7 @@ __export(utils_exports2, {
75156
75584
  getAccessFromBusiness: () => getAccessFromBusiness,
75157
75585
  getAdminTextMessageType: () => getAdminTextMessageType,
75158
75586
  getAppState: () => getAppState,
75587
+ getFingerprintParams: () => getFingerprintParams,
75159
75588
  getFrom: () => getFrom,
75160
75589
  getGUID: () => getGUID,
75161
75590
  getHeaders: () => getHeaders,
@@ -75163,14 +75592,28 @@ __export(utils_exports2, {
75163
75592
  getRandom: () => getRandom,
75164
75593
  getSignatureID: () => getSignatureID,
75165
75594
  getType: () => getType,
75595
+ getWebSocketHeaders: () => getWebSocketHeaders,
75596
+ hasAuthenticatedSession: () => hasAuthenticatedSession,
75597
+ humanDelay: () => humanDelay,
75166
75598
  info: () => info,
75599
+ invalidateCometTokens: () => invalidateCometTokens,
75600
+ isAuthFailure: () => isAuthFailure,
75601
+ isBreakerOpen: () => isBreakerOpen,
75167
75602
  isReadableStream: () => isReadableStream2,
75603
+ isStaleTokenError: () => isStaleTokenError,
75168
75604
  json: () => json2,
75169
75605
  log: () => log,
75170
75606
  logOptions: () => logOptions,
75171
75607
  makeDefaults: () => makeDefaults,
75172
75608
  makeParsable: () => makeParsable,
75173
75609
  meta: () => meta,
75610
+ missingSessionCookies: () => missingSessionCookies,
75611
+ normalizeBrowserProfile: () => normalizeBrowserProfile,
75612
+ noteAction: () => noteAction,
75613
+ noteAuthFailure: () => noteAuthFailure,
75614
+ noteCheckpoint: () => noteCheckpoint,
75615
+ noteRateLimit: () => noteRateLimit,
75616
+ paceRequest: () => paceRequest,
75174
75617
  padZeros: () => padZeros,
75175
75618
  parseAndCheckLogin: () => parseAndCheckLogin,
75176
75619
  post: () => post,
@@ -75181,16 +75624,31 @@ __export(utils_exports2, {
75181
75624
  promisify: () => promisify,
75182
75625
  publishLsRequestWithAck: () => publishLsRequestWithAck,
75183
75626
  randomUserAgent: () => randomUserAgent,
75627
+ refreshSessionCookies: () => refreshSessionCookies,
75628
+ repairSession: () => repairSession,
75629
+ reserveRequest: () => reserveRequest,
75630
+ resetBreaker: () => resetBreaker,
75631
+ resolveProfile: () => resolveProfile,
75632
+ retryDelay: () => retryDelay,
75633
+ safetySnapshot: () => safetySnapshot,
75184
75634
  saveCookies: () => saveCookies,
75635
+ scheduleSessionKeepAlive: () => scheduleSessionKeepAlive,
75185
75636
  setProxy: () => setProxy2,
75637
+ sleep: () => sleep,
75638
+ startLiveness: () => startLiveness,
75186
75639
  success: () => success,
75640
+ tripBreaker: () => tripBreaker,
75187
75641
  uploadGroupImage: () => uploadGroupImage,
75188
75642
  uploadMercuryAttachment: () => uploadMercuryAttachment,
75643
+ warmUpSession: () => warmUpSession,
75189
75644
  warn: () => warn,
75190
75645
  windowsUserAgent: () => windowsUserAgent,
75646
+ withCometTokens: () => withCometTokens,
75647
+ withSessionRetry: () => withSessionRetry,
75191
75648
  ws: () => ws
75192
75649
  });
75193
75650
  init_axios3();
75651
+ init_headers();
75194
75652
  init_constants();
75195
75653
 
75196
75654
  // node_modules/cheerio/dist/esm/options.js
@@ -89399,8 +89857,34 @@ init_headers();
89399
89857
 
89400
89858
  // src/utils/clients.ts
89401
89859
  init_constants();
89860
+ function formatAppStateCookie(cookie) {
89861
+ const name = cookie.name || cookie.key;
89862
+ const value = String(cookie.value);
89863
+ const parts = [`${name}=${value}`];
89864
+ const path2 = cookie.path || "/";
89865
+ parts.push(`Path=${path2}`);
89866
+ const domain = cookie.domain || ".facebook.com";
89867
+ parts.push(`Domain=${domain}`);
89868
+ if (cookie.secure) parts.push("Secure");
89869
+ if (cookie.httpOnly) parts.push("HttpOnly");
89870
+ const sameSite = normalizeSameSite(cookie.sameSite);
89871
+ if (sameSite) parts.push(`SameSite=${sameSite}`);
89872
+ if (cookie.expirationDate && !cookie.session) {
89873
+ parts.push(`Expires=${new Date(cookie.expirationDate * 1e3).toUTCString()}`);
89874
+ }
89875
+ return parts.join("; ");
89876
+ }
89877
+ function normalizeSameSite(value) {
89878
+ if (!value) return null;
89879
+ const v = String(value).toLowerCase();
89880
+ if (v === "no_restriction" || v === "none") return "None";
89881
+ if (v === "lax") return "Lax";
89882
+ if (v === "strict") return "Strict";
89883
+ return null;
89884
+ }
89402
89885
  function formatCookie(arr, url2) {
89403
- return arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=" + url2 + ".com";
89886
+ const host = url2.replace(/^\./, "");
89887
+ return arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=." + host + "; Secure; SameSite=None";
89404
89888
  }
89405
89889
  function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89406
89890
  const delay3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -89409,7 +89893,7 @@ function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89409
89893
  throw new Error("parseAndCheckLogin received an invalid response.");
89410
89894
  }
89411
89895
  if (data2.statusCode >= 500 && data2.statusCode < 600) {
89412
- if (noRetry || retryCount >= 5) {
89896
+ if (noRetry || retryCount >= 3) {
89413
89897
  const err = new Error(
89414
89898
  "Request retry failed. Check the `res` and `statusCode` property on this error."
89415
89899
  );
@@ -89419,7 +89903,7 @@ function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89419
89903
  throw err;
89420
89904
  }
89421
89905
  retryCount++;
89422
- const retryTime = Math.floor(Math.random() * 5e3);
89906
+ const retryTime = Math.min(3e4, Math.floor(800 * Math.pow(1.7, retryCount) * (0.5 + Math.random())));
89423
89907
  const request = data2.request || {};
89424
89908
  const uri = request.uri || {};
89425
89909
  const url2 = request.url || (uri.protocol && uri.hostname ? uri.protocol + "//" + uri.hostname + (uri.port ? ":" + uri.port : "") + (uri.pathname || "") : "");
@@ -89469,17 +89953,17 @@ function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89469
89953
  } else {
89470
89954
  throw new Error("Unknown response body type: " + typeof data2.body);
89471
89955
  }
89472
- if (res.redirect && data2.request.method === "GET") {
89956
+ if (res.redirect && data2.request.method === "GET" && retryCount < 5) {
89473
89957
  const redirectRes = await http5.get(res.redirect, ctx.jar);
89474
- return await parseAndCheckLogin(ctx, http5)(redirectRes);
89958
+ return await parseAndCheckLogin(ctx, http5, retryCount + 1)(redirectRes);
89475
89959
  }
89476
89960
  if (res.jsmods && res.jsmods.require && Array.isArray(res.jsmods.require[0]) && res.jsmods.require[0][0] === "Cookie") {
89477
89961
  const requireCookie = res.jsmods.require[0][3];
89478
89962
  if (Array.isArray(requireCookie) && requireCookie.length >= 4) {
89479
89963
  const cookieValue = String(requireCookie[0]).replace("_js_", "");
89480
89964
  const normalizedCookie = [cookieValue, requireCookie[1], requireCookie[2], requireCookie[3]];
89481
- ctx.jar.setCookie(formatCookie(normalizedCookie, "facebook"), "https://www.facebook.com");
89482
- ctx.jar.setCookie(formatCookie(normalizedCookie, "messenger"), "https://www.messenger.com");
89965
+ ctx.jar.setCookieSync(formatCookie(normalizedCookie, "facebook"), "https://www.facebook.com");
89966
+ ctx.jar.setCookieSync(formatCookie(normalizedCookie, "messenger"), "https://www.messenger.com");
89483
89967
  }
89484
89968
  }
89485
89969
  if (res.jsmods && Array.isArray(res.jsmods.require)) {
@@ -89504,13 +89988,27 @@ function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89504
89988
  }
89505
89989
  function saveCookies(jar2) {
89506
89990
  return function(res) {
89507
- const cookies = res?.headers?.["set-cookie"] || [];
89991
+ const headers = res?.headers || {};
89992
+ const raw = headers["set-cookie"] || headers["Set-Cookie"] || [];
89993
+ const cookies = Array.isArray(raw) ? raw : [raw];
89508
89994
  cookies.forEach(function(c) {
89509
- if (c.indexOf(".facebook.com") > -1) {
89510
- jar2.setCookie(c, "https://www.facebook.com");
89995
+ if (!c || typeof c !== "string") return;
89996
+ if (/domain=\.?facebook\.com/i.test(c) || /domain=\.?messenger\.com/i.test(c)) {
89997
+ try {
89998
+ jar2.setCookieSync(c, "https://www.facebook.com");
89999
+ } catch {
90000
+ }
90001
+ try {
90002
+ const mirrored = c.replace(/domain=\.?facebook\.com/i, "domain=.messenger.com").replace(/domain=\.?messenger\.com/i, "domain=.facebook.com");
90003
+ jar2.setCookieSync(mirrored, "https://www.messenger.com");
90004
+ } catch {
90005
+ }
90006
+ } else {
90007
+ try {
90008
+ jar2.setCookieSync(`${c}; domain=.facebook.com; path=/`, "https://www.facebook.com");
90009
+ } catch {
90010
+ }
89511
90011
  }
89512
- const c2 = c.replace(/domain=\.facebook\.com/, "domain=.messenger.com");
89513
- jar2.setCookie(c2, "https://www.messenger.com");
89514
90012
  });
89515
90013
  return res;
89516
90014
  };
@@ -90040,43 +90538,8 @@ function formatProxyPresence(presence, userID) {
90040
90538
  };
90041
90539
  }
90042
90540
 
90043
- // src/utils/user-agents.ts
90044
- init_constants();
90045
- var BROWSER_DATA = {
90046
- windows: {
90047
- platform: "Windows NT 10.0; Win64; x64",
90048
- chromeVersions: ["126.0.0.0", "125.0.0.0", "124.0.0.0"],
90049
- platformVersion: '"15.0.0"'
90050
- },
90051
- mac: {
90052
- platform: "Macintosh; Intel Mac OS X 10_15_7",
90053
- chromeVersions: ["126.0.0.0", "125.0.0.0", "124.0.0.0"],
90054
- platformVersion: '"15.7.9"'
90055
- }
90056
- };
90057
- 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";
90058
- var windowsUserAgent = defaultUserAgent;
90059
- function randomUserAgent() {
90060
- const os = getRandom(Object.keys(BROWSER_DATA));
90061
- const data2 = BROWSER_DATA[os];
90062
- const version = getRandom(data2.chromeVersions);
90063
- const majorVersion = version.split(".")[0];
90064
- const userAgent = `Mozilla/5.0 (${data2.platform}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`;
90065
- const brands = [
90066
- `"Not/A)Brand";v="8"`,
90067
- `"Chromium";v="${majorVersion}"`,
90068
- `"Google Chrome";v="${majorVersion}"`
90069
- ];
90070
- const secChUa = brands.join(", ");
90071
- const secChUaFullVersionList = brands.map((b) => b.replace(/"$/, `.0.0.0"`)).join(", ");
90072
- return {
90073
- userAgent,
90074
- secChUa,
90075
- secChUaFullVersionList,
90076
- secChUaPlatform: `"${os === "windows" ? "Windows" : "macOS"}"`,
90077
- secChUaPlatformVersion: data2.platformVersion
90078
- };
90079
- }
90541
+ // src/utils/index.ts
90542
+ init_user_agents();
90080
90543
 
90081
90544
  // src/utils/errors.ts
90082
90545
  var FCAError = class extends Error {
@@ -90240,6 +90703,7 @@ function buildWsTaskContent(ctx, tasks, versionId) {
90240
90703
  // src/utils/attachments.ts
90241
90704
  var import_form_data3 = __toESM(require_form_data2());
90242
90705
  init_constants();
90706
+ init_user_agents();
90243
90707
  function cleanJsonResponse(value) {
90244
90708
  if (typeof value !== "string") return value;
90245
90709
  const normalized = value.replace(/^for\s*\(;;\);\s*/i, "");
@@ -90381,7 +90845,7 @@ function normalizeFilename(filename, mime) {
90381
90845
  return ext ? `${base}.${ext}` : base;
90382
90846
  }
90383
90847
  async function uploadMercuryAttachment(ctx, defaultFuncs, attachment) {
90384
- const normalized = await normalizeAttachmentInput(attachment);
90848
+ const normalized = await normalizeAttachmentInput(attachment, ctx);
90385
90849
  const url2 = "https://www.facebook.com/ajax/mercury/upload.php";
90386
90850
  await ensureUploadTokens(ctx, defaultFuncs);
90387
90851
  const formData = new import_form_data3.default();
@@ -90393,7 +90857,7 @@ async function uploadMercuryAttachment(ctx, defaultFuncs, attachment) {
90393
90857
  const data2 = cleanJsonResponse(res && res.body !== void 0 ? res.body : res);
90394
90858
  return finalizeUpload(data2);
90395
90859
  }
90396
- async function normalizeAttachmentInput(attachment) {
90860
+ async function normalizeAttachmentInput(attachment, ctx) {
90397
90861
  if (Buffer.isBuffer(attachment)) {
90398
90862
  const mime = sniffMime(attachment);
90399
90863
  return {
@@ -90405,7 +90869,11 @@ async function normalizeAttachmentInput(attachment) {
90405
90869
  const url2 = typeof attachment === "string" ? attachment : attachment && (attachment.url || attachment.href);
90406
90870
  if (typeof url2 === "string" && /^https?:\/\//i.test(url2)) {
90407
90871
  const resp = await fetch(url2, {
90408
- headers: { "User-Agent": "Mozilla/5.0", Accept: "*/*" }
90872
+ headers: {
90873
+ "User-Agent": ctx?.globalOptions && ctx.globalOptions.userAgent || defaultBrowserProfile.userAgent,
90874
+ Accept: "image/avif,image/webp,image/apng,image/svg+xml,image/*,video/*,audio/*,*/*;q=0.8",
90875
+ "Accept-Language": ctx?.globalOptions && ctx.globalOptions.browser?.acceptLanguage || "en-US,en;q=0.9"
90876
+ }
90409
90877
  });
90410
90878
  if (!resp.ok) {
90411
90879
  throw new Error(`Failed to download attachment url (HTTP ${resp.status})`);
@@ -90495,7 +90963,21 @@ async function uploadGroupImage(ctx, defaultFuncs, image) {
90495
90963
  }
90496
90964
 
90497
90965
  // src/utils/lsd.ts
90498
- var TOKEN_TTL_MS = 30 * 60 * 1e3;
90966
+ var TOKEN_TTL_MS = 10 * 60 * 1e3;
90967
+ var STALE_TOKEN_ERRORS = /* @__PURE__ */ new Set([
90968
+ 1357004,
90969
+ // "Sorry, something went wrong / close and re-open your browser window"
90970
+ 1357031,
90971
+ // document token invalid
90972
+ 1357051
90973
+ // token mismatch
90974
+ ]);
90975
+ var MAX_BACKOFF_MS = 60 * 1e3;
90976
+ function tokenState(ctx) {
90977
+ const state = ctx.__cometTokens || (ctx.__cometTokens = {});
90978
+ if (typeof state.failures !== "number") state.failures = 0;
90979
+ return state;
90980
+ }
90499
90981
  function getFrom3(html3, startToken, endToken) {
90500
90982
  const startIndex = html3.indexOf(startToken);
90501
90983
  if (startIndex < 0) return "";
@@ -90510,34 +90992,544 @@ function extractLsd(html3) {
90510
90992
  function extractDtsg(html3) {
90511
90993
  return getFrom3(html3, '["DTSGInitialData",[],{"token":"', '"}') || getFrom3(html3, 'name="fb_dtsg" value="', '"') || (html3.match(/"DTSGInitialData",\[\],\{"token":"([^"]+)"/) || [])[1] || "";
90512
90994
  }
90995
+ function extractSpin(html3) {
90996
+ const out = {};
90997
+ const spinB = (html3.match(/"__spin_b":"([^"]+)"/) || [])[1];
90998
+ const spinR = (html3.match(/"__spin_r":(\d+)/) || [])[1];
90999
+ const spinT = (html3.match(/"__spin_t":(\d+)/) || [])[1];
91000
+ const rev = (html3.match(/"__rev":(\d+)/) || [])[1] || getFrom3(html3, 'revision":', ",");
91001
+ if (spinB) out.__spin_b = spinB;
91002
+ if (spinR) out.__spin_r = spinR;
91003
+ if (spinT) out.__spin_t = spinT;
91004
+ if (rev) out.__rev = rev;
91005
+ return out;
91006
+ }
91007
+ function recomputeJazoest(fbDtsg) {
91008
+ let sum = 0;
91009
+ for (let i2 = 0; i2 < fbDtsg.length; i2++) sum += fbDtsg.charCodeAt(i2);
91010
+ return "2" + String(sum);
91011
+ }
91012
+ function tokenPairFresh(state) {
91013
+ return Boolean(
91014
+ state.lsd && state.fb_dtsg && state.fetchedAt && Date.now() - state.fetchedAt < TOKEN_TTL_MS
91015
+ );
91016
+ }
91017
+ function htmlOf(res) {
91018
+ if (typeof res === "string") return res;
91019
+ if (res && typeof res.body === "string") return res.body;
91020
+ if (res && res.body != null) return String(res.body);
91021
+ return "";
91022
+ }
90513
91023
  async function ensureCometTokens(ctx, defaultFuncs, force = false) {
90514
- const state = ctx.__cometTokens || (ctx.__cometTokens = {});
90515
- const fresh = state.fetchedAt && Date.now() - state.fetchedAt < TOKEN_TTL_MS;
90516
- if (!force && fresh && state.lsd && state.fb_dtsg) {
91024
+ const state = tokenState(ctx);
91025
+ if (!force && tokenPairFresh(state)) {
90517
91026
  ctx.lsd = state.lsd;
90518
91027
  ctx.fb_dtsg = state.fb_dtsg;
90519
91028
  return;
90520
91029
  }
91030
+ if (!force && state.failures > 0) {
91031
+ const backoff = Math.min(1e3 * Math.pow(2, state.failures), MAX_BACKOFF_MS);
91032
+ if (state.attemptedAt && Date.now() - state.attemptedAt < backoff) {
91033
+ if (state.lsd && state.fb_dtsg) {
91034
+ ctx.lsd = state.lsd;
91035
+ ctx.fb_dtsg = state.fb_dtsg;
91036
+ }
91037
+ return;
91038
+ }
91039
+ }
91040
+ state.attemptedAt = Date.now();
90521
91041
  try {
90522
91042
  const res = await defaultFuncs.get("https://www.facebook.com/", ctx.jar);
90523
- const html3 = typeof res === "string" ? res : res && res.body;
90524
- if (typeof html3 !== "string") return;
91043
+ const html3 = htmlOf(res);
91044
+ if (!html3) {
91045
+ state.failures++;
91046
+ return;
91047
+ }
90525
91048
  const lsd = extractLsd(html3);
90526
91049
  const dtsg = extractDtsg(html3);
90527
- if (lsd) state.lsd = lsd;
90528
- if (dtsg) state.fb_dtsg = dtsg;
91050
+ if (!lsd || !dtsg) {
91051
+ state.failures++;
91052
+ return;
91053
+ }
91054
+ state.lsd = lsd;
91055
+ state.fb_dtsg = dtsg;
90529
91056
  state.fetchedAt = Date.now();
90530
- if (state.lsd) ctx.lsd = state.lsd;
90531
- if (state.fb_dtsg) {
90532
- ctx.fb_dtsg = state.fb_dtsg;
90533
- if (typeof ctx.jazoest !== "string" || !ctx.jazoest) {
90534
- let sum = 0;
90535
- for (let i2 = 0; i2 < ctx.fb_dtsg.length; i2++) sum += ctx.fb_dtsg.charCodeAt(i2);
90536
- ctx.jazoest = "2" + String(sum);
91057
+ state.failures = 0;
91058
+ const spin = extractSpin(html3);
91059
+ if (Object.keys(spin).length) ctx.__spin = { ...ctx.__spin || {}, ...spin };
91060
+ if (spin.__rev) ctx.revision = spin.__rev;
91061
+ ctx.lsd = lsd;
91062
+ ctx.fb_dtsg = dtsg;
91063
+ ctx.jazoest = recomputeJazoest(dtsg);
91064
+ } catch {
91065
+ state.failures++;
91066
+ }
91067
+ }
91068
+ function invalidateCometTokens(ctx) {
91069
+ const state = tokenState(ctx);
91070
+ state.lsd = void 0;
91071
+ state.fb_dtsg = void 0;
91072
+ state.fetchedAt = void 0;
91073
+ state.failures = 0;
91074
+ state.attemptedAt = 0;
91075
+ delete ctx.lsd;
91076
+ delete ctx.fb_dtsg;
91077
+ }
91078
+ function isStaleTokenError(value) {
91079
+ if (value == null) return false;
91080
+ if (typeof value === "number") return STALE_TOKEN_ERRORS.has(value);
91081
+ if (typeof value === "object") {
91082
+ const code = Number(value.error ?? value.code ?? value.errorCode);
91083
+ if (STALE_TOKEN_ERRORS.has(code)) return true;
91084
+ const text3 = String(value.errorDescription || value.errorSummary || value.message || "");
91085
+ return /clos(?:e|ing) (?:and|then) re-?open|invalid document|invalid token|stale token|re-?open your browser/i.test(
91086
+ text3
91087
+ );
91088
+ }
91089
+ return false;
91090
+ }
91091
+ var LS_DOC_TOKEN_ERRORS = STALE_TOKEN_ERRORS;
91092
+ async function withCometTokens(ctx, defaultFuncs, run, options = {}) {
91093
+ const retries = Math.max(1, options.retries ?? 2);
91094
+ let last2;
91095
+ for (let attempt = 0; attempt < retries; attempt++) {
91096
+ await ensureCometTokens(ctx, defaultFuncs, attempt > 0);
91097
+ last2 = await run();
91098
+ if (!isStaleTokenError(last2)) return last2;
91099
+ invalidateCometTokens(ctx);
91100
+ }
91101
+ return last2;
91102
+ }
91103
+
91104
+ // src/utils/session.ts
91105
+ init_safety();
91106
+ var SESSION_COOKIE_NAMES = /* @__PURE__ */ new Set([
91107
+ "c_user",
91108
+ "xs",
91109
+ "fr",
91110
+ "datr",
91111
+ "sb",
91112
+ "presence",
91113
+ "wd",
91114
+ "dpr",
91115
+ "locale"
91116
+ ]);
91117
+ var AUTH_ERROR_CODES = /* @__PURE__ */ new Set([
91118
+ 1357001,
91119
+ // "Facebook blocked the login"
91120
+ 1357002,
91121
+ // not logged in
91122
+ 1357031,
91123
+ // document token invalid (treated as auth-adjacent here)
91124
+ 1357046,
91125
+ 1357036
91126
+ ]);
91127
+ function isCookieJar(jar2) {
91128
+ return Boolean(jar2) && typeof jar2.getCookiesSync === "function";
91129
+ }
91130
+ function extractCookiesFromJar(jar2) {
91131
+ const out = {};
91132
+ if (!isCookieJar(jar2)) return out;
91133
+ const origins = [
91134
+ "https://www.facebook.com",
91135
+ "https://facebook.com",
91136
+ "https://mbasic.facebook.com",
91137
+ "https://web.facebook.com",
91138
+ "https://www.messenger.com",
91139
+ "https://messenger.com"
91140
+ ];
91141
+ for (const origin2 of origins) {
91142
+ try {
91143
+ const cookies = jar2.getCookiesSync(origin2) || [];
91144
+ for (const cookie of cookies) {
91145
+ const key = cookie && (cookie.key || cookie.name);
91146
+ const value = cookie && cookie.value;
91147
+ if (!key || value == null) continue;
91148
+ if (!(key in out) || /facebook\.com$/.test(cookie.domain || "")) {
91149
+ out[key] = String(value);
91150
+ }
91151
+ }
91152
+ } catch {
91153
+ }
91154
+ }
91155
+ return out;
91156
+ }
91157
+ function extractCookiesFromSetCookie(header) {
91158
+ const out = {};
91159
+ if (!header) return out;
91160
+ const list = Array.isArray(header) ? header : [String(header)];
91161
+ for (const raw of list) {
91162
+ const parts = String(raw).split(/,(?=\s*[^=;,\s]+\s*=)/);
91163
+ for (const part of parts) {
91164
+ const firstSegment = part.split(";")[0].trim();
91165
+ const eq2 = firstSegment.indexOf("=");
91166
+ if (eq2 <= 0) continue;
91167
+ const name = firstSegment.slice(0, eq2).trim();
91168
+ const value = firstSegment.slice(eq2 + 1).trim();
91169
+ if (name) out[name] = value;
91170
+ }
91171
+ }
91172
+ return out;
91173
+ }
91174
+ function extractCookiesFromBody(body) {
91175
+ const out = {};
91176
+ if (body == null) return out;
91177
+ const text3 = typeof body === "string" ? body : JSON.stringify(body);
91178
+ if (!text3) return out;
91179
+ const re = /(?:document\.cookie\s*=\s*|setCookie\(\s*)["'\\]*([A-Za-z0-9_]+)=([^"';\s\\]+)/g;
91180
+ let match;
91181
+ while ((match = re.exec(text3)) !== null) {
91182
+ out[match[1]] = match[2];
91183
+ }
91184
+ return out;
91185
+ }
91186
+ function extractCookies(sources) {
91187
+ const merged = {};
91188
+ const seen = [];
91189
+ const fromJar = extractCookiesFromJar(sources.jar);
91190
+ if (Object.keys(fromJar).length) {
91191
+ Object.assign(merged, fromJar);
91192
+ seen.push("jar");
91193
+ }
91194
+ const fromHeader = extractCookiesFromSetCookie(sources.setCookie);
91195
+ if (Object.keys(fromHeader).length) {
91196
+ Object.assign(merged, fromHeader);
91197
+ seen.push("set-cookie");
91198
+ }
91199
+ const fromBody = extractCookiesFromBody(sources.body);
91200
+ if (Object.keys(fromBody).length) {
91201
+ Object.assign(merged, fromBody);
91202
+ seen.push("body");
91203
+ }
91204
+ return { cookies: merged, count: Object.keys(merged).length, sources: seen };
91205
+ }
91206
+ function applySetCookie(jar2, header) {
91207
+ if (!isCookieJar(jar2) || !header) return 0;
91208
+ const list = Array.isArray(header) ? header : [String(header)];
91209
+ let applied = 0;
91210
+ for (const raw of list) {
91211
+ if (!raw || typeof raw !== "string") continue;
91212
+ try {
91213
+ jar2.setCookieSync(raw, "https://www.facebook.com");
91214
+ applied++;
91215
+ } catch {
91216
+ try {
91217
+ const normalized = raw.replace(/domain=\.?facebook\.com/i, "Domain=.facebook.com").replace(/;\s*$/, "");
91218
+ jar2.setCookieSync(normalized, "https://www.facebook.com");
91219
+ applied++;
91220
+ } catch {
91221
+ }
91222
+ }
91223
+ if (/domain=\.?facebook\.com/i.test(raw)) {
91224
+ try {
91225
+ jar2.setCookieSync(raw.replace(/domain=\.?facebook\.com/i, "domain=.messenger.com"), "https://www.messenger.com");
91226
+ } catch {
90537
91227
  }
90538
91228
  }
91229
+ }
91230
+ return applied;
91231
+ }
91232
+ function hasAuthenticatedSession(jar2) {
91233
+ const cookies = extractCookiesFromJar(jar2);
91234
+ return Boolean(cookies.c_user && (cookies.xs || cookies.fr));
91235
+ }
91236
+ function collectSessionCookies(ctx, host) {
91237
+ const origins = /* @__PURE__ */ new Set([
91238
+ "https://www.facebook.com",
91239
+ "https://facebook.com",
91240
+ "https://web.facebook.com",
91241
+ "https://mbasic.facebook.com",
91242
+ "https://www.messenger.com",
91243
+ "https://messenger.com",
91244
+ "https://edge-chat.messenger.com",
91245
+ "https://gateway.facebook.com"
91246
+ ]);
91247
+ if (host) {
91248
+ try {
91249
+ origins.add(new URL(host).origin);
91250
+ } catch {
91251
+ }
91252
+ }
91253
+ const seen = {};
91254
+ const parts = [];
91255
+ for (const origin2 of origins) {
91256
+ let list = [];
91257
+ try {
91258
+ list = ctx?.jar?.getCookiesSync(origin2) || [];
91259
+ } catch {
91260
+ list = [];
91261
+ }
91262
+ for (const cookie of list) {
91263
+ const name = cookie?.key || cookie?.name;
91264
+ if (!name || seen[name]) continue;
91265
+ seen[name] = true;
91266
+ try {
91267
+ parts.push(cookie.cookieString ? cookie.cookieString() : `${name}=${cookie.value}`);
91268
+ } catch {
91269
+ parts.push(`${name}=${cookie.value}`);
91270
+ }
91271
+ }
91272
+ }
91273
+ return parts.join("; ");
91274
+ }
91275
+ function missingSessionCookies(jar2) {
91276
+ const cookies = extractCookiesFromJar(jar2);
91277
+ const missing = [];
91278
+ if (!cookies.c_user) missing.push("c_user");
91279
+ if (!cookies.xs) missing.push("xs");
91280
+ if (!cookies.fr) missing.push("fr");
91281
+ if (!cookies.datr) missing.push("datr");
91282
+ return missing;
91283
+ }
91284
+ function defaultFuncsGet(defaultFuncs, url2, jar2) {
91285
+ return defaultFuncs.get(url2, jar2);
91286
+ }
91287
+ async function refreshSessionCookies(ctx, defaultFuncs, options = {}) {
91288
+ const surfaces = options.surfaces || [
91289
+ "https://www.facebook.com/",
91290
+ "https://www.messenger.com/"
91291
+ ];
91292
+ let applied = 0;
91293
+ const errors = [];
91294
+ for (const url2 of surfaces) {
91295
+ try {
91296
+ const res = await defaultFuncsGet(defaultFuncs, url2, ctx.jar);
91297
+ const headers = res && res.headers || {};
91298
+ const setCookie = headers["set-cookie"] || headers["Set-Cookie"];
91299
+ applied += applySetCookie(ctx.jar, setCookie);
91300
+ const embedded = extractCookiesFromBody(res && (res.body ?? res));
91301
+ for (const [name, value] of Object.entries(embedded)) {
91302
+ try {
91303
+ ctx.jar.setCookieSync(`${name}=${value}; domain=.facebook.com; path=/; Secure; SameSite=None`, "https://www.facebook.com");
91304
+ applied++;
91305
+ } catch {
91306
+ }
91307
+ }
91308
+ if (typeof res?.body === "string" && res.body.includes("DTSGInitialData")) {
91309
+ invalidateCometTokens(ctx);
91310
+ }
91311
+ } catch (error2) {
91312
+ errors.push(`${url2}: ${error2 && (error2.message || error2.error || error2)}`);
91313
+ }
91314
+ }
91315
+ const extracted = extractCookies({ jar: ctx.jar });
91316
+ const authenticated = hasAuthenticatedSession(ctx.jar);
91317
+ if (applied > 0) ctx.__lastCookieRefreshAt = Date.now();
91318
+ return { ...extracted, applied, authenticated, errors };
91319
+ }
91320
+ function isAuthFailure(value) {
91321
+ if (value == null) return false;
91322
+ if (typeof value === "number") return AUTH_ERROR_CODES.has(value);
91323
+ if (typeof value === "object") {
91324
+ const code = Number(value.error ?? value.code ?? value.errorCode ?? value.statusCode);
91325
+ if (AUTH_ERROR_CODES.has(code)) return true;
91326
+ const text3 = String(value.error || value.message || value.errorDescription || "");
91327
+ return /not logged in|blocked the login|session (?:has )?expired|requires_reauth|please log in again/i.test(text3);
91328
+ }
91329
+ return false;
91330
+ }
91331
+ async function withSessionRetry(ctx, defaultFuncs, operation, options = {}) {
91332
+ const attempts = Math.max(1, options.attempts ?? 2);
91333
+ let lastError;
91334
+ for (let i2 = 0; i2 < attempts; i2++) {
91335
+ try {
91336
+ const result = await operation();
91337
+ if (isAuthFailure(result)) {
91338
+ lastError = result;
91339
+ noteAuthFailure(ctx);
91340
+ if (i2 === attempts - 1) throw result;
91341
+ if (options.onRecover) options.onRecover({ attempt: i2 + 1, error: result });
91342
+ await repairSession(ctx, defaultFuncs);
91343
+ continue;
91344
+ }
91345
+ resetBreaker(ctx);
91346
+ return result;
91347
+ } catch (error2) {
91348
+ lastError = error2;
91349
+ if (!isAuthFailure(error2) || i2 === attempts - 1) throw error2;
91350
+ noteAuthFailure(ctx);
91351
+ if (options.onRecover) options.onRecover({ attempt: i2 + 1, error: error2 });
91352
+ await repairSession(ctx, defaultFuncs);
91353
+ }
91354
+ }
91355
+ throw lastError || new Error("Operation failed after session retries.");
91356
+ }
91357
+ async function repairSession(ctx, defaultFuncs) {
91358
+ invalidateCometTokens(ctx);
91359
+ let ok = false;
91360
+ try {
91361
+ const refresh = await refreshSessionCookies(ctx, defaultFuncs);
91362
+ ok = refresh.authenticated;
90539
91363
  } catch {
91364
+ ok = false;
90540
91365
  }
91366
+ if (typeof ctx.__resetMqttBackoff === "function") {
91367
+ try {
91368
+ ctx.__resetMqttBackoff();
91369
+ } catch {
91370
+ }
91371
+ }
91372
+ return ok;
91373
+ }
91374
+ function scheduleSessionKeepAlive(ctx, defaultFuncs, intervalMs = 15 * 60 * 1e3) {
91375
+ if (ctx.__cookieKeepAliveTimer) {
91376
+ clearInterval(ctx.__cookieKeepAliveTimer);
91377
+ ctx.__cookieKeepAliveTimer = null;
91378
+ }
91379
+ const jitter = () => intervalMs * (0.85 + Math.random() * 0.3);
91380
+ let stopped = false;
91381
+ const tick = async () => {
91382
+ if (stopped || ctx.loggedIn === false) return;
91383
+ try {
91384
+ await refreshSessionCookies(ctx, defaultFuncs);
91385
+ } catch {
91386
+ } finally {
91387
+ if (!stopped) ctx.__cookieKeepAliveTimer = setTimeout(tick, jitter());
91388
+ }
91389
+ };
91390
+ ctx.__cookieKeepAliveTimer = setTimeout(tick, jitter());
91391
+ return () => {
91392
+ stopped = true;
91393
+ if (ctx.__cookieKeepAliveTimer) {
91394
+ clearTimeout(ctx.__cookieKeepAliveTimer);
91395
+ ctx.__cookieKeepAliveTimer = null;
91396
+ }
91397
+ };
91398
+ }
91399
+
91400
+ // src/utils/index.ts
91401
+ init_pacing();
91402
+
91403
+ // src/utils/warmup.ts
91404
+ init_pacing();
91405
+ var SURFACES = [
91406
+ "https://www.facebook.com/",
91407
+ "https://www.facebook.com/messages/t/",
91408
+ "https://www.messenger.com/"
91409
+ ];
91410
+ async function warmUpSession(ctx, getter, options = {}) {
91411
+ const visited = [];
91412
+ const errors = [];
91413
+ let cookiesApplied = 0;
91414
+ let tokensSeeded = false;
91415
+ if (!hasAuthenticatedSession(ctx.jar)) {
91416
+ return { visited, cookiesApplied, authenticated: false, tokensSeeded, errors: ["no authenticated session cookies"] };
91417
+ }
91418
+ const surfaces = options.includeMessenger === false ? SURFACES.slice(0, 2) : SURFACES;
91419
+ for (const url2 of surfaces) {
91420
+ try {
91421
+ const res = await getter(url2, ctx.jar, null, ctx.globalOptions, ctx, { noRef: true });
91422
+ visited.push(url2);
91423
+ const headers = res && res.headers || {};
91424
+ cookiesApplied += applySetCookie(ctx.jar, headers["set-cookie"] || headers["Set-Cookie"]);
91425
+ const html3 = typeof res === "string" ? res : res && res.body;
91426
+ if (typeof html3 === "string" && html3.includes("DTSGInitialData")) {
91427
+ const lsd = extractLsd(html3);
91428
+ const dtsg = extractDtsg(html3);
91429
+ if (lsd && dtsg) {
91430
+ ctx.__cometTokens = { lsd, fb_dtsg: dtsg, fetchedAt: Date.now(), failures: 0 };
91431
+ ctx.lsd = lsd;
91432
+ ctx.fb_dtsg = dtsg;
91433
+ ctx.jazoest = "2" + Array.from(dtsg).reduce((a, b) => a + b.charCodeAt(0), 0);
91434
+ const spin = extractSpin(html3);
91435
+ if (Object.keys(spin).length) ctx.__spin = { ...ctx.__spin || {}, ...spin };
91436
+ if (spin.__rev) ctx.revision = spin.__rev;
91437
+ tokensSeeded = true;
91438
+ }
91439
+ } else if (url2.includes("/messages")) {
91440
+ invalidateCometTokens(ctx);
91441
+ }
91442
+ await sleep(humanDelay(650, 420));
91443
+ } catch (error2) {
91444
+ errors.push(`${url2}: ${error2 && (error2.message || error2.error || error2)}`);
91445
+ }
91446
+ }
91447
+ const extracted = extractCookies({ jar: ctx.jar });
91448
+ return {
91449
+ visited,
91450
+ cookiesApplied,
91451
+ authenticated: hasAuthenticatedSession(ctx.jar),
91452
+ tokensSeeded,
91453
+ errors: [...errors, ...extracted.count ? [] : ["no cookies extracted"]]
91454
+ };
91455
+ }
91456
+
91457
+ // src/utils/index.ts
91458
+ init_safety();
91459
+
91460
+ // src/utils/liveness.ts
91461
+ init_pacing();
91462
+ init_safety();
91463
+ var ACTIVE_MIN_MS = 6 * 60 * 1e3;
91464
+ var ACTIVE_MAX_MS = 14 * 60 * 1e3;
91465
+ var IDLE_MIN_MS = 2 * 60 * 1e3;
91466
+ var IDLE_MAX_MS = 7 * 60 * 1e3;
91467
+ function randBetween(min, max) {
91468
+ return Math.floor(min + Math.random() * (max - min));
91469
+ }
91470
+ function startLiveness(ctx, options = {}) {
91471
+ if (ctx.__livenessStop) {
91472
+ try {
91473
+ ctx.__livenessStop();
91474
+ } catch {
91475
+ }
91476
+ }
91477
+ ctx.__requestsPaced = ctx.__requestsPaced || 0;
91478
+ let stopped = false;
91479
+ let active = true;
91480
+ let nextAt = Date.now() + randBetween(ACTIVE_MIN_MS, ACTIVE_MAX_MS);
91481
+ let timer = null;
91482
+ ctx.__foreground = true;
91483
+ const schedule = () => {
91484
+ if (stopped) return;
91485
+ const wait = Math.max(1e3, nextAt - Date.now());
91486
+ timer = setTimeout(tick, wait);
91487
+ if (timer && typeof timer.unref === "function") timer.unref();
91488
+ };
91489
+ const tick = () => {
91490
+ if (stopped) return;
91491
+ active = !active;
91492
+ ctx.__foreground = active ? !!ctx.globalOptions?.online : false;
91493
+ try {
91494
+ if (active) options.foregroundPing?.();
91495
+ else options.backgroundPing?.();
91496
+ } catch {
91497
+ }
91498
+ nextAt = Date.now() + (active ? randBetween(ACTIVE_MIN_MS, ACTIVE_MAX_MS) : randBetween(IDLE_MIN_MS, IDLE_MAX_MS));
91499
+ schedule();
91500
+ };
91501
+ schedule();
91502
+ const stop = () => {
91503
+ stopped = true;
91504
+ if (timer) {
91505
+ clearTimeout(timer);
91506
+ timer = null;
91507
+ }
91508
+ ctx.__livenessStop = null;
91509
+ };
91510
+ ctx.__livenessStop = stop;
91511
+ return {
91512
+ stop,
91513
+ state: () => ({
91514
+ active,
91515
+ nextTransitionMs: Math.max(0, nextAt - Date.now()),
91516
+ requests: ctx.__requestsPaced || 0,
91517
+ breakerOpen: isBreakerOpen(ctx)
91518
+ })
91519
+ };
91520
+ }
91521
+ function canActProactively(ctx) {
91522
+ if (isBreakerOpen(ctx)) return false;
91523
+ if (ctx.__foreground === false) return false;
91524
+ return true;
91525
+ }
91526
+ async function awaitProactiveSlot(ctx, maxWaitMs = 15 * 60 * 1e3) {
91527
+ const deadline = Date.now() + maxWaitMs;
91528
+ while (Date.now() < deadline) {
91529
+ if (canActProactively(ctx)) return true;
91530
+ await sleep(humanDelay(4e3, 3e3));
91531
+ }
91532
+ return false;
90541
91533
  }
90542
91534
 
90543
91535
  // src/utils/index.ts
@@ -90569,19 +91561,32 @@ async function json2(url2, jar2, qs2, options, ctx, customHeader) {
90569
91561
  }
90570
91562
  }
90571
91563
  function makeDefaults(html3, userID, ctx) {
90572
- let reqCounter = 1;
90573
91564
  const revision = getFrom(html3, 'revision":', ",");
90574
91565
  function mergeWithDefaults(obj) {
91566
+ const reqId = (() => {
91567
+ ctx.__reqCounter = (typeof ctx.__reqCounter === "number" ? ctx.__reqCounter : 0) + 1;
91568
+ return ctx.__reqCounter.toString(36);
91569
+ })();
91570
+ const spin = ctx.__spin || {};
90575
91571
  const newObj = {
90576
91572
  av: userID,
90577
91573
  __user: userID,
90578
- __req: (reqCounter++).toString(36),
90579
- __rev: revision,
91574
+ __req: reqId,
91575
+ __rev: ctx.revision || revision,
90580
91576
  __a: 1,
90581
91577
  ...ctx && {
90582
91578
  fb_dtsg: ctx.fb_dtsg,
90583
91579
  jazoest: ctx.jazoest
90584
- }
91580
+ },
91581
+ // The Comet document token and its spin siblings gate GraphQL; include
91582
+ // them whenever they are known so no module has to remember.
91583
+ ...ctx && ctx.lsd ? { lsd: ctx.lsd } : {},
91584
+ ...spin.__spin_b ? { __spin_b: spin.__spin_b } : {},
91585
+ ...spin.__spin_r ? { __spin_r: spin.__spin_r } : {},
91586
+ ...spin.__spin_t ? { __spin_t: spin.__spin_t } : {},
91587
+ // Device pixel ratio must match the Client Hints profile the headers
91588
+ // advertise, otherwise the form and the headers disagree.
91589
+ ...getFingerprintParams(ctx?.globalOptions)
90585
91590
  };
90586
91591
  if (!obj) return newObj;
90587
91592
  for (const prop2 in obj) {
@@ -90592,13 +91597,18 @@ function makeDefaults(html3, userID, ctx) {
90592
91597
  return newObj;
90593
91598
  }
90594
91599
  return {
90595
- get: (url2, jar2, qs2, ctxx, customHeader = {}) => get(url2, jar2, mergeWithDefaults(qs2), ctx.globalOptions, ctxx || ctx, customHeader),
91600
+ // GET carries only caller-supplied query parameters. The shared form
91601
+ // defaults (av/__user/fb_dtsg/jazoest/lsd/…) are a POST body and must never
91602
+ // be appended to a document URL: Facebook treats a document GET that
91603
+ // carries form state as an AJAX call and answers with a 1357004 JSON error
91604
+ // instead of the page, which is exactly the "stale token" symptom.
91605
+ get: (url2, jar2, qs2, ctxx, customHeader = {}) => get(url2, jar2, qs2, ctx.globalOptions, ctxx || ctx, customHeader),
90596
91606
  post: (url2, jar2, form, ctxx, customHeader = {}) => post(url2, jar2, mergeWithDefaults(form), ctx.globalOptions, ctxx || ctx, customHeader),
90597
91607
  postFormData: (url2, jar2, form, qs2, ctxx, customHeader) => postFormData(
90598
91608
  url2,
90599
91609
  jar2,
90600
91610
  mergeWithDefaults(form),
90601
- mergeWithDefaults(qs2),
91611
+ qs2,
90602
91612
  ctx.globalOptions,
90603
91613
  ctxx || ctx,
90604
91614
  customHeader
@@ -90622,7 +91632,19 @@ async function setOptions(globalOptions, options = {}) {
90622
91632
  listenEvents: (value) => globalOptions.listenEvents = Boolean(value),
90623
91633
  updatePresence: (value) => globalOptions.updatePresence = Boolean(value),
90624
91634
  forceLogin: (value) => globalOptions.forceLogin = Boolean(value),
90625
- userAgent: (value) => globalOptions.userAgent = value,
91635
+ userAgent: (value) => {
91636
+ globalOptions.userAgent = value;
91637
+ globalOptions.browser = normalizeBrowserProfile({
91638
+ ...globalOptions.browser || defaultBrowserProfile,
91639
+ userAgent: value
91640
+ });
91641
+ },
91642
+ browser: (value) => {
91643
+ if (!value || typeof value !== "object") return;
91644
+ const profile = normalizeBrowserProfile(value);
91645
+ globalOptions.browser = profile;
91646
+ globalOptions.userAgent = profile.userAgent;
91647
+ },
90626
91648
  autoMarkDelivery: (value) => globalOptions.autoMarkDelivery = Boolean(value),
90627
91649
  autoMarkRead: (value) => globalOptions.autoMarkRead = Boolean(value),
90628
91650
  listenTyping: (value) => globalOptions.listenTyping = Boolean(value),
@@ -90640,8 +91662,9 @@ async function setOptions(globalOptions, options = {}) {
90640
91662
  randomUserAgent(value) {
90641
91663
  globalOptions.randomUserAgent = Boolean(value);
90642
91664
  if (value) {
90643
- const ua = randomUserAgent();
90644
- globalOptions.userAgent = ua.userAgent;
91665
+ const profile = randomUserAgent();
91666
+ globalOptions.browser = profile;
91667
+ globalOptions.userAgent = profile.userAgent;
90645
91668
  }
90646
91669
  },
90647
91670
  bypassRegion(value) {
@@ -90659,7 +91682,20 @@ async function setOptions(globalOptions, options = {}) {
90659
91682
  // src/core/models/buildAPI.ts
90660
91683
  async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRetrievingMsg) {
90661
91684
  const userID = (() => {
90662
- const cookies = jar2.getCookiesSync(fbLinkFunc());
91685
+ const origins = [
91686
+ "https://www.facebook.com",
91687
+ "https://facebook.com",
91688
+ "https://web.facebook.com",
91689
+ "https://mbasic.facebook.com",
91690
+ "https://www.messenger.com"
91691
+ ];
91692
+ let cookies = [];
91693
+ for (const origin2 of origins) {
91694
+ try {
91695
+ cookies = cookies.concat(jar2.getCookiesSync(origin2) || []);
91696
+ } catch {
91697
+ }
91698
+ }
90663
91699
  const primaryProfile = cookies.find(
90664
91700
  (val2) => val2.cookieString().startsWith("c_user=")
90665
91701
  );
@@ -90667,6 +91703,13 @@ async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRe
90667
91703
  (val2) => val2.cookieString().startsWith("i_user=")
90668
91704
  );
90669
91705
  if (!primaryProfile && !secondaryProfile) {
91706
+ const hasXs = cookies.some((val2) => val2.cookieString().startsWith("xs="));
91707
+ const hasDatr = cookies.some((val2) => val2.cookieString().startsWith("datr="));
91708
+ if (hasXs || hasDatr) {
91709
+ throw new Error(
91710
+ "Facebook session expired or invalid (cookies present but no c_user). Export a fresh appState from a logged-in browser and try again."
91711
+ );
91712
+ }
90670
91713
  throw new Error(errorRetrievingMsg);
90671
91714
  }
90672
91715
  return secondaryProfile?.cookieString().split("=")[1] || primaryProfile.cookieString().split("=")[1];
@@ -90691,7 +91734,7 @@ async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRe
90691
91734
  return null;
90692
91735
  };
90693
91736
  const dtsgData = findConfig("DTSGInitialData");
90694
- const dtsg = dtsgData ? dtsgData.token : getFrom(html3, '"token":"', '"');
91737
+ const dtsg = dtsgData ? dtsgData.token : extractDtsg(html3) || getFrom(html3, '"token":"', '"');
90695
91738
  if (typeof dtsg !== "string" || dtsg.length === 0) {
90696
91739
  throw new Error("Unable to retrieve Facebook form security token (fb_dtsg).");
90697
91740
  }
@@ -90702,6 +91745,10 @@ async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRe
90702
91745
  0
90703
91746
  )}`
90704
91747
  };
91748
+ const lsdConfig = findConfig("LSD");
91749
+ const lsd = lsdConfig && lsdConfig.token || extractLsd(html3) || void 0;
91750
+ const spin = extractSpin(html3);
91751
+ const revision = spin.__rev || getFrom(html3, 'revision":', ",").trim();
90705
91752
  const clientIDData = findConfig("MqttWebDeviceID");
90706
91753
  const clientID = clientIDData ? clientIDData.clientID : void 0;
90707
91754
  const mqttConfigData = findConfig("MqttWebConfig");
@@ -90740,8 +91787,14 @@ async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRe
90740
91787
  callback_Task: {},
90741
91788
  region,
90742
91789
  firstListen: true,
90743
- ...dtsgResult
91790
+ ...dtsgResult,
91791
+ ...lsd ? { lsd } : {},
91792
+ ...Object.keys(spin).length ? { __spin: spin } : {},
91793
+ ...revision ? { revision } : {}
90744
91794
  };
91795
+ if (lsd && dtsg) {
91796
+ ctx.__cometTokens = { lsd, fb_dtsg: dtsg, fetchedAt: Date.now(), failures: 0 };
91797
+ }
90745
91798
  const defaultFuncs = makeDefaults(html3, userID, ctx);
90746
91799
  return [ctx, defaultFuncs, {}];
90747
91800
  }
@@ -91015,29 +92068,78 @@ var getBotInitialData_default = (defaultFuncs, api, ctx) => {
91015
92068
  };
91016
92069
  }
91017
92070
  log("Fetching account info...");
91018
- api.httpGet(`https://www.facebook.com/profile.php?id=${ctx.userID}`, null, {
91019
- customUserAgent: windowsUserAgent
91020
- }, (err, data2) => {
91021
- if (err) return callback(err);
91022
- try {
91023
- const profileMatch = data2.match(/"CurrentUserInitialData",\[\],\{(.*?)\},(.*?)\]/);
91024
- if (profileMatch && profileMatch[1]) {
91025
- const accountJson = JSON.parse(`{${profileMatch[1]}}`);
91026
- accountJson.name = accountJson.NAME;
91027
- accountJson.uid = accountJson.USER_ID;
91028
- delete accountJson.NAME;
91029
- delete accountJson.USER_ID;
92071
+ const locale = (ctx.globalOptions?.browser?.language || "en-US").replace("-", "_");
92072
+ const url2 = `https://www.facebook.com/profile.php?id=${ctx.userID}&sk=about&locale=${locale}`;
92073
+ api.httpGet(
92074
+ url2,
92075
+ null,
92076
+ {},
92077
+ (err, data2) => {
92078
+ if (err) return callback(err);
92079
+ try {
92080
+ const accountJson = extractCurrentUser(data2);
92081
+ if (accountJson) {
92082
+ return callback(null, {
92083
+ ...accountJson,
92084
+ name: accountJson.NAME ?? accountJson.name,
92085
+ uid: accountJson.USER_ID ?? accountJson.userID ?? ctx.userID
92086
+ });
92087
+ }
91030
92088
  return callback(null, {
91031
- ...accountJson
92089
+ error: "Something went wrong. Maybe its possible that it has a limitation due to spam requests. You can try again later."
91032
92090
  });
91033
- } 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." });
91034
- } catch (e) {
91035
- return callback(e);
91036
- }
91037
- }, true);
92091
+ } catch (e) {
92092
+ return callback(e);
92093
+ }
92094
+ },
92095
+ true
92096
+ );
91038
92097
  return returnPromise;
91039
92098
  };
91040
92099
  };
92100
+ function extractCurrentUser(html3) {
92101
+ if (typeof html3 !== "string") return null;
92102
+ const marker = '"CurrentUserInitialData",[],';
92103
+ const markerIndex = html3.indexOf(marker);
92104
+ const anchor = markerIndex >= 0 ? markerIndex + marker.length : html3.indexOf('"CurrentUserInitialData"');
92105
+ if (anchor < 0) return null;
92106
+ const start = html3.indexOf("{", anchor);
92107
+ if (start < 0) return null;
92108
+ let depth = 0;
92109
+ let inString = false;
92110
+ let escaped = false;
92111
+ for (let i2 = start; i2 < html3.length; i2++) {
92112
+ const ch = html3[i2];
92113
+ if (inString) {
92114
+ if (escaped) {
92115
+ escaped = false;
92116
+ } else if (ch === "\\") {
92117
+ escaped = true;
92118
+ } else if (ch === '"') {
92119
+ inString = false;
92120
+ }
92121
+ continue;
92122
+ }
92123
+ if (ch === '"') {
92124
+ inString = true;
92125
+ } else if (ch === "{") {
92126
+ depth++;
92127
+ } else if (ch === "}") {
92128
+ depth--;
92129
+ if (depth === 0) {
92130
+ try {
92131
+ const parsed = JSON.parse(html3.slice(start, i2 + 1));
92132
+ parsed.name = parsed.NAME;
92133
+ parsed.uid = parsed.USER_ID;
92134
+ return parsed;
92135
+ } catch {
92136
+ return null;
92137
+ }
92138
+ }
92139
+ }
92140
+ }
92141
+ return null;
92142
+ }
91041
92143
 
91042
92144
  // src/deltas/apis/login/logout.ts
91043
92145
  function logout_default(defaultFuncs, api, ctx) {
@@ -91047,6 +92149,13 @@ function logout_default(defaultFuncs, api, ctx) {
91047
92149
  if (ctx.globalOptions) {
91048
92150
  ctx.globalOptions.autoReconnect = false;
91049
92151
  }
92152
+ if (typeof ctx.__stopCookieKeepAlive === "function") {
92153
+ try {
92154
+ ctx.__stopCookieKeepAlive();
92155
+ } catch {
92156
+ }
92157
+ ctx.__stopCookieKeepAlive = null;
92158
+ }
91050
92159
  if (ctx.presenceInterval) {
91051
92160
  clearInterval(ctx.presenceInterval);
91052
92161
  ctx.presenceInterval = null;
@@ -93156,6 +94265,10 @@ function collectTracks(payload) {
93156
94265
  }
93157
94266
 
93158
94267
  // src/deltas/apis/music/searchMusic.ts
94268
+ function nextRequestId(ctx) {
94269
+ ctx.__reqCounter = (typeof ctx.__reqCounter === "number" ? ctx.__reqCounter : 0) + 1;
94270
+ return ctx.__reqCounter.toString(36);
94271
+ }
93159
94272
  function normalizeError(error2) {
93160
94273
  if (!error2 || typeof error2 !== "object") {
93161
94274
  const message2 = String(error2);
@@ -93177,32 +94290,53 @@ function normalizeError(error2) {
93177
94290
  }
93178
94291
  function searchMusic_default(defaultFuncs, _api, ctx) {
93179
94292
  async function runSearch(text3, count, selectedOptions, callback) {
93180
- await ensureCometTokens(ctx, defaultFuncs);
93181
94293
  const params = { first: count };
93182
94294
  if (text3) params.search_text = text3;
93183
94295
  if (selectedOptions.cursor) params.after = String(selectedOptions.cursor);
93184
- const form = {
93185
- av: ctx.userID,
93186
- __user: ctx.userID,
93187
- __a: "1",
93188
- __req: Math.floor(Math.random() * 1296).toString(36),
93189
- fb_api_caller_class: "RelayModern",
93190
- fb_api_req_friendly_name: SEARCH_FRIENDLY_NAME,
93191
- doc_id: SEARCH_DOC_ID,
93192
- variables: JSON.stringify({
93193
- params,
93194
- product: selectedOptions.product || PRODUCT
93195
- }),
93196
- server_timestamps: "true"
93197
- };
93198
- if (ctx.fb_dtsg) form.fb_dtsg = ctx.fb_dtsg;
93199
- if (ctx.jazoest) form.jazoest = ctx.jazoest;
93200
- if (ctx.lsd) form.lsd = ctx.lsd;
93201
- const customHeader = {};
93202
- if (ctx.lsd) customHeader["X-Fb-Lsd"] = ctx.lsd;
93203
- customHeader["X-Fb-Friendly-Name"] = SEARCH_FRIENDLY_NAME;
93204
- const parsed = await defaultFuncs.post(GRAPHQL_URL, ctx.jar, form, {}, ctx, customHeader).then(parseAndCheckLogin(ctx, defaultFuncs));
94296
+ const attempt = async (forceRefresh) => {
94297
+ await ensureCometTokens(ctx, defaultFuncs, forceRefresh);
94298
+ const form = {
94299
+ av: ctx.userID,
94300
+ __user: ctx.userID,
94301
+ __a: "1",
94302
+ __req: nextRequestId(ctx),
94303
+ fb_api_caller_class: "RelayModern",
94304
+ fb_api_req_friendly_name: SEARCH_FRIENDLY_NAME,
94305
+ doc_id: SEARCH_DOC_ID,
94306
+ variables: JSON.stringify({
94307
+ params,
94308
+ product: selectedOptions.product || PRODUCT
94309
+ }),
94310
+ server_timestamps: "true"
94311
+ };
94312
+ if (ctx.fb_dtsg) form.fb_dtsg = ctx.fb_dtsg;
94313
+ if (ctx.jazoest) form.jazoest = ctx.jazoest;
94314
+ if (ctx.lsd) form.lsd = ctx.lsd;
94315
+ const spin = ctx.__spin || {};
94316
+ if (spin.__spin_b) form.__spin_b = spin.__spin_b;
94317
+ if (spin.__spin_r) form.__spin_r = spin.__spin_r;
94318
+ if (spin.__spin_t) form.__spin_t = spin.__spin_t;
94319
+ if (ctx.revision) form.__rev = ctx.revision;
94320
+ const customHeader = {};
94321
+ if (ctx.lsd) customHeader["X-Fb-Lsd"] = ctx.lsd;
94322
+ customHeader["X-Fb-Friendly-Name"] = SEARCH_FRIENDLY_NAME;
94323
+ const raw = await defaultFuncs.post(GRAPHQL_URL, ctx.jar, form, ctx, customHeader).then(parseAndCheckLogin(ctx, defaultFuncs));
94324
+ return raw;
94325
+ };
94326
+ let parsed = await attempt(false);
94327
+ if (isStaleTokenError(parsed)) {
94328
+ invalidateCometTokens(ctx);
94329
+ parsed = await attempt(true);
94330
+ }
93205
94331
  if (!parsed) throw { error: "searchMusic returned empty object.", code: "BAD_RESPONSE" };
94332
+ if (isStaleTokenError(parsed)) {
94333
+ throw {
94334
+ error: parsed.error,
94335
+ errorSummary: parsed.errorSummary,
94336
+ errorDescription: parsed.errorDescription,
94337
+ code: "STALE_TOKEN"
94338
+ };
94339
+ }
93206
94340
  if (parsed.error) {
93207
94341
  throw {
93208
94342
  error: parsed.error,
@@ -93224,6 +94358,20 @@ function searchMusic_default(defaultFuncs, _api, ctx) {
93224
94358
  const page = collectTracks(parsed);
93225
94359
  const tracks = page.tracks.slice(0, count);
93226
94360
  if (tracks.length === 0) {
94361
+ invalidateCometTokens(ctx);
94362
+ const retried = await attempt(true);
94363
+ if (!isStaleTokenError(retried) && !retried.error && !(retried.errors || []).length) {
94364
+ const retryPage = collectTracks(retried);
94365
+ const retryTracks = retryPage.tracks.slice(0, count);
94366
+ if (retryTracks.length) {
94367
+ const result2 = retryTracks.slice();
94368
+ result2.tracks = retryTracks;
94369
+ result2.endCursor = retryPage.endCursor;
94370
+ result2.hasNextPage = retryPage.hasNextPage;
94371
+ result2.query = text3;
94372
+ return result2;
94373
+ }
94374
+ }
93227
94375
  throw {
93228
94376
  error: `No music results found for "${text3}". The Facebook music catalog may be unavailable for this account or region.`,
93229
94377
  code: "NO_RESULTS",
@@ -93507,8 +94655,9 @@ function connectLightspeed(ctx, globalCallback) {
93507
94655
  const chatOn = ctx.globalOptions.online;
93508
94656
  const foreground = false;
93509
94657
  const sessionID = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1;
93510
- const cookies = ctx.jar.getCookiesSync("https://www.facebook.com").join("; ");
94658
+ const cookies = collectSessionCookies(ctx, "https://gateway.facebook.com");
93511
94659
  const cid = ctx.clientID;
94660
+ const appId = ctx.mqttAppID || ctx.appID || "2220391788200892";
93512
94661
  const username = {
93513
94662
  u: ctx.userID,
93514
94663
  s: sessionID,
@@ -93516,7 +94665,7 @@ function connectLightspeed(ctx, globalCallback) {
93516
94665
  fg: foreground,
93517
94666
  d: cid,
93518
94667
  ct: "websocket",
93519
- aid: "2220391788200892",
94668
+ aid: appId,
93520
94669
  mqtt_sid: "",
93521
94670
  cp: 3,
93522
94671
  ecp: 10,
@@ -93526,10 +94675,12 @@ function connectLightspeed(ctx, globalCallback) {
93526
94675
  no_auto_fg: true,
93527
94676
  gas: null,
93528
94677
  pack: [],
93529
- a: ctx.globalOptions.userAgent
94678
+ a: ctx.globalOptions.userAgent || defaultBrowserProfile.userAgent,
94679
+ vi: "3",
94680
+ lc: "en_US"
93530
94681
  };
93531
94682
  const queryParams = new URLSearchParams({
93532
- "x-dgw-appid": "2220391788200892",
94683
+ "x-dgw-appid": appId,
93533
94684
  "x-dgw-appversion": "0",
93534
94685
  "x-dgw-authtype": "1:0",
93535
94686
  "x-dgw-version": "5",
@@ -93540,6 +94691,7 @@ function connectLightspeed(ctx, globalCallback) {
93540
94691
  "x-dgw-deviceid": ctx.clientID
93541
94692
  });
93542
94693
  const host = `wss://gateway.facebook.com/ws/lightspeed?${queryParams.toString()}`;
94694
+ const wsHeaders = getWebSocketHeaders(host, ctx.globalOptions);
93543
94695
  const options = {
93544
94696
  clientId: "mqttwsclient",
93545
94697
  protocolId: "MQIsdp",
@@ -93547,15 +94699,12 @@ function connectLightspeed(ctx, globalCallback) {
93547
94699
  username: JSON.stringify(username),
93548
94700
  clean: true,
93549
94701
  wsOptions: {
93550
- headers: {
93551
- "Cookie": cookies,
93552
- "Origin": "https://www.facebook.com",
93553
- "User-Agent": username.a,
93554
- "Referer": "https://www.facebook.com/",
93555
- "Host": new URL(host).hostname
93556
- }
94702
+ headers: { ...wsHeaders, Cookie: cookies },
94703
+ origin: wsHeaders.Origin,
94704
+ protocolVersion: 13,
94705
+ binaryType: "arraybuffer"
93557
94706
  },
93558
- keepalive: 10,
94707
+ keepalive: 10 + Math.floor(Math.random() * 10),
93559
94708
  reconnectPeriod: 0
93560
94709
  };
93561
94710
  if (ctx.globalOptions.proxy) {
@@ -93607,9 +94756,9 @@ function connectLightspeed(ctx, globalCallback) {
93607
94756
  }
93608
94757
  function reconnect(retryCount) {
93609
94758
  if (isStopped || reconnectTimer || ctx.loggedIn === false || ctx.globalOptions.autoReconnect === false) return;
93610
- const delay3 = Math.min(3e3 * Math.pow(2, retryCount), 6e4);
93611
- log(`[Lightspeed] Reconnecting in ${delay3 / 1e3} seconds...`);
93612
- reconnectTimer = setTimeout(() => startConnection(retryCount), delay3);
94759
+ const delay3 = retryDelay(retryCount, 4e3, 12e4);
94760
+ log(`[Lightspeed] Reconnecting in ${(delay3 / 1e3).toFixed(1)} seconds...`);
94761
+ reconnectTimer = setTimeout(() => startConnection(retryCount + 1), delay3);
93613
94762
  }
93614
94763
  startConnection();
93615
94764
  return {
@@ -98633,11 +99782,15 @@ function themeQuery_default(defaultFuncs, _api, ctx) {
98633
99782
  doc_id: "24474714052117636"
98634
99783
  };
98635
99784
  const referer = threadID ? `https://www.facebook.com/messages/t/${threadID}` : "https://www.facebook.com/messages";
98636
- const resData = await defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form, null, {
98637
- "x-fb-friendly-name": "MWPThreadThemeQuery_AllThemesQuery",
98638
- "x-fb-lsd": ctx.lsd,
98639
- referer
98640
- }).then(parseAndCheckLogin(ctx, defaultFuncs));
99785
+ const resData = await withCometTokens(
99786
+ ctx,
99787
+ defaultFuncs,
99788
+ () => defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form, null, {
99789
+ "x-fb-friendly-name": "MWPThreadThemeQuery_AllThemesQuery",
99790
+ "x-fb-lsd": ctx.lsd,
99791
+ referer
99792
+ }).then(parseAndCheckLogin(ctx, defaultFuncs))
99793
+ );
98641
99794
  if (resData?.errors) {
98642
99795
  throw new Error(JSON.stringify(resData.errors));
98643
99796
  }
@@ -98678,6 +99831,7 @@ function getHealthStatus_default(_defaultFuncs, _api, ctx) {
98678
99831
  return function getHealthStatus() {
98679
99832
  const mqtt3 = ctx.mqttClient;
98680
99833
  const connected = !!mqtt3 && (typeof mqtt3.connected === "boolean" ? mqtt3.connected : mqtt3.readyState === 1 || !!(mqtt3.stream && !mqtt3.stream.destroyed));
99834
+ const safety = typeof ctx.__safetySnapshot === "function" ? ctx.__safetySnapshot() : null;
98681
99835
  return {
98682
99836
  userID: ctx.userID || null,
98683
99837
  loggedIn: !!ctx.userID,
@@ -98688,8 +99842,13 @@ function getHealthStatus_default(_defaultFuncs, _api, ctx) {
98688
99842
  lastMessageAt: ctx.__mqttLastMessageAt || null
98689
99843
  },
98690
99844
  antiSuspension: {
98691
- enabled: false,
98692
- circuitBreakerOpen: false
99845
+ enabled: true,
99846
+ // The breaker is open when Facebook has signalled it is unhappy and
99847
+ // the session is deliberately pausing rather than risking a lockdown.
99848
+ circuitBreakerOpen: safety ? !safety.closed : false,
99849
+ reason: safety ? safety.reason : void 0,
99850
+ cooldownRemainingMs: safety ? safety.cooldownRemainingMs : 0,
99851
+ requestsInWindow: safety ? safety.requestsInWindow : 0
98693
99852
  },
98694
99853
  uptimeMs: typeof ctx.__startedAt === "number" ? Date.now() - ctx.__startedAt : null,
98695
99854
  timestamp: Date.now()
@@ -98750,7 +99909,6 @@ function getFriendsList_default(defaultFuncs, api, ctx) {
98750
99909
 
98751
99910
  // src/deltas/apis/mqtt/realtime.ts
98752
99911
  var import_undici = __toESM(require_undici());
98753
- var import_https_proxy_agent3 = __toESM(require_dist3());
98754
99912
  function formatNotification(data2) {
98755
99913
  if (!data2.data || !data2.data.viewer) return null;
98756
99914
  const notifEdge = data2.data.viewer.notifications_page?.edges?.[1]?.node?.notif;
@@ -98765,6 +99923,31 @@ function formatNotification(data2) {
98765
99923
  seenState: notifEdge.seen_state
98766
99924
  };
98767
99925
  }
99926
+ function collectRealtimeCookies(ctx) {
99927
+ const origins = [
99928
+ "https://www.facebook.com",
99929
+ "https://facebook.com",
99930
+ "https://www.messenger.com",
99931
+ "https://gateway.facebook.com"
99932
+ ];
99933
+ const seen = {};
99934
+ const parts = [];
99935
+ for (const origin2 of origins) {
99936
+ let list = [];
99937
+ try {
99938
+ list = ctx.jar.getCookiesSync(origin2) || [];
99939
+ } catch {
99940
+ list = [];
99941
+ }
99942
+ for (const cookie of list) {
99943
+ const name = cookie?.key;
99944
+ if (!name || seen[name]) continue;
99945
+ seen[name] = true;
99946
+ parts.push(cookie.cookieString());
99947
+ }
99948
+ }
99949
+ return parts.join("; ");
99950
+ }
98768
99951
  function realtime_default(defaultFuncs, api, ctx) {
98769
99952
  return function listenRealtime() {
98770
99953
  const emitter = new EventEmitter2();
@@ -98772,6 +99955,7 @@ function realtime_default(defaultFuncs, api, ctx) {
98772
99955
  let reconnectTimeout;
98773
99956
  let keepAliveInterval;
98774
99957
  let stopped = false;
99958
+ let retries = 0;
98775
99959
  const subscriptions = [
98776
99960
  '{"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"}',
98777
99961
  '{"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"}',
@@ -98823,8 +100007,9 @@ function realtime_default(defaultFuncs, api, ctx) {
98823
100007
  async function connect() {
98824
100008
  if (stopped) return;
98825
100009
  try {
100010
+ const appId = ctx.mqttAppID || ctx.appID || "2220391788200892";
98826
100011
  const queryParams = new URLSearchParams({
98827
- "x-dgw-appid": "2220391788200892",
100012
+ "x-dgw-appid": String(appId),
98828
100013
  "x-dgw-appversion": "0",
98829
100014
  "x-dgw-authtype": "1:0",
98830
100015
  "x-dgw-version": "5",
@@ -98834,23 +100019,22 @@ function realtime_default(defaultFuncs, api, ctx) {
98834
100019
  "x-dgw-app-stream-group": "group1"
98835
100020
  });
98836
100021
  const url2 = `wss://gateway.facebook.com/ws/realtime?${queryParams.toString()}`;
98837
- const cookies = ctx.jar.getCookiesSync("https://www.facebook.com").join("; ");
100022
+ const cookies = collectRealtimeCookies(ctx);
100023
+ const wsHeaders = getWebSocketHeaders(url2, ctx.globalOptions, ctx);
98838
100024
  const baseHeaders = {
98839
- "Cookie": cookies,
98840
- "Origin": "https://www.facebook.com",
98841
- "User-Agent": ctx.globalOptions.userAgent,
98842
- "Referer": "https://www.facebook.com",
98843
- "Host": new URL(url2).hostname,
98844
- "Accept-Encoding": "gzip, deflate, br",
98845
- "Accept-Language": "en-US,en;q=0.9"
100025
+ ...wsHeaders,
100026
+ "Referer": "https://www.facebook.com/friends",
100027
+ "Cookie": cookies
98846
100028
  };
98847
100029
  const wsOptions = { headers: baseHeaders };
98848
100030
  if (ctx.globalOptions.proxy) {
98849
- wsOptions.agent = new import_https_proxy_agent3.HttpsProxyAgent(ctx.globalOptions.proxy);
100031
+ const { ProxyAgent } = await Promise.resolve().then(() => __toESM(require_undici()));
100032
+ wsOptions.dispatcher = new ProxyAgent(ctx.globalOptions.proxy);
98850
100033
  }
98851
100034
  ws2 = new import_undici.WebSocket(url2, wsOptions);
98852
100035
  ws2.onopen = () => {
98853
100036
  log("Connected via undici.WebSocket");
100037
+ retries = 0;
98854
100038
  subscriptions.forEach((payload, index3) => {
98855
100039
  const prefix = Buffer.from([14, index3, 0, payload.length]);
98856
100040
  const suffix = Buffer.from([0, 0]);
@@ -98882,7 +100066,7 @@ function realtime_default(defaultFuncs, api, ctx) {
98882
100066
  clearInterval(keepAliveInterval);
98883
100067
  keepAliveInterval = void 0;
98884
100068
  clearTimeout(reconnectTimeout);
98885
- reconnectTimeout = setTimeout(connect, 1e3);
100069
+ reconnectTimeout = setTimeout(connect, retryDelay(++retries, 2e3, 6e4));
98886
100070
  };
98887
100071
  } catch (err) {
98888
100072
  if (stopped) return;
@@ -98890,7 +100074,7 @@ function realtime_default(defaultFuncs, api, ctx) {
98890
100074
  emitter.emit("error", err);
98891
100075
  clearInterval(keepAliveInterval);
98892
100076
  clearTimeout(reconnectTimeout);
98893
- reconnectTimeout = setTimeout(connect, 1e3);
100077
+ reconnectTimeout = setTimeout(connect, retryDelay(++retries, 2e3, 6e4));
98894
100078
  }
98895
100079
  }
98896
100080
  connect();
@@ -98909,7 +100093,7 @@ function realtime_default(defaultFuncs, api, ctx) {
98909
100093
  // src/deltas/apis/mqtt/listenMqtt.ts
98910
100094
  var import_mqtt2 = __toESM(require_mqtt2());
98911
100095
  var import_websocket_stream2 = __toESM(require_websocket_stream());
98912
- var import_https_proxy_agent4 = __toESM(require_dist3());
100096
+ var import_https_proxy_agent3 = __toESM(require_dist3());
98913
100097
 
98914
100098
  // src/deltas/apis/mqtt/deltas/value.ts
98915
100099
  function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
@@ -99133,9 +100317,15 @@ var MQTT_CONFIG = {
99133
100317
  },
99134
100318
  PROTOCOL_VERSION: 3,
99135
100319
  QOS_LEVEL: 1,
99136
- INITIAL_RETRY_DELAY: 2e3,
99137
- MAX_RETRY_DELAY: 6e4,
99138
- RETRY_MULTIPLIER: 1.6
100320
+ // A dropped socket deserves a quick retry; only a refused handshake
100321
+ // (explicit throttle) gets the long backoff. Both ramps are jittered.
100322
+ INITIAL_RETRY_DELAY: 4e3,
100323
+ MAX_RETRY_DELAY: 3e5,
100324
+ RETRY_MULTIPLIER: 2,
100325
+ // A refused handshake (connack returnCode != 0) means we are being
100326
+ // throttled, not that the network blipped: wait much longer before trying.
100327
+ THROTTLE_DELAY: 9e4,
100328
+ MAX_THROTTLE_DELAY: 9e5
99139
100329
  };
99140
100330
  var SYNC_CONFIG = {
99141
100331
  API_VERSION: 11,
@@ -99144,14 +100334,15 @@ var SYNC_CONFIG = {
99144
100334
  ENCODING: "JSON"
99145
100335
  };
99146
100336
  function buildMqttUsername(ctx, sessionID) {
100337
+ const profile = resolveProfile(ctx.globalOptions);
99147
100338
  return {
99148
100339
  u: ctx.userID,
99149
100340
  s: String(sessionID),
99150
- chat_on: ctx.globalOptions.online,
100341
+ chat_on: !!ctx.globalOptions.online,
99151
100342
  fg: false,
99152
100343
  d: ctx.clientID,
99153
100344
  ct: "websocket",
99154
- aid: ctx.mqttAppID || "218474845183941",
100345
+ aid: ctx.mqttAppID || ctx.appID || "2220391788200892",
99155
100346
  mqtt_sid: "",
99156
100347
  cp: 3,
99157
100348
  ecp: 10,
@@ -99161,13 +100352,14 @@ function buildMqttUsername(ctx, sessionID) {
99161
100352
  no_auto_fg: true,
99162
100353
  gas: null,
99163
100354
  pack: [],
99164
- a: ctx.globalOptions.userAgent,
100355
+ a: profile.userAgent,
99165
100356
  vi: "3",
99166
- lc: "en_US"
100357
+ lc: (profile.language || "en-US").replace("-", "_")
99167
100358
  };
99168
100359
  }
99169
100360
  function buildMqttOptions(ctx, host, username) {
99170
- const cookies = ctx.jar.getCookiesSync("https://www.facebook.com").join("; ");
100361
+ const cookies = collectSessionCookies(ctx, host);
100362
+ const wsHeaders = getWebSocketHeaders(host, ctx.globalOptions);
99171
100363
  const options = {
99172
100364
  clientId: "mqttwsclient",
99173
100365
  protocolId: "MQIsdp",
@@ -99175,14 +100367,8 @@ function buildMqttOptions(ctx, host, username) {
99175
100367
  username: JSON.stringify(username),
99176
100368
  clean: true,
99177
100369
  wsOptions: {
99178
- headers: {
99179
- "Cookie": cookies,
99180
- "Origin": "https://www.messenger.com",
99181
- "User-Agent": username.a,
99182
- "Referer": "https://www.messenger.com/",
99183
- "Host": new URL(host).hostname
99184
- },
99185
- origin: "https://www.messenger.com",
100370
+ headers: { ...wsHeaders, Cookie: cookies },
100371
+ origin: wsHeaders.Origin,
99186
100372
  protocolVersion: 13,
99187
100373
  binaryType: "arraybuffer"
99188
100374
  },
@@ -99192,7 +100378,7 @@ function buildMqttOptions(ctx, host, username) {
99192
100378
  reconnectPeriod: 0
99193
100379
  };
99194
100380
  if (ctx.globalOptions.proxy) {
99195
- options.wsOptions.agent = new import_https_proxy_agent4.HttpsProxyAgent(ctx.globalOptions.proxy);
100381
+ options.wsOptions.agent = new import_https_proxy_agent3.HttpsProxyAgent(ctx.globalOptions.proxy);
99196
100382
  }
99197
100383
  return options;
99198
100384
  }
@@ -99214,6 +100400,7 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99214
100400
  stopped: false,
99215
100401
  attempts: 0,
99216
100402
  delay: MQTT_CONFIG.INITIAL_RETRY_DELAY,
100403
+ throttleDelay: MQTT_CONFIG.THROTTLE_DELAY,
99217
100404
  generation: 0
99218
100405
  };
99219
100406
  const log2 = (...args) => log(...args);
@@ -99247,13 +100434,36 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99247
100434
  } catch (_3) {
99248
100435
  }
99249
100436
  }
99250
- function scheduleReconnect(reason) {
100437
+ function scheduleReconnect(reason, throttled = false) {
99251
100438
  if (lifecycle.stopped) return;
99252
100439
  if (ctx.loggedIn === false) return;
99253
100440
  if (ctx.globalOptions && ctx.globalOptions.autoReconnect === false) return;
100441
+ if (isBreakerOpen(ctx)) {
100442
+ const wait = Math.min(
100443
+ safetySnapshot(ctx).cooldownRemainingMs || MQTT_CONFIG.THROTTLE_DELAY,
100444
+ MQTT_CONFIG.MAX_THROTTLE_DELAY
100445
+ );
100446
+ clearReconnectTimer();
100447
+ lifecycle.reconnectTimer = setTimeout(() => {
100448
+ lifecycle.reconnectTimer = null;
100449
+ if (lifecycle.stopped || ctx.loggedIn === false) return;
100450
+ start();
100451
+ }, wait);
100452
+ log2(`MQTT ${reason}; safety breaker open, waiting ${(wait / 1e3).toFixed(1)}s`);
100453
+ return;
100454
+ }
99254
100455
  clearReconnectTimer();
99255
- const delay3 = Math.min(lifecycle.delay + getJitter(500), MQTT_CONFIG.MAX_RETRY_DELAY);
99256
- lifecycle.delay = Math.min(lifecycle.delay * MQTT_CONFIG.RETRY_MULTIPLIER, MQTT_CONFIG.MAX_RETRY_DELAY);
100456
+ let delay3;
100457
+ if (throttled) {
100458
+ delay3 = Math.min(lifecycle.throttleDelay + getJitter(8e3), MQTT_CONFIG.MAX_THROTTLE_DELAY);
100459
+ lifecycle.throttleDelay = Math.min(
100460
+ lifecycle.throttleDelay * MQTT_CONFIG.RETRY_MULTIPLIER,
100461
+ MQTT_CONFIG.MAX_THROTTLE_DELAY
100462
+ );
100463
+ } else {
100464
+ delay3 = Math.min(lifecycle.delay + getJitter(1500), MQTT_CONFIG.MAX_RETRY_DELAY);
100465
+ lifecycle.delay = Math.min(lifecycle.delay * MQTT_CONFIG.RETRY_MULTIPLIER, MQTT_CONFIG.MAX_RETRY_DELAY);
100466
+ }
99257
100467
  lifecycle.attempts++;
99258
100468
  log2(`MQTT ${reason}; reconnecting in ${(delay3 / 1e3).toFixed(1)}s (attempt ${lifecycle.attempts})`);
99259
100469
  lifecycle.reconnectTimer = setTimeout(() => {
@@ -99265,7 +100475,9 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99265
100475
  function resetBackoff() {
99266
100476
  lifecycle.attempts = 0;
99267
100477
  lifecycle.delay = MQTT_CONFIG.INITIAL_RETRY_DELAY;
100478
+ lifecycle.throttleDelay = MQTT_CONFIG.THROTTLE_DELAY;
99268
100479
  }
100480
+ ctx.__resetMqttBackoff = resetBackoff;
99269
100481
  async function fetchSeqId() {
99270
100482
  if (ctx.lastSeqId) return ctx.lastSeqId;
99271
100483
  const form = {
@@ -99332,9 +100544,18 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99332
100544
  ctx.mqttClient = client2;
99333
100545
  let connected = false;
99334
100546
  let closing = false;
100547
+ let throttled = false;
100548
+ let authFailure = false;
99335
100549
  client2.on("error", (err) => {
99336
100550
  ctx.lastMqttError = err;
99337
- error("listenMqtt", new NetworkError(`MQTT connection error: ${err?.message || err}`, { originalError: err, host }));
100551
+ const msg = String(err && err.message || err || "");
100552
+ if (/connection refused|not authorized|server unavailable|bad username|identifier rejected|unacceptable protocol/i.test(msg)) {
100553
+ throttled = true;
100554
+ }
100555
+ if (isAuthFailure && isAuthFailure(err)) {
100556
+ authFailure = true;
100557
+ }
100558
+ error("listenMqtt", new NetworkError(`MQTT connection error: ${msg}`, { originalError: err, host }));
99338
100559
  });
99339
100560
  client2.on("offline", () => {
99340
100561
  if (generation !== lifecycle.generation) return;
@@ -99348,7 +100569,17 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99348
100569
  ctx.mqttConnected = false;
99349
100570
  if (closing) return;
99350
100571
  closing = true;
99351
- scheduleReconnect("connection closed");
100572
+ if (authFailure) {
100573
+ noteAuthFailure(ctx);
100574
+ Promise.resolve().then(() => repairSession(ctx, defaultFuncs)).catch(() => {
100575
+ }).then(() => {
100576
+ if (generation !== lifecycle.generation) return;
100577
+ resetBackoff();
100578
+ scheduleReconnect("session repaired after auth error");
100579
+ });
100580
+ return;
100581
+ }
100582
+ scheduleReconnect(throttled ? "connection refused (throttled)" : "connection closed", throttled);
99352
100583
  });
99353
100584
  client2.on("connect", () => {
99354
100585
  if (generation !== lifecycle.generation) return;
@@ -99452,6 +100683,13 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99452
100683
  log2("Reconnecting MQTT...");
99453
100684
  clearTimers();
99454
100685
  destroyClient();
100686
+ try {
100687
+ const last2 = ctx.lastMqttError;
100688
+ if (last2 && isAuthFailure && isAuthFailure(last2)) {
100689
+ await repairSession(ctx, defaultFuncs);
100690
+ }
100691
+ } catch (_3) {
100692
+ }
99455
100693
  try {
99456
100694
  await ensureSeqId();
99457
100695
  } catch (err) {
@@ -99511,7 +100749,9 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99511
100749
  }
99512
100750
  }
99513
100751
  ctx.firstListen = false;
100752
+ let fetchedSeqId = false;
99514
100753
  try {
100754
+ fetchedSeqId = !ctx.lastSeqId;
99515
100755
  await ensureSeqId();
99516
100756
  } catch (err) {
99517
100757
  ctx.lastMqttError = err;
@@ -99519,6 +100759,7 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99519
100759
  scheduleReconnect("sequence id fetch failed");
99520
100760
  return;
99521
100761
  }
100762
+ if (fetchedSeqId) await sleep(humanDelay(700, 400));
99522
100763
  await start();
99523
100764
  })().catch((err) => {
99524
100765
  error("listenMqtt startup error:", err);
@@ -99650,7 +100891,7 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
99650
100891
  if (!name || c.value === void 0 || c.value === null) {
99651
100892
  throw new Error(`Invalid appState cookie at index ${index3}.`);
99652
100893
  }
99653
- return `${name}=${String(c.value)}`;
100894
+ return formatAppStateCookie(c);
99654
100895
  });
99655
100896
  } else if (typeof appState === "string") {
99656
100897
  cookieStrings = appState.split(";").map((s) => s.trim()).filter(Boolean);
@@ -99663,9 +100904,16 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
99663
100904
  if (cookieString.indexOf("=") <= 0) {
99664
100905
  throw new Error(`Invalid appState cookie at index ${index3}.`);
99665
100906
  }
99666
- const domain = ".facebook.com";
99667
- const str = `${cookieString}; domain=${domain}; path=/;`;
99668
- jar2.setCookie(str, "https://facebook.com");
100907
+ const normalized = cookieString.replace(/;\s*domain=facebook\.com/i, "; domain=.facebook.com").replace(/;\s*domain=messenger\.com/i, "; domain=.messenger.com");
100908
+ const str = /(^|;)\s*domain=/i.test(normalized) ? normalized : `${normalized}; domain=.facebook.com; path=/; Secure; SameSite=None`;
100909
+ try {
100910
+ jar2.setCookieSync(str, "https://facebook.com");
100911
+ } catch {
100912
+ try {
100913
+ jar2.setCookieSync(`${normalized}; domain=.facebook.com; path=/; Secure; SameSite=None`, "https://www.facebook.com");
100914
+ } catch {
100915
+ }
100916
+ }
99669
100917
  });
99670
100918
  } else if (credentials.email && credentials.password) {
99671
100919
  const url2 = "https://api.facebook.com/method/auth.login";
@@ -99682,15 +100930,25 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
99682
100930
  const query = qs.stringify(params);
99683
100931
  const xurl = `${url2}?${query}`;
99684
100932
  try {
99685
- const resp2 = await axios_default.get(xurl);
100933
+ const legacyHeaders = getHeaders(
100934
+ url2,
100935
+ globalOptions,
100936
+ null,
100937
+ { "Content-Type": "application/x-www-form-urlencoded" }
100938
+ );
100939
+ const resp2 = await axios_default.get(xurl, {
100940
+ headers: legacyHeaders,
100941
+ timeout: 6e4,
100942
+ validateStatus: (status) => status >= 200 && status < 600
100943
+ });
99686
100944
  if (resp2.status !== 200) {
99687
100945
  throw new Error("Wrong password / email");
99688
100946
  }
99689
100947
  const cstrs = resp2.data["session_cookies"].map((c) => `${c.name}=${c.value}`);
99690
100948
  cstrs.forEach((cstr) => {
99691
100949
  const domain = ".facebook.com";
99692
- const str = `${cstr}; domain=${domain}; path=/;`;
99693
- jar2.setCookie(str, "https://facebook.com");
100950
+ const str = `${cstr}; domain=${domain}; path=/; Secure; SameSite=None`;
100951
+ jar2.setCookieSync(str, "https://facebook.com");
99694
100952
  });
99695
100953
  } catch (e) {
99696
100954
  throw new Error("Wrong password / email");
@@ -99803,6 +101061,46 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
99803
101061
  api.ctx = ctx;
99804
101062
  api.defaultFuncs = defaultFuncs;
99805
101063
  api.globalOptions = globalOptions;
101064
+ api.extractCookies = () => extractCookies({ jar: jar2 });
101065
+ api.refreshSession = () => refreshSessionCookies(ctx, defaultFuncs);
101066
+ api.hasAuthenticatedSession = () => hasAuthenticatedSession(jar2);
101067
+ api.repairSession = () => repairSession(ctx, defaultFuncs);
101068
+ api.warmUpSession = () => warmUpSession(ctx, defaultFuncs.get);
101069
+ ctx.__startedAt = Date.now();
101070
+ ctx.__safetySnapshot = () => safetySnapshot(ctx);
101071
+ api.getSafetyStatus = () => safetySnapshot(ctx);
101072
+ api.pauseSession = (reason) => {
101073
+ tripBreaker(ctx, reason || "manual");
101074
+ return safetySnapshot(ctx);
101075
+ };
101076
+ api.resumeSession = () => {
101077
+ resetBreaker(ctx);
101078
+ return safetySnapshot(ctx);
101079
+ };
101080
+ ctx.__onSafetyTrip = (info2) => {
101081
+ warn(
101082
+ "Account safety",
101083
+ `pausing requests for ${Math.round((info2.cooldownMs || 0) / 1e3)}s (${info2.reason})`
101084
+ );
101085
+ };
101086
+ if (globalOptions.warmUp !== false) {
101087
+ try {
101088
+ await warmUpSession(ctx, defaultFuncs.get);
101089
+ } catch (warmUpError) {
101090
+ warn("Session warm-up skipped:", warmUpError?.message || warmUpError);
101091
+ }
101092
+ }
101093
+ ctx.__stopCookieKeepAlive = scheduleSessionKeepAlive(ctx, defaultFuncs, 15 * 60 * 1e3);
101094
+ if (globalOptions.liveness !== false) {
101095
+ const liveness = startLiveness(ctx, {
101096
+ foregroundPing: () => log("Session active"),
101097
+ backgroundPing: () => log("Session idle")
101098
+ });
101099
+ ctx.__livenessHandle = liveness;
101100
+ api.getLivenessState = () => liveness.state();
101101
+ api.canActProactively = () => canActProactively(ctx);
101102
+ api.awaitProactiveSlot = (maxWaitMs) => awaitProactiveSlot(ctx, maxWaitMs);
101103
+ }
99806
101104
  return callback(null, api);
99807
101105
  } catch (error2) {
99808
101106
  error("loginHelper", error2.error || error2);
@@ -99822,6 +101120,10 @@ async function login(credentials, options, callback) {
99822
101120
  if ("logging" in options) {
99823
101121
  logOptions(options.logging);
99824
101122
  }
101123
+ const browser = options.randomUserAgent ? randomUserAgent() : normalizeBrowserProfile({
101124
+ ...options.browser || defaultBrowserProfile,
101125
+ ...options.userAgent ? { userAgent: options.userAgent } : {}
101126
+ });
99825
101127
  const defaultOptions2 = {
99826
101128
  selfListen: false,
99827
101129
  listenEvents: false,
@@ -99833,7 +101135,8 @@ async function login(credentials, options, callback) {
99833
101135
  autoReconnect: true,
99834
101136
  online: false,
99835
101137
  emitReady: false,
99836
- 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",
101138
+ userAgent: browser.userAgent,
101139
+ browser,
99837
101140
  advancedProtection: false,
99838
101141
  autoRotateSession: false,
99839
101142
  randomUserAgent: false
@@ -99876,6 +101179,10 @@ async function login(credentials, options, callback) {
99876
101179
  var public_exports = {};
99877
101180
 
99878
101181
  // index.ts
101182
+ init_headers();
101183
+ init_user_agents();
101184
+ init_pacing();
101185
+ init_safety();
99879
101186
  var metaChat = Object.assign(login, {
99880
101187
  login,
99881
101188
  publicTypes: public_exports,
@@ -99966,4 +101273,4 @@ lodash/lodash.js:
99966
101273
  *)
99967
101274
  */
99968
101275
 
99969
- export { index_default as default, login, public_exports as publicTypes };
101276
+ export { applySetCookie, awaitProactiveSlot, canActProactively, collectSessionCookies, index_default as default, defaultBrowserProfile, ensureCometTokens, extractCookies, extractCookiesFromBody, extractCookiesFromJar, extractCookiesFromSetCookie, extractCurrentUser, getFingerprintParams, getHeaders, getWebSocketHeaders, hasAuthenticatedSession, humanDelay, invalidateCometTokens, isAuthFailure, isBreakerOpen, isStaleTokenError, login, missingSessionCookies, normalizeBrowserProfile, noteAction, noteAuthFailure, noteCheckpoint, noteRateLimit, paceRequest, public_exports as publicTypes, randomUserAgent, refreshSessionCookies, repairSession, reserveRequest, resetBreaker, resolveProfile, retryDelay, safetySnapshot, sleep, startLiveness, tripBreaker, warmUpSession, withCometTokens, withSessionRetry };