@lazyneoaz/metachat 4.0.4 → 4.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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,483 @@ 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 isEdgeChatHost(host) {
25017
+ return /(^|\.)edge-chat\.messenger\.com$/i.test(host) || /(^|\.)edge-chat\.facebook\.com$/i.test(host);
25018
+ }
25019
+ function isBusinessHost(host) {
25020
+ return /(^|\.)business\.facebook\.com$/i.test(host);
25021
+ }
25022
+ function isFacebookHost(host) {
25023
+ return /(^|\.)facebook\.com$/i.test(host);
25024
+ }
25025
+ function isGraphQlPath(pathname) {
25026
+ return /\/api\/graphql/i.test(pathname) || /graphqlbatch/i.test(pathname);
25027
+ }
25028
+ function resolveProfile(options) {
25029
+ const base = options?.browser || options?.browserProfile || defaultBrowserProfile;
25030
+ const merged = {
25031
+ ...base,
25032
+ userAgent: options?.userAgent || base.userAgent,
25033
+ secChUa: options?.secChUa || base.secChUa,
25034
+ secChUaFullVersionList: options?.secChUaFullVersionList || base.secChUaFullVersionList,
25035
+ secChUaPlatform: options?.secChUaPlatform || base.secChUaPlatform,
25036
+ secChUaPlatformVersion: options?.secChUaPlatformVersion || base.secChUaPlatformVersion,
25037
+ secChUaArch: options?.secChUaArch || base.secChUaArch,
25038
+ secChUaBitness: options?.secChUaBitness || base.secChUaBitness,
25039
+ secChUaWow64: options?.secChUaWow64 || base.secChUaWow64,
25040
+ secChUaFormFactors: options?.secChUaFormFactors || base.secChUaFormFactors,
25041
+ secChUaMobile: options?.secChUaMobile || base.secChUaMobile,
25042
+ acceptLanguage: options?.acceptLanguage || base.acceptLanguage
25043
+ };
25044
+ if (options?.userAgent && !options?.browser && !options?.browserProfile) {
25045
+ return normalizeBrowserProfile(merged);
25046
+ }
25047
+ return merged;
25048
+ }
25049
+ function shouldSendOrigin(method, isXhr) {
25050
+ const m = (method || "GET").toUpperCase();
25051
+ if (m === "GET" || m === "HEAD" || m === "OPTIONS") return false;
25052
+ return true;
25053
+ }
25054
+ function getHeaders(url2, options, ctx, customHeader) {
25055
+ const u = new URL(url2);
25056
+ const profile = resolveProfile(options);
25057
+ const method = String(options?.method || customHeader?.method || "GET").toUpperCase();
25058
+ const defaultReferer = isMessengerHost(u.hostname) ? "https://www.messenger.com/" : isBusinessHost(u.hostname) ? "https://business.facebook.com/" : "https://www.facebook.com/";
25059
+ const referer = options?.referer || defaultReferer;
25060
+ const origin2 = options?.origin || originOf(referer);
25061
+ const contentType = options?.contentType || (customHeader?.["Content-Type"] || customHeader?.["content-type"]) || "application/x-www-form-urlencoded";
25062
+ const isGraphQl = isGraphQlPath(u.pathname);
25063
+ const isXhr = isGraphQl || contentType.includes("json") || !!options?.xhr;
25064
+ const isDocument2 = !isXhr && (method === "GET" || method === "HEAD");
25065
+ const secFetchSite = (() => {
25066
+ if (isDocument2) return "none";
25067
+ let refererHost = referer;
25068
+ try {
25069
+ refererHost = new URL(referer).hostname;
25070
+ } catch {
25071
+ }
25072
+ if (isMessengerHost(u.hostname) && !isMessengerHost(refererHost)) return "same-site";
25073
+ if (isFacebookHost(u.hostname) && !isFacebookHost(refererHost)) return "cross-site";
25074
+ return "same-origin";
25075
+ })();
25076
+ 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";
25077
+ const headers = {
25078
+ Referer: sanitizeHeaderValue2(referer),
25079
+ "User-Agent": sanitizeHeaderValue2(profile.userAgent),
25080
+ Accept: accept,
25081
+ "Accept-Language": sanitizeHeaderValue2(profile.acceptLanguage),
25082
+ "Accept-Encoding": "gzip, deflate, br",
25083
+ Connection: "keep-alive",
25084
+ "Upgrade-Insecure-Requests": "1",
25085
+ "sec-ch-ua": sanitizeHeaderValue2(profile.secChUa),
25086
+ "sec-ch-ua-mobile": sanitizeHeaderValue2(profile.secChUaMobile),
25087
+ "sec-ch-ua-platform": sanitizeHeaderValue2(profile.secChUaPlatform),
25088
+ "sec-ch-ua-platform-version": sanitizeHeaderValue2(profile.secChUaPlatformVersion),
25089
+ "sec-ch-ua-arch": sanitizeHeaderValue2(profile.secChUaArch),
25090
+ "sec-ch-ua-bitness": sanitizeHeaderValue2(profile.secChUaBitness),
25091
+ "sec-ch-ua-model": sanitizeHeaderValue2(profile.secChUaModel),
25092
+ "sec-ch-ua-wow64": sanitizeHeaderValue2(profile.secChUaWow64),
25093
+ "sec-ch-ua-form-factors": sanitizeHeaderValue2(profile.secChUaFormFactors),
25094
+ "sec-ch-ua-full-version-list": sanitizeHeaderValue2(profile.secChUaFullVersionList),
25095
+ "Sec-Fetch-Site": secFetchSite,
25096
+ "Sec-Fetch-Mode": isXhr ? "cors" : "navigate",
25097
+ "Sec-Fetch-Dest": isXhr ? "empty" : "document"
25098
+ };
25099
+ if (method !== "GET" && method !== "HEAD") {
25100
+ headers["Content-Type"] = sanitizeHeaderValue2(contentType);
25101
+ }
25102
+ if (shouldSendOrigin(method)) {
25103
+ headers["Origin"] = sanitizeHeaderValue2(origin2);
25104
+ }
25105
+ if (isDocument2) {
25106
+ headers["Sec-Fetch-User"] = "?1";
25107
+ headers["priority"] = "u=0, i";
25108
+ }
25109
+ if (isXhr) {
25110
+ headers["X-Requested-With"] = "XMLHttpRequest";
25111
+ headers["Pragma"] = "no-cache";
25112
+ headers["Cache-Control"] = "no-cache";
25113
+ headers["priority"] = "u=1, i";
25114
+ }
25115
+ if (isGraphQl) {
25116
+ headers["x-asbd-id"] = "129477";
25117
+ const lsd = ctx?.lsd || ctx?.fb_lsd;
25118
+ if (lsd) headers["x-fb-lsd"] = sanitizeHeaderValue2(lsd);
25119
+ const friendlyName = customHeader?.["x-fb-friendly-name"] || customHeader?.["X-Fb-Friendly-Name"];
25120
+ if (friendlyName) headers["x-fb-friendly-name"] = sanitizeHeaderValue2(friendlyName);
25121
+ }
25122
+ if (ctx?.region && (isMessengerHost(u.hostname) || isEdgeChatHost(u.hostname))) {
25123
+ const regionValue = sanitizeHeaderValue2(ctx.region);
25124
+ if (regionValue) headers["X-MSGR-Region"] = regionValue;
25125
+ }
25126
+ if (customHeader && typeof customHeader === "object") {
25127
+ for (const [key, value] of Object.entries(customHeader)) {
25128
+ if (value === null || value === void 0 || typeof value === "function") continue;
25129
+ if (typeof value === "object") continue;
25130
+ const sanitizedKey = sanitizeHeaderName(key);
25131
+ let sanitizedValue = sanitizeHeaderValue2(value);
25132
+ if (!sanitizedKey || sanitizedValue === "") continue;
25133
+ if (sanitizedKey.toLowerCase() === "referer") {
25134
+ headers["Referer"] = sanitizedValue;
25135
+ if (!customHeader.origin && !customHeader.Origin && shouldSendOrigin(method)) {
25136
+ headers["Origin"] = originOf(sanitizedValue);
25137
+ }
25138
+ continue;
25139
+ }
25140
+ const existingKey = Object.keys(headers).find(
25141
+ (headerKey) => headerKey.toLowerCase() === sanitizedKey.toLowerCase()
25142
+ );
25143
+ headers[existingKey || sanitizedKey] = sanitizedValue;
25144
+ }
25145
+ }
25146
+ const sanitizedHeaders = {};
25147
+ for (const [key, value] of Object.entries(headers)) {
25148
+ if (value === void 0 || value === null) continue;
25149
+ const sanitizedKey = sanitizeHeaderName(key);
25150
+ const sanitizedValue = sanitizeHeaderValue2(value);
25151
+ if (sanitizedKey && sanitizedValue !== "") {
25152
+ sanitizedHeaders[sanitizedKey] = sanitizedValue;
25153
+ }
25154
+ }
25155
+ return sanitizedHeaders;
25156
+ }
25157
+ function getWebSocketHeaders(url2, options, ctx) {
25158
+ const profile = resolveProfile(options);
25159
+ const u = new URL(url2);
25160
+ const origin2 = isMessengerHost(u.hostname) ? "https://www.messenger.com" : isBusinessHost(u.hostname) ? "https://business.facebook.com" : "https://www.facebook.com";
25161
+ const referer = options?.referer || (origin2 === "https://www.messenger.com" ? "https://www.messenger.com/" : `${origin2}/`);
25162
+ return {
25163
+ Origin: origin2,
25164
+ Referer: referer,
25165
+ "User-Agent": profile.userAgent,
25166
+ "Accept-Language": profile.acceptLanguage,
25167
+ "Accept-Encoding": "gzip, deflate, br, zstd",
25168
+ "Cache-Control": "no-cache",
25169
+ Pragma: "no-cache",
25170
+ "sec-ch-ua": profile.secChUa,
25171
+ "sec-ch-ua-mobile": profile.secChUaMobile,
25172
+ "sec-ch-ua-platform": profile.secChUaPlatform,
25173
+ "sec-ch-ua-platform-version": profile.secChUaPlatformVersion,
25174
+ "sec-ch-ua-arch": profile.secChUaArch,
25175
+ "sec-ch-ua-bitness": profile.secChUaBitness,
25176
+ "sec-ch-ua-model": profile.secChUaModel,
25177
+ "sec-ch-ua-wow64": profile.secChUaWow64,
25178
+ "sec-ch-ua-full-version-list": profile.secChUaFullVersionList
25179
+ };
25180
+ }
25181
+ function getFingerprintParams(options) {
25182
+ const profile = resolveProfile(options);
25183
+ return {
25184
+ dpr: String(profile.devicePixelRatio)
25185
+ };
25186
+ }
25187
+ var meta;
25188
+ var init_headers = __esm({
25189
+ "src/utils/headers.ts"() {
25190
+ init_user_agents();
25191
+ meta = (prop2) => new RegExp(`<meta property="${prop2}" content="([^"]*)"`);
25192
+ }
25193
+ });
25194
+
25195
+ // src/utils/pacing.ts
25196
+ function pacingState(ctx) {
25197
+ if (!ctx.__pacing) {
25198
+ ctx.__pacing = { lastRequestAt: 0, chain: Promise.resolve(), inflight: 0 };
25199
+ }
25200
+ return ctx.__pacing;
25201
+ }
25202
+ function humanDelay(baseMs = TYPICAL_GAP_MS, spreadMs = 220) {
25203
+ const u = Math.random() * Math.random();
25204
+ const jitter = Math.floor(u * spreadMs * 2) - spreadMs;
25205
+ return Math.max(MIN_GAP_MS, Math.min(MAX_GAP_MS, baseMs + jitter));
25206
+ }
25207
+ function sleep(ms) {
25208
+ return new Promise((resolve) => setTimeout(resolve, Math.max(0, Math.floor(ms))));
25209
+ }
25210
+ async function paceRequest(ctx, weight = "normal") {
25211
+ const state = pacingState(ctx);
25212
+ const base = weight === "light" ? TYPICAL_GAP_MS * 0.5 : weight === "heavy" ? TYPICAL_GAP_MS * 2.2 : TYPICAL_GAP_MS;
25213
+ const turn = state.chain.then(async () => {
25214
+ const now = Date.now();
25215
+ const elapsed = now - state.lastRequestAt;
25216
+ if (elapsed < MIN_GAP_MS) {
25217
+ await sleep(humanDelay(Math.max(base, MIN_GAP_MS - elapsed)));
25218
+ } else if (elapsed < base) {
25219
+ await sleep(humanDelay(base - elapsed, 160));
25220
+ } else {
25221
+ await sleep(humanDelay(MIN_GAP_MS, 60));
25222
+ }
25223
+ state.lastRequestAt = Date.now();
25224
+ });
25225
+ state.chain = turn.catch(() => {
25226
+ });
25227
+ return turn;
25228
+ }
25229
+ function retryDelay(attempt, baseMs = 1200, capMs = 45e3) {
25230
+ const exp = Math.min(capMs, baseMs * Math.pow(1.7, Math.max(0, attempt)));
25231
+ const jitter = 0.5 + Math.random() * 0.75;
25232
+ return Math.min(capMs, Math.floor(exp * jitter));
25233
+ }
25234
+ function noteAction(ctx, weight = "heavy") {
25235
+ const state = pacingState(ctx);
25236
+ state.lastRequestAt = Date.now() + (weight === "heavy" ? 350 : 120);
25237
+ }
25238
+ var MIN_GAP_MS, TYPICAL_GAP_MS, MAX_GAP_MS;
25239
+ var init_pacing = __esm({
25240
+ "src/utils/pacing.ts"() {
25241
+ MIN_GAP_MS = 120;
25242
+ TYPICAL_GAP_MS = 420;
25243
+ MAX_GAP_MS = 2500;
25244
+ }
25245
+ });
25246
+
25247
+ // src/utils/safety.ts
25248
+ function safetyState(ctx) {
25249
+ if (!ctx.__safety) {
25250
+ ctx.__safety = { window: [], openedAt: 0, authFailures: 0, cappedCount: 0, trips: [] };
25251
+ }
25252
+ const state = ctx.__safety;
25253
+ if (!Array.isArray(state.window)) state.window = [];
25254
+ if (!Array.isArray(state.trips)) state.trips = [];
25255
+ return state;
25256
+ }
25257
+ function cooldownFor(state) {
25258
+ const factor = Math.pow(1.8, Math.max(0, state.trips.length - 1));
25259
+ return Math.min(MAX_COOLDOWN_MS, Math.floor(BASE_COOLDOWN_MS * factor));
25260
+ }
25261
+ function isBreakerOpen(ctx) {
25262
+ const state = safetyState(ctx);
25263
+ if (!state.openedAt) return false;
25264
+ if (Date.now() - state.openedAt >= cooldownFor(state)) {
25265
+ state.openedAt = 0;
25266
+ state.authFailures = 0;
25267
+ return false;
25268
+ }
25269
+ return true;
25270
+ }
25271
+ function tripBreaker(ctx, reason = "manual") {
25272
+ const state = safetyState(ctx);
25273
+ if (state.openedAt && state.reason === reason) return;
25274
+ state.openedAt = Date.now();
25275
+ state.reason = reason;
25276
+ state.authFailures = 0;
25277
+ state.trips.push(Date.now());
25278
+ if (ctx.__onSafetyTrip) {
25279
+ try {
25280
+ ctx.__onSafetyTrip({ reason, cooldownMs: cooldownFor(state) });
25281
+ } catch {
25282
+ }
25283
+ }
25284
+ }
25285
+ function resetBreaker(ctx) {
25286
+ const state = safetyState(ctx);
25287
+ state.openedAt = 0;
25288
+ state.reason = void 0;
25289
+ state.authFailures = 0;
25290
+ }
25291
+ function noteAuthFailure(ctx) {
25292
+ const state = safetyState(ctx);
25293
+ state.authFailures += 1;
25294
+ if (state.authFailures >= AUTH_FAILURE_THRESHOLD) {
25295
+ tripBreaker(ctx, "auth-failure");
25296
+ }
25297
+ }
25298
+ function noteRateLimit(ctx) {
25299
+ tripBreaker(ctx, "rate-limit");
25300
+ }
25301
+ function noteCheckpoint(ctx) {
25302
+ tripBreaker(ctx, "checkpoint");
25303
+ }
25304
+ function reserveRequest(ctx) {
25305
+ const state = safetyState(ctx);
25306
+ if (isBreakerOpen(ctx)) {
25307
+ return cooldownFor(state) - (Date.now() - state.openedAt);
25308
+ }
25309
+ const now = Date.now();
25310
+ state.window = state.window.filter((t) => now - t < WINDOW_MS);
25311
+ if (state.window.length >= MAX_REQUESTS_IN_WINDOW) {
25312
+ state.cappedCount += 1;
25313
+ const oldest = state.window[0];
25314
+ return Math.max(0, WINDOW_MS - (now - oldest));
25315
+ }
25316
+ state.window.push(now);
25317
+ return 0;
25318
+ }
25319
+ function safetySnapshot(ctx) {
25320
+ const state = safetyState(ctx);
25321
+ const now = Date.now();
25322
+ state.window = state.window.filter((t) => now - t < WINDOW_MS);
25323
+ const open = isBreakerOpen(ctx);
25324
+ return {
25325
+ closed: !open,
25326
+ reason: open ? state.reason : void 0,
25327
+ cooldownRemainingMs: open ? cooldownFor(state) - (now - state.openedAt) : 0,
25328
+ requestsInWindow: state.window.length,
25329
+ authFailures: state.authFailures,
25330
+ cappedCount: state.cappedCount
25331
+ };
25332
+ }
25333
+ var MAX_REQUESTS_IN_WINDOW, WINDOW_MS, BASE_COOLDOWN_MS, MAX_COOLDOWN_MS, AUTH_FAILURE_THRESHOLD;
25334
+ var init_safety = __esm({
25335
+ "src/utils/safety.ts"() {
25336
+ MAX_REQUESTS_IN_WINDOW = 28;
25337
+ WINDOW_MS = 2e4;
25338
+ BASE_COOLDOWN_MS = 3 * 60 * 1e3;
25339
+ MAX_COOLDOWN_MS = 30 * 60 * 1e3;
25340
+ AUTH_FAILURE_THRESHOLD = 3;
25341
+ }
25342
+ });
25343
+
24957
25344
  // src/utils/axios.ts
24958
25345
  var axios_exports = {};
24959
25346
  __export(axios_exports, {
@@ -25019,18 +25406,37 @@ function adaptResponse(res) {
25019
25406
  }
25020
25407
  };
25021
25408
  }
25409
+ function looksLikeCheckpoint(res) {
25410
+ const location = res?.headers?.location || res?.headers?.Location || "";
25411
+ if (typeof location === "string" && /\/checkpoint\/|two_factor|\/consent|\/recover|account_disabled/i.test(location)) {
25412
+ return true;
25413
+ }
25414
+ const body = typeof res?.body === "string" ? res.body : "";
25415
+ return /"error":1357004|account has been (?:disabled|suspended)|confirm your identity|security check/i.test(body.slice(0, 400));
25416
+ }
25022
25417
  async function requestWithRetry(requestFunction, retries = 3, baseDelay = 1e3, ctx) {
25023
25418
  const emit2 = (event, payload) => {
25024
25419
  try {
25025
- if (ctx?._emitter && typeof ctx._emitter.emit === "function") ;
25420
+ if (ctx?._emitter && typeof ctx._emitter.emit === "function") {
25421
+ ctx._emitter.emit(event, payload);
25422
+ }
25026
25423
  } catch {
25027
25424
  }
25028
25425
  };
25029
25426
  let lastError;
25030
25427
  for (let i2 = 0; i2 < retries; i2++) {
25031
25428
  try {
25429
+ const safetyWait = reserveRequest(ctx);
25430
+ if (safetyWait > 0) await delay(safetyWait);
25431
+ await paceRequest(ctx, "normal");
25032
25432
  const res = await requestFunction();
25033
- return adaptResponse(res);
25433
+ const adapted = adaptResponse(res);
25434
+ if (looksLikeCheckpoint(adapted)) {
25435
+ noteCheckpoint(ctx);
25436
+ } else {
25437
+ resetBreaker(ctx);
25438
+ }
25439
+ return adapted;
25034
25440
  } catch (rawError) {
25035
25441
  const e = rawError || {};
25036
25442
  lastError = e;
@@ -25046,6 +25452,7 @@ async function requestWithRetry(requestFunction, retries = 3, baseDelay = 1e3, c
25046
25452
  const method = String(e?.config?.method || "").toUpperCase();
25047
25453
  if (status === 429) {
25048
25454
  emit2("rateLimit", { status, url: url2, method });
25455
+ noteRateLimit(ctx);
25049
25456
  }
25050
25457
  if (status >= 400 && status < 500 && status !== 429) {
25051
25458
  if (e.response) return adaptResponse(e.response);
@@ -25060,8 +25467,7 @@ async function requestWithRetry(requestFunction, retries = 3, baseDelay = 1e3, c
25060
25467
  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
25468
  emit2("networkError", { code: netCode, message: msg, url: url2, method });
25062
25469
  }
25063
- const backoffDelay = Math.min(baseDelay * Math.pow(2, i2) + Math.floor(Math.random() * 200), 3e4);
25064
- await delay(backoffDelay);
25470
+ await delay(retryDelay(i2, baseDelay, 3e4));
25065
25471
  }
25066
25472
  }
25067
25473
  throw lastError || new Error("Request failed after retries");
@@ -25084,16 +25490,16 @@ function cleanGet(url2) {
25084
25490
  }
25085
25491
  async function get(url2, reqJar, qs2, options, ctx, customHeader) {
25086
25492
  const config = {
25087
- headers: getHeaders(url2, options, ctx, customHeader),
25493
+ headers: getHeaders(url2, { ...options, method: "GET" }, ctx, customHeader),
25088
25494
  timeout: 6e4,
25089
25495
  params: qs2,
25090
25496
  ...getRequestProxy(options),
25091
25497
  validateStatus: (status) => status >= 200 && status < 600
25092
25498
  };
25093
- return requestWithRetry(async () => await getClient(reqJar).get(url2, config));
25499
+ return requestWithRetry(async () => await getClient(reqJar).get(url2, config), 3, 1e3, ctx);
25094
25500
  }
25095
25501
  async function post(url2, reqJar, form, options, ctx, customHeader) {
25096
- const headers = getHeaders(url2, options, ctx, customHeader);
25502
+ const headers = getHeaders(url2, { ...options, method: "POST" }, ctx, customHeader);
25097
25503
  let data2 = form;
25098
25504
  const contentType = headers["Content-Type"] || "application/x-www-form-urlencoded";
25099
25505
  if (contentType.includes("json")) {
@@ -25118,7 +25524,7 @@ async function post(url2, reqJar, form, options, ctx, customHeader) {
25118
25524
  ...getRequestProxy(options),
25119
25525
  validateStatus: (status) => status >= 200 && status < 600
25120
25526
  };
25121
- return requestWithRetry(async () => await getClient(reqJar).post(url2, data2, config));
25527
+ return requestWithRetry(async () => await getClient(reqJar).post(url2, data2, config), 3, 1e3, ctx);
25122
25528
  }
25123
25529
  async function postMultipart(url2, reqJar, formData, qs2, options, ctx, customHeader) {
25124
25530
  const multipartHeader = {
@@ -25126,7 +25532,7 @@ async function postMultipart(url2, reqJar, formData, qs2, options, ctx, customHe
25126
25532
  ...customHeader || {}
25127
25533
  };
25128
25534
  const config = {
25129
- headers: getHeaders(url2, options, ctx, multipartHeader),
25535
+ headers: getHeaders(url2, { ...options, method: "POST" }, ctx, multipartHeader),
25130
25536
  timeout: 12e4,
25131
25537
  params: qs2,
25132
25538
  maxContentLength: Infinity,
@@ -25134,7 +25540,7 @@ async function postMultipart(url2, reqJar, formData, qs2, options, ctx, customHe
25134
25540
  ...getRequestProxy(options),
25135
25541
  validateStatus: (status) => status >= 200 && status < 600
25136
25542
  };
25137
- return requestWithRetry(async () => await getClient(reqJar).post(url2, formData, config));
25543
+ return requestWithRetry(async () => await getClient(reqJar).post(url2, formData, config), 3, 1e3, ctx);
25138
25544
  }
25139
25545
  async function postFormData(url2, reqJar, form, qs2, options, ctx, customHeader) {
25140
25546
  const formData = new import_form_data2.default();
@@ -25148,13 +25554,13 @@ async function postFormData(url2, reqJar, form, qs2, options, ctx, customHeader)
25148
25554
  ...customHeader || {}
25149
25555
  };
25150
25556
  const config = {
25151
- headers: getHeaders(url2, options, ctx, multipartHeader),
25557
+ headers: getHeaders(url2, { ...options, method: "POST" }, ctx, multipartHeader),
25152
25558
  timeout: 6e4,
25153
25559
  params: qs2,
25154
25560
  ...getRequestProxy(options),
25155
25561
  validateStatus: (status) => status >= 200 && status < 600
25156
25562
  };
25157
- return requestWithRetry(async () => await getClient(reqJar).post(url2, formData, config));
25563
+ return requestWithRetry(async () => await getClient(reqJar).post(url2, formData, config), 3, 1e3, ctx);
25158
25564
  }
25159
25565
  function getJar() {
25160
25566
  return new import_tough_cookie.CookieJar();
@@ -25168,6 +25574,8 @@ var init_axios3 = __esm({
25168
25574
  import_form_data2 = __toESM(require_form_data2());
25169
25575
  init_headers();
25170
25576
  init_constants();
25577
+ init_pacing();
25578
+ init_safety();
25171
25579
  jar = new import_tough_cookie.CookieJar();
25172
25580
  client = wrapper(axios_default.create({ jar }));
25173
25581
  clients = /* @__PURE__ */ new WeakMap();
@@ -69521,7 +69929,7 @@ var require_dist3 = __commonJS({
69521
69929
  }
69522
69930
  return options;
69523
69931
  };
69524
- var HttpsProxyAgent5 = class extends agent_base_1.Agent {
69932
+ var HttpsProxyAgent4 = class extends agent_base_1.Agent {
69525
69933
  constructor(proxy, opts) {
69526
69934
  super(opts);
69527
69935
  this.options = { path: void 0 };
@@ -69600,8 +70008,8 @@ var require_dist3 = __commonJS({
69600
70008
  return fakeSocket;
69601
70009
  }
69602
70010
  };
69603
- HttpsProxyAgent5.protocols = ["http", "https"];
69604
- exports.HttpsProxyAgent = HttpsProxyAgent5;
70011
+ HttpsProxyAgent4.protocols = ["http", "https"];
70012
+ exports.HttpsProxyAgent = HttpsProxyAgent4;
69605
70013
  function resume(socket) {
69606
70014
  socket.resume();
69607
70015
  }
@@ -75102,34 +75510,57 @@ var require_lodash = __commonJS({
75102
75510
  var utils_exports2 = {};
75103
75511
  __export(utils_exports2, {
75104
75512
  AUTHOR: () => AUTHOR,
75513
+ AUTH_ERROR_CODES: () => AUTH_ERROR_CODES,
75514
+ AUTH_FAILURE_THRESHOLD: () => AUTH_FAILURE_THRESHOLD,
75105
75515
  AuthenticationError: () => AuthenticationError,
75516
+ BASE_COOLDOWN_MS: () => BASE_COOLDOWN_MS,
75106
75517
  BRAND: () => BRAND,
75518
+ CHROME_MAJORS: () => CHROME_MAJORS,
75107
75519
  ConfigurationError: () => ConfigurationError,
75520
+ DESKTOP_PLATFORMS: () => DESKTOP_PLATFORMS,
75108
75521
  FCAError: () => FCAError,
75522
+ LS_DOC_TOKEN_ERRORS: () => LS_DOC_TOKEN_ERRORS,
75523
+ MAX_REQUESTS_IN_WINDOW: () => MAX_REQUESTS_IN_WINDOW,
75109
75524
  NUM_TO_DAY: () => NUM_TO_DAY,
75110
75525
  NUM_TO_MONTH: () => NUM_TO_MONTH,
75111
75526
  NetworkError: () => NetworkError,
75112
75527
  NotFoundError: () => NotFoundError,
75113
75528
  PermissionError: () => PermissionError,
75114
75529
  RateLimitError: () => RateLimitError,
75530
+ SESSION_COOKIE_NAMES: () => SESSION_COOKIE_NAMES,
75115
75531
  TimeoutError: () => TimeoutError,
75116
75532
  ValidationError: () => ValidationError,
75533
+ WINDOW_MS: () => WINDOW_MS,
75117
75534
  _formatAttachment: () => _formatAttachment,
75535
+ applySetCookie: () => applySetCookie,
75118
75536
  arrToForm: () => arrToForm,
75119
75537
  arrayToObject: () => arrayToObject2,
75538
+ awaitProactiveSlot: () => awaitProactiveSlot,
75120
75539
  banner: () => banner,
75121
75540
  binaryToDecimal: () => binaryToDecimal,
75122
75541
  brandTag: () => brandTag,
75542
+ buildProfile: () => buildProfile,
75123
75543
  buildWsTaskContent: () => buildWsTaskContent,
75544
+ canActProactively: () => canActProactively,
75124
75545
  cleanGet: () => cleanGet,
75125
75546
  cleanJsonResponse: () => cleanJsonResponse,
75547
+ collectSessionCookies: () => collectSessionCookies,
75126
75548
  debug: () => debug,
75127
75549
  decodeClientPayload: () => decodeClientPayload,
75550
+ defaultBrowserProfile: () => defaultBrowserProfile,
75128
75551
  defaultUserAgent: () => defaultUserAgent,
75129
75552
  delay: () => delay2,
75130
75553
  ensureCometTokens: () => ensureCometTokens,
75131
75554
  error: () => error,
75132
75555
  extractAttachmentIds: () => extractAttachmentIds,
75556
+ extractCookies: () => extractCookies,
75557
+ extractCookiesFromBody: () => extractCookiesFromBody,
75558
+ extractCookiesFromJar: () => extractCookiesFromJar,
75559
+ extractCookiesFromSetCookie: () => extractCookiesFromSetCookie,
75560
+ extractDtsg: () => extractDtsg,
75561
+ extractLsd: () => extractLsd,
75562
+ extractSpin: () => extractSpin,
75563
+ formatAppStateCookie: () => formatAppStateCookie,
75133
75564
  formatAttachment: () => formatAttachment,
75134
75565
  formatCookie: () => formatCookie2,
75135
75566
  formatDate: () => formatDate,
@@ -75156,6 +75587,7 @@ __export(utils_exports2, {
75156
75587
  getAccessFromBusiness: () => getAccessFromBusiness,
75157
75588
  getAdminTextMessageType: () => getAdminTextMessageType,
75158
75589
  getAppState: () => getAppState,
75590
+ getFingerprintParams: () => getFingerprintParams,
75159
75591
  getFrom: () => getFrom,
75160
75592
  getGUID: () => getGUID,
75161
75593
  getHeaders: () => getHeaders,
@@ -75163,14 +75595,28 @@ __export(utils_exports2, {
75163
75595
  getRandom: () => getRandom,
75164
75596
  getSignatureID: () => getSignatureID,
75165
75597
  getType: () => getType,
75598
+ getWebSocketHeaders: () => getWebSocketHeaders,
75599
+ hasAuthenticatedSession: () => hasAuthenticatedSession,
75600
+ humanDelay: () => humanDelay,
75166
75601
  info: () => info,
75602
+ invalidateCometTokens: () => invalidateCometTokens,
75603
+ isAuthFailure: () => isAuthFailure,
75604
+ isBreakerOpen: () => isBreakerOpen,
75167
75605
  isReadableStream: () => isReadableStream2,
75606
+ isStaleTokenError: () => isStaleTokenError,
75168
75607
  json: () => json2,
75169
75608
  log: () => log,
75170
75609
  logOptions: () => logOptions,
75171
75610
  makeDefaults: () => makeDefaults,
75172
75611
  makeParsable: () => makeParsable,
75173
75612
  meta: () => meta,
75613
+ missingSessionCookies: () => missingSessionCookies,
75614
+ normalizeBrowserProfile: () => normalizeBrowserProfile,
75615
+ noteAction: () => noteAction,
75616
+ noteAuthFailure: () => noteAuthFailure,
75617
+ noteCheckpoint: () => noteCheckpoint,
75618
+ noteRateLimit: () => noteRateLimit,
75619
+ paceRequest: () => paceRequest,
75174
75620
  padZeros: () => padZeros,
75175
75621
  parseAndCheckLogin: () => parseAndCheckLogin,
75176
75622
  post: () => post,
@@ -75181,16 +75627,31 @@ __export(utils_exports2, {
75181
75627
  promisify: () => promisify,
75182
75628
  publishLsRequestWithAck: () => publishLsRequestWithAck,
75183
75629
  randomUserAgent: () => randomUserAgent,
75630
+ refreshSessionCookies: () => refreshSessionCookies,
75631
+ repairSession: () => repairSession,
75632
+ reserveRequest: () => reserveRequest,
75633
+ resetBreaker: () => resetBreaker,
75634
+ resolveProfile: () => resolveProfile,
75635
+ retryDelay: () => retryDelay,
75636
+ safetySnapshot: () => safetySnapshot,
75184
75637
  saveCookies: () => saveCookies,
75638
+ scheduleSessionKeepAlive: () => scheduleSessionKeepAlive,
75185
75639
  setProxy: () => setProxy2,
75640
+ sleep: () => sleep,
75641
+ startLiveness: () => startLiveness,
75186
75642
  success: () => success,
75643
+ tripBreaker: () => tripBreaker,
75187
75644
  uploadGroupImage: () => uploadGroupImage,
75188
75645
  uploadMercuryAttachment: () => uploadMercuryAttachment,
75646
+ warmUpSession: () => warmUpSession,
75189
75647
  warn: () => warn,
75190
75648
  windowsUserAgent: () => windowsUserAgent,
75649
+ withCometTokens: () => withCometTokens,
75650
+ withSessionRetry: () => withSessionRetry,
75191
75651
  ws: () => ws
75192
75652
  });
75193
75653
  init_axios3();
75654
+ init_headers();
75194
75655
  init_constants();
75195
75656
 
75196
75657
  // node_modules/cheerio/dist/esm/options.js
@@ -89399,8 +89860,34 @@ init_headers();
89399
89860
 
89400
89861
  // src/utils/clients.ts
89401
89862
  init_constants();
89863
+ function formatAppStateCookie(cookie) {
89864
+ const name = cookie.name || cookie.key;
89865
+ const value = String(cookie.value);
89866
+ const parts = [`${name}=${value}`];
89867
+ const path2 = cookie.path || "/";
89868
+ parts.push(`Path=${path2}`);
89869
+ const domain = cookie.domain || ".facebook.com";
89870
+ parts.push(`Domain=${domain}`);
89871
+ if (cookie.secure) parts.push("Secure");
89872
+ if (cookie.httpOnly) parts.push("HttpOnly");
89873
+ const sameSite = normalizeSameSite(cookie.sameSite);
89874
+ if (sameSite) parts.push(`SameSite=${sameSite}`);
89875
+ if (cookie.expirationDate && !cookie.session) {
89876
+ parts.push(`Expires=${new Date(cookie.expirationDate * 1e3).toUTCString()}`);
89877
+ }
89878
+ return parts.join("; ");
89879
+ }
89880
+ function normalizeSameSite(value) {
89881
+ if (!value) return null;
89882
+ const v = String(value).toLowerCase();
89883
+ if (v === "no_restriction" || v === "none") return "None";
89884
+ if (v === "lax") return "Lax";
89885
+ if (v === "strict") return "Strict";
89886
+ return null;
89887
+ }
89402
89888
  function formatCookie(arr, url2) {
89403
- return arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=" + url2 + ".com";
89889
+ const host = url2.replace(/^\./, "");
89890
+ return arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=." + host + "; Secure; SameSite=None";
89404
89891
  }
89405
89892
  function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89406
89893
  const delay3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -89409,7 +89896,7 @@ function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89409
89896
  throw new Error("parseAndCheckLogin received an invalid response.");
89410
89897
  }
89411
89898
  if (data2.statusCode >= 500 && data2.statusCode < 600) {
89412
- if (noRetry || retryCount >= 5) {
89899
+ if (noRetry || retryCount >= 3) {
89413
89900
  const err = new Error(
89414
89901
  "Request retry failed. Check the `res` and `statusCode` property on this error."
89415
89902
  );
@@ -89419,7 +89906,7 @@ function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89419
89906
  throw err;
89420
89907
  }
89421
89908
  retryCount++;
89422
- const retryTime = Math.floor(Math.random() * 5e3);
89909
+ const retryTime = Math.min(3e4, Math.floor(800 * Math.pow(1.7, retryCount) * (0.5 + Math.random())));
89423
89910
  const request = data2.request || {};
89424
89911
  const uri = request.uri || {};
89425
89912
  const url2 = request.url || (uri.protocol && uri.hostname ? uri.protocol + "//" + uri.hostname + (uri.port ? ":" + uri.port : "") + (uri.pathname || "") : "");
@@ -89469,17 +89956,17 @@ function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89469
89956
  } else {
89470
89957
  throw new Error("Unknown response body type: " + typeof data2.body);
89471
89958
  }
89472
- if (res.redirect && data2.request.method === "GET") {
89959
+ if (res.redirect && data2.request.method === "GET" && retryCount < 5) {
89473
89960
  const redirectRes = await http5.get(res.redirect, ctx.jar);
89474
- return await parseAndCheckLogin(ctx, http5)(redirectRes);
89961
+ return await parseAndCheckLogin(ctx, http5, retryCount + 1)(redirectRes);
89475
89962
  }
89476
89963
  if (res.jsmods && res.jsmods.require && Array.isArray(res.jsmods.require[0]) && res.jsmods.require[0][0] === "Cookie") {
89477
89964
  const requireCookie = res.jsmods.require[0][3];
89478
89965
  if (Array.isArray(requireCookie) && requireCookie.length >= 4) {
89479
89966
  const cookieValue = String(requireCookie[0]).replace("_js_", "");
89480
89967
  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");
89968
+ ctx.jar.setCookieSync(formatCookie(normalizedCookie, "facebook"), "https://www.facebook.com");
89969
+ ctx.jar.setCookieSync(formatCookie(normalizedCookie, "messenger"), "https://www.messenger.com");
89483
89970
  }
89484
89971
  }
89485
89972
  if (res.jsmods && Array.isArray(res.jsmods.require)) {
@@ -89504,13 +89991,27 @@ function parseAndCheckLogin(ctx, http5, retryCount = 0, noRetry = false) {
89504
89991
  }
89505
89992
  function saveCookies(jar2) {
89506
89993
  return function(res) {
89507
- const cookies = res?.headers?.["set-cookie"] || [];
89994
+ const headers = res?.headers || {};
89995
+ const raw = headers["set-cookie"] || headers["Set-Cookie"] || [];
89996
+ const cookies = Array.isArray(raw) ? raw : [raw];
89508
89997
  cookies.forEach(function(c) {
89509
- if (c.indexOf(".facebook.com") > -1) {
89510
- jar2.setCookie(c, "https://www.facebook.com");
89998
+ if (!c || typeof c !== "string") return;
89999
+ if (/domain=\.?facebook\.com/i.test(c) || /domain=\.?messenger\.com/i.test(c)) {
90000
+ try {
90001
+ jar2.setCookieSync(c, "https://www.facebook.com");
90002
+ } catch {
90003
+ }
90004
+ try {
90005
+ const mirrored = c.replace(/domain=\.?facebook\.com/i, "domain=.messenger.com").replace(/domain=\.?messenger\.com/i, "domain=.facebook.com");
90006
+ jar2.setCookieSync(mirrored, "https://www.messenger.com");
90007
+ } catch {
90008
+ }
90009
+ } else {
90010
+ try {
90011
+ jar2.setCookieSync(`${c}; domain=.facebook.com; path=/`, "https://www.facebook.com");
90012
+ } catch {
90013
+ }
89511
90014
  }
89512
- const c2 = c.replace(/domain=\.facebook\.com/, "domain=.messenger.com");
89513
- jar2.setCookie(c2, "https://www.messenger.com");
89514
90015
  });
89515
90016
  return res;
89516
90017
  };
@@ -90040,43 +90541,8 @@ function formatProxyPresence(presence, userID) {
90040
90541
  };
90041
90542
  }
90042
90543
 
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
- }
90544
+ // src/utils/index.ts
90545
+ init_user_agents();
90080
90546
 
90081
90547
  // src/utils/errors.ts
90082
90548
  var FCAError = class extends Error {
@@ -90240,6 +90706,7 @@ function buildWsTaskContent(ctx, tasks, versionId) {
90240
90706
  // src/utils/attachments.ts
90241
90707
  var import_form_data3 = __toESM(require_form_data2());
90242
90708
  init_constants();
90709
+ init_user_agents();
90243
90710
  function cleanJsonResponse(value) {
90244
90711
  if (typeof value !== "string") return value;
90245
90712
  const normalized = value.replace(/^for\s*\(;;\);\s*/i, "");
@@ -90381,7 +90848,7 @@ function normalizeFilename(filename, mime) {
90381
90848
  return ext ? `${base}.${ext}` : base;
90382
90849
  }
90383
90850
  async function uploadMercuryAttachment(ctx, defaultFuncs, attachment) {
90384
- const normalized = await normalizeAttachmentInput(attachment);
90851
+ const normalized = await normalizeAttachmentInput(attachment, ctx);
90385
90852
  const url2 = "https://www.facebook.com/ajax/mercury/upload.php";
90386
90853
  await ensureUploadTokens(ctx, defaultFuncs);
90387
90854
  const formData = new import_form_data3.default();
@@ -90393,7 +90860,7 @@ async function uploadMercuryAttachment(ctx, defaultFuncs, attachment) {
90393
90860
  const data2 = cleanJsonResponse(res && res.body !== void 0 ? res.body : res);
90394
90861
  return finalizeUpload(data2);
90395
90862
  }
90396
- async function normalizeAttachmentInput(attachment) {
90863
+ async function normalizeAttachmentInput(attachment, ctx) {
90397
90864
  if (Buffer.isBuffer(attachment)) {
90398
90865
  const mime = sniffMime(attachment);
90399
90866
  return {
@@ -90405,7 +90872,11 @@ async function normalizeAttachmentInput(attachment) {
90405
90872
  const url2 = typeof attachment === "string" ? attachment : attachment && (attachment.url || attachment.href);
90406
90873
  if (typeof url2 === "string" && /^https?:\/\//i.test(url2)) {
90407
90874
  const resp = await fetch(url2, {
90408
- headers: { "User-Agent": "Mozilla/5.0", Accept: "*/*" }
90875
+ headers: {
90876
+ "User-Agent": ctx?.globalOptions && ctx.globalOptions.userAgent || defaultBrowserProfile.userAgent,
90877
+ Accept: "image/avif,image/webp,image/apng,image/svg+xml,image/*,video/*,audio/*,*/*;q=0.8",
90878
+ "Accept-Language": ctx?.globalOptions && ctx.globalOptions.browser?.acceptLanguage || "en-US,en;q=0.9"
90879
+ }
90409
90880
  });
90410
90881
  if (!resp.ok) {
90411
90882
  throw new Error(`Failed to download attachment url (HTTP ${resp.status})`);
@@ -90495,7 +90966,21 @@ async function uploadGroupImage(ctx, defaultFuncs, image) {
90495
90966
  }
90496
90967
 
90497
90968
  // src/utils/lsd.ts
90498
- var TOKEN_TTL_MS = 30 * 60 * 1e3;
90969
+ var TOKEN_TTL_MS = 10 * 60 * 1e3;
90970
+ var STALE_TOKEN_ERRORS = /* @__PURE__ */ new Set([
90971
+ 1357004,
90972
+ // "Sorry, something went wrong / close and re-open your browser window"
90973
+ 1357031,
90974
+ // document token invalid
90975
+ 1357051
90976
+ // token mismatch
90977
+ ]);
90978
+ var MAX_BACKOFF_MS = 60 * 1e3;
90979
+ function tokenState(ctx) {
90980
+ const state = ctx.__cometTokens || (ctx.__cometTokens = {});
90981
+ if (typeof state.failures !== "number") state.failures = 0;
90982
+ return state;
90983
+ }
90499
90984
  function getFrom3(html3, startToken, endToken) {
90500
90985
  const startIndex = html3.indexOf(startToken);
90501
90986
  if (startIndex < 0) return "";
@@ -90510,34 +90995,544 @@ function extractLsd(html3) {
90510
90995
  function extractDtsg(html3) {
90511
90996
  return getFrom3(html3, '["DTSGInitialData",[],{"token":"', '"}') || getFrom3(html3, 'name="fb_dtsg" value="', '"') || (html3.match(/"DTSGInitialData",\[\],\{"token":"([^"]+)"/) || [])[1] || "";
90512
90997
  }
90998
+ function extractSpin(html3) {
90999
+ const out = {};
91000
+ const spinB = (html3.match(/"__spin_b":"([^"]+)"/) || [])[1];
91001
+ const spinR = (html3.match(/"__spin_r":(\d+)/) || [])[1];
91002
+ const spinT = (html3.match(/"__spin_t":(\d+)/) || [])[1];
91003
+ const rev = (html3.match(/"__rev":(\d+)/) || [])[1] || getFrom3(html3, 'revision":', ",");
91004
+ if (spinB) out.__spin_b = spinB;
91005
+ if (spinR) out.__spin_r = spinR;
91006
+ if (spinT) out.__spin_t = spinT;
91007
+ if (rev) out.__rev = rev;
91008
+ return out;
91009
+ }
91010
+ function recomputeJazoest(fbDtsg) {
91011
+ let sum = 0;
91012
+ for (let i2 = 0; i2 < fbDtsg.length; i2++) sum += fbDtsg.charCodeAt(i2);
91013
+ return "2" + String(sum);
91014
+ }
91015
+ function tokenPairFresh(state) {
91016
+ return Boolean(
91017
+ state.lsd && state.fb_dtsg && state.fetchedAt && Date.now() - state.fetchedAt < TOKEN_TTL_MS
91018
+ );
91019
+ }
91020
+ function htmlOf(res) {
91021
+ if (typeof res === "string") return res;
91022
+ if (res && typeof res.body === "string") return res.body;
91023
+ if (res && res.body != null) return String(res.body);
91024
+ return "";
91025
+ }
90513
91026
  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) {
91027
+ const state = tokenState(ctx);
91028
+ if (!force && tokenPairFresh(state)) {
90517
91029
  ctx.lsd = state.lsd;
90518
91030
  ctx.fb_dtsg = state.fb_dtsg;
90519
91031
  return;
90520
91032
  }
91033
+ if (!force && state.failures > 0) {
91034
+ const backoff = Math.min(1e3 * Math.pow(2, state.failures), MAX_BACKOFF_MS);
91035
+ if (state.attemptedAt && Date.now() - state.attemptedAt < backoff) {
91036
+ if (state.lsd && state.fb_dtsg) {
91037
+ ctx.lsd = state.lsd;
91038
+ ctx.fb_dtsg = state.fb_dtsg;
91039
+ }
91040
+ return;
91041
+ }
91042
+ }
91043
+ state.attemptedAt = Date.now();
90521
91044
  try {
90522
91045
  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;
91046
+ const html3 = htmlOf(res);
91047
+ if (!html3) {
91048
+ state.failures++;
91049
+ return;
91050
+ }
90525
91051
  const lsd = extractLsd(html3);
90526
91052
  const dtsg = extractDtsg(html3);
90527
- if (lsd) state.lsd = lsd;
90528
- if (dtsg) state.fb_dtsg = dtsg;
91053
+ if (!lsd || !dtsg) {
91054
+ state.failures++;
91055
+ return;
91056
+ }
91057
+ state.lsd = lsd;
91058
+ state.fb_dtsg = dtsg;
90529
91059
  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);
91060
+ state.failures = 0;
91061
+ const spin = extractSpin(html3);
91062
+ if (Object.keys(spin).length) ctx.__spin = { ...ctx.__spin || {}, ...spin };
91063
+ if (spin.__rev) ctx.revision = spin.__rev;
91064
+ ctx.lsd = lsd;
91065
+ ctx.fb_dtsg = dtsg;
91066
+ ctx.jazoest = recomputeJazoest(dtsg);
91067
+ } catch {
91068
+ state.failures++;
91069
+ }
91070
+ }
91071
+ function invalidateCometTokens(ctx) {
91072
+ const state = tokenState(ctx);
91073
+ state.lsd = void 0;
91074
+ state.fb_dtsg = void 0;
91075
+ state.fetchedAt = void 0;
91076
+ state.failures = 0;
91077
+ state.attemptedAt = 0;
91078
+ delete ctx.lsd;
91079
+ delete ctx.fb_dtsg;
91080
+ }
91081
+ function isStaleTokenError(value) {
91082
+ if (value == null) return false;
91083
+ if (typeof value === "number") return STALE_TOKEN_ERRORS.has(value);
91084
+ if (typeof value === "object") {
91085
+ const code = Number(value.error ?? value.code ?? value.errorCode);
91086
+ if (STALE_TOKEN_ERRORS.has(code)) return true;
91087
+ const text3 = String(value.errorDescription || value.errorSummary || value.message || "");
91088
+ return /clos(?:e|ing) (?:and|then) re-?open|invalid document|invalid token|stale token|re-?open your browser/i.test(
91089
+ text3
91090
+ );
91091
+ }
91092
+ return false;
91093
+ }
91094
+ var LS_DOC_TOKEN_ERRORS = STALE_TOKEN_ERRORS;
91095
+ async function withCometTokens(ctx, defaultFuncs, run, options = {}) {
91096
+ const retries = Math.max(1, options.retries ?? 2);
91097
+ let last2;
91098
+ for (let attempt = 0; attempt < retries; attempt++) {
91099
+ await ensureCometTokens(ctx, defaultFuncs, attempt > 0);
91100
+ last2 = await run();
91101
+ if (!isStaleTokenError(last2)) return last2;
91102
+ invalidateCometTokens(ctx);
91103
+ }
91104
+ return last2;
91105
+ }
91106
+
91107
+ // src/utils/session.ts
91108
+ init_safety();
91109
+ var SESSION_COOKIE_NAMES = /* @__PURE__ */ new Set([
91110
+ "c_user",
91111
+ "xs",
91112
+ "fr",
91113
+ "datr",
91114
+ "sb",
91115
+ "presence",
91116
+ "wd",
91117
+ "dpr",
91118
+ "locale"
91119
+ ]);
91120
+ var AUTH_ERROR_CODES = /* @__PURE__ */ new Set([
91121
+ 1357001,
91122
+ // "Facebook blocked the login"
91123
+ 1357002,
91124
+ // not logged in
91125
+ 1357031,
91126
+ // document token invalid (treated as auth-adjacent here)
91127
+ 1357046,
91128
+ 1357036
91129
+ ]);
91130
+ function isCookieJar(jar2) {
91131
+ return Boolean(jar2) && typeof jar2.getCookiesSync === "function";
91132
+ }
91133
+ function extractCookiesFromJar(jar2) {
91134
+ const out = {};
91135
+ if (!isCookieJar(jar2)) return out;
91136
+ const origins = [
91137
+ "https://www.facebook.com",
91138
+ "https://facebook.com",
91139
+ "https://mbasic.facebook.com",
91140
+ "https://web.facebook.com",
91141
+ "https://www.messenger.com",
91142
+ "https://messenger.com"
91143
+ ];
91144
+ for (const origin2 of origins) {
91145
+ try {
91146
+ const cookies = jar2.getCookiesSync(origin2) || [];
91147
+ for (const cookie of cookies) {
91148
+ const key = cookie && (cookie.key || cookie.name);
91149
+ const value = cookie && cookie.value;
91150
+ if (!key || value == null) continue;
91151
+ if (!(key in out) || /facebook\.com$/.test(cookie.domain || "")) {
91152
+ out[key] = String(value);
91153
+ }
91154
+ }
91155
+ } catch {
91156
+ }
91157
+ }
91158
+ return out;
91159
+ }
91160
+ function extractCookiesFromSetCookie(header) {
91161
+ const out = {};
91162
+ if (!header) return out;
91163
+ const list = Array.isArray(header) ? header : [String(header)];
91164
+ for (const raw of list) {
91165
+ const parts = String(raw).split(/,(?=\s*[^=;,\s]+\s*=)/);
91166
+ for (const part of parts) {
91167
+ const firstSegment = part.split(";")[0].trim();
91168
+ const eq2 = firstSegment.indexOf("=");
91169
+ if (eq2 <= 0) continue;
91170
+ const name = firstSegment.slice(0, eq2).trim();
91171
+ const value = firstSegment.slice(eq2 + 1).trim();
91172
+ if (name) out[name] = value;
91173
+ }
91174
+ }
91175
+ return out;
91176
+ }
91177
+ function extractCookiesFromBody(body) {
91178
+ const out = {};
91179
+ if (body == null) return out;
91180
+ const text3 = typeof body === "string" ? body : JSON.stringify(body);
91181
+ if (!text3) return out;
91182
+ const re = /(?:document\.cookie\s*=\s*|setCookie\(\s*)["'\\]*([A-Za-z0-9_]+)=([^"';\s\\]+)/g;
91183
+ let match;
91184
+ while ((match = re.exec(text3)) !== null) {
91185
+ out[match[1]] = match[2];
91186
+ }
91187
+ return out;
91188
+ }
91189
+ function extractCookies(sources) {
91190
+ const merged = {};
91191
+ const seen = [];
91192
+ const fromJar = extractCookiesFromJar(sources.jar);
91193
+ if (Object.keys(fromJar).length) {
91194
+ Object.assign(merged, fromJar);
91195
+ seen.push("jar");
91196
+ }
91197
+ const fromHeader = extractCookiesFromSetCookie(sources.setCookie);
91198
+ if (Object.keys(fromHeader).length) {
91199
+ Object.assign(merged, fromHeader);
91200
+ seen.push("set-cookie");
91201
+ }
91202
+ const fromBody = extractCookiesFromBody(sources.body);
91203
+ if (Object.keys(fromBody).length) {
91204
+ Object.assign(merged, fromBody);
91205
+ seen.push("body");
91206
+ }
91207
+ return { cookies: merged, count: Object.keys(merged).length, sources: seen };
91208
+ }
91209
+ function applySetCookie(jar2, header) {
91210
+ if (!isCookieJar(jar2) || !header) return 0;
91211
+ const list = Array.isArray(header) ? header : [String(header)];
91212
+ let applied = 0;
91213
+ for (const raw of list) {
91214
+ if (!raw || typeof raw !== "string") continue;
91215
+ try {
91216
+ jar2.setCookieSync(raw, "https://www.facebook.com");
91217
+ applied++;
91218
+ } catch {
91219
+ try {
91220
+ const normalized = raw.replace(/domain=\.?facebook\.com/i, "Domain=.facebook.com").replace(/;\s*$/, "");
91221
+ jar2.setCookieSync(normalized, "https://www.facebook.com");
91222
+ applied++;
91223
+ } catch {
91224
+ }
91225
+ }
91226
+ if (/domain=\.?facebook\.com/i.test(raw)) {
91227
+ try {
91228
+ jar2.setCookieSync(raw.replace(/domain=\.?facebook\.com/i, "domain=.messenger.com"), "https://www.messenger.com");
91229
+ } catch {
91230
+ }
91231
+ }
91232
+ }
91233
+ return applied;
91234
+ }
91235
+ function hasAuthenticatedSession(jar2) {
91236
+ const cookies = extractCookiesFromJar(jar2);
91237
+ return Boolean(cookies.c_user && (cookies.xs || cookies.fr));
91238
+ }
91239
+ function collectSessionCookies(ctx, host) {
91240
+ const origins = /* @__PURE__ */ new Set([
91241
+ "https://www.facebook.com",
91242
+ "https://facebook.com",
91243
+ "https://web.facebook.com",
91244
+ "https://mbasic.facebook.com",
91245
+ "https://www.messenger.com",
91246
+ "https://messenger.com",
91247
+ "https://edge-chat.messenger.com",
91248
+ "https://gateway.facebook.com"
91249
+ ]);
91250
+ if (host) {
91251
+ try {
91252
+ origins.add(new URL(host).origin);
91253
+ } catch {
91254
+ }
91255
+ }
91256
+ const seen = {};
91257
+ const parts = [];
91258
+ for (const origin2 of origins) {
91259
+ let list = [];
91260
+ try {
91261
+ list = ctx?.jar?.getCookiesSync(origin2) || [];
91262
+ } catch {
91263
+ list = [];
91264
+ }
91265
+ for (const cookie of list) {
91266
+ const name = cookie?.key || cookie?.name;
91267
+ if (!name || seen[name]) continue;
91268
+ seen[name] = true;
91269
+ try {
91270
+ parts.push(cookie.cookieString ? cookie.cookieString() : `${name}=${cookie.value}`);
91271
+ } catch {
91272
+ parts.push(`${name}=${cookie.value}`);
91273
+ }
91274
+ }
91275
+ }
91276
+ return parts.join("; ");
91277
+ }
91278
+ function missingSessionCookies(jar2) {
91279
+ const cookies = extractCookiesFromJar(jar2);
91280
+ const missing = [];
91281
+ if (!cookies.c_user) missing.push("c_user");
91282
+ if (!cookies.xs) missing.push("xs");
91283
+ if (!cookies.fr) missing.push("fr");
91284
+ if (!cookies.datr) missing.push("datr");
91285
+ return missing;
91286
+ }
91287
+ function defaultFuncsGet(defaultFuncs, url2, jar2) {
91288
+ return defaultFuncs.get(url2, jar2);
91289
+ }
91290
+ async function refreshSessionCookies(ctx, defaultFuncs, options = {}) {
91291
+ const surfaces = options.surfaces || [
91292
+ "https://www.facebook.com/",
91293
+ "https://www.messenger.com/"
91294
+ ];
91295
+ let applied = 0;
91296
+ const errors = [];
91297
+ for (const url2 of surfaces) {
91298
+ try {
91299
+ const res = await defaultFuncsGet(defaultFuncs, url2, ctx.jar);
91300
+ const headers = res && res.headers || {};
91301
+ const setCookie = headers["set-cookie"] || headers["Set-Cookie"];
91302
+ applied += applySetCookie(ctx.jar, setCookie);
91303
+ const embedded = extractCookiesFromBody(res && (res.body ?? res));
91304
+ for (const [name, value] of Object.entries(embedded)) {
91305
+ try {
91306
+ ctx.jar.setCookieSync(`${name}=${value}; domain=.facebook.com; path=/; Secure; SameSite=None`, "https://www.facebook.com");
91307
+ applied++;
91308
+ } catch {
91309
+ }
91310
+ }
91311
+ if (typeof res?.body === "string" && res.body.includes("DTSGInitialData")) {
91312
+ invalidateCometTokens(ctx);
91313
+ }
91314
+ } catch (error2) {
91315
+ errors.push(`${url2}: ${error2 && (error2.message || error2.error || error2)}`);
91316
+ }
91317
+ }
91318
+ const extracted = extractCookies({ jar: ctx.jar });
91319
+ const authenticated = hasAuthenticatedSession(ctx.jar);
91320
+ if (applied > 0) ctx.__lastCookieRefreshAt = Date.now();
91321
+ return { ...extracted, applied, authenticated, errors };
91322
+ }
91323
+ function isAuthFailure(value) {
91324
+ if (value == null) return false;
91325
+ if (typeof value === "number") return AUTH_ERROR_CODES.has(value);
91326
+ if (typeof value === "object") {
91327
+ const code = Number(value.error ?? value.code ?? value.errorCode ?? value.statusCode);
91328
+ if (AUTH_ERROR_CODES.has(code)) return true;
91329
+ const text3 = String(value.error || value.message || value.errorDescription || "");
91330
+ return /not logged in|blocked the login|session (?:has )?expired|requires_reauth|please log in again/i.test(text3);
91331
+ }
91332
+ return false;
91333
+ }
91334
+ async function withSessionRetry(ctx, defaultFuncs, operation, options = {}) {
91335
+ const attempts = Math.max(1, options.attempts ?? 2);
91336
+ let lastError;
91337
+ for (let i2 = 0; i2 < attempts; i2++) {
91338
+ try {
91339
+ const result = await operation();
91340
+ if (isAuthFailure(result)) {
91341
+ lastError = result;
91342
+ noteAuthFailure(ctx);
91343
+ if (i2 === attempts - 1) throw result;
91344
+ if (options.onRecover) options.onRecover({ attempt: i2 + 1, error: result });
91345
+ await repairSession(ctx, defaultFuncs);
91346
+ continue;
90537
91347
  }
91348
+ resetBreaker(ctx);
91349
+ return result;
91350
+ } catch (error2) {
91351
+ lastError = error2;
91352
+ if (!isAuthFailure(error2) || i2 === attempts - 1) throw error2;
91353
+ noteAuthFailure(ctx);
91354
+ if (options.onRecover) options.onRecover({ attempt: i2 + 1, error: error2 });
91355
+ await repairSession(ctx, defaultFuncs);
90538
91356
  }
91357
+ }
91358
+ throw lastError || new Error("Operation failed after session retries.");
91359
+ }
91360
+ async function repairSession(ctx, defaultFuncs) {
91361
+ invalidateCometTokens(ctx);
91362
+ let ok = false;
91363
+ try {
91364
+ const refresh = await refreshSessionCookies(ctx, defaultFuncs);
91365
+ ok = refresh.authenticated;
90539
91366
  } catch {
91367
+ ok = false;
91368
+ }
91369
+ if (typeof ctx.__resetMqttBackoff === "function") {
91370
+ try {
91371
+ ctx.__resetMqttBackoff();
91372
+ } catch {
91373
+ }
90540
91374
  }
91375
+ return ok;
91376
+ }
91377
+ function scheduleSessionKeepAlive(ctx, defaultFuncs, intervalMs = 15 * 60 * 1e3) {
91378
+ if (ctx.__cookieKeepAliveTimer) {
91379
+ clearInterval(ctx.__cookieKeepAliveTimer);
91380
+ ctx.__cookieKeepAliveTimer = null;
91381
+ }
91382
+ const jitter = () => intervalMs * (0.85 + Math.random() * 0.3);
91383
+ let stopped = false;
91384
+ const tick = async () => {
91385
+ if (stopped || ctx.loggedIn === false) return;
91386
+ try {
91387
+ await refreshSessionCookies(ctx, defaultFuncs);
91388
+ } catch {
91389
+ } finally {
91390
+ if (!stopped) ctx.__cookieKeepAliveTimer = setTimeout(tick, jitter());
91391
+ }
91392
+ };
91393
+ ctx.__cookieKeepAliveTimer = setTimeout(tick, jitter());
91394
+ return () => {
91395
+ stopped = true;
91396
+ if (ctx.__cookieKeepAliveTimer) {
91397
+ clearTimeout(ctx.__cookieKeepAliveTimer);
91398
+ ctx.__cookieKeepAliveTimer = null;
91399
+ }
91400
+ };
91401
+ }
91402
+
91403
+ // src/utils/index.ts
91404
+ init_pacing();
91405
+
91406
+ // src/utils/warmup.ts
91407
+ init_pacing();
91408
+ var SURFACES = [
91409
+ "https://www.facebook.com/",
91410
+ "https://www.facebook.com/messages/t/",
91411
+ "https://www.messenger.com/"
91412
+ ];
91413
+ async function warmUpSession(ctx, getter, options = {}) {
91414
+ const visited = [];
91415
+ const errors = [];
91416
+ let cookiesApplied = 0;
91417
+ let tokensSeeded = false;
91418
+ if (!hasAuthenticatedSession(ctx.jar)) {
91419
+ return { visited, cookiesApplied, authenticated: false, tokensSeeded, errors: ["no authenticated session cookies"] };
91420
+ }
91421
+ const surfaces = options.includeMessenger === false ? SURFACES.slice(0, 2) : SURFACES;
91422
+ for (const url2 of surfaces) {
91423
+ try {
91424
+ const res = await getter(url2, ctx.jar, null, ctx.globalOptions, ctx, { noRef: true });
91425
+ visited.push(url2);
91426
+ const headers = res && res.headers || {};
91427
+ cookiesApplied += applySetCookie(ctx.jar, headers["set-cookie"] || headers["Set-Cookie"]);
91428
+ const html3 = typeof res === "string" ? res : res && res.body;
91429
+ if (typeof html3 === "string" && html3.includes("DTSGInitialData")) {
91430
+ const lsd = extractLsd(html3);
91431
+ const dtsg = extractDtsg(html3);
91432
+ if (lsd && dtsg) {
91433
+ ctx.__cometTokens = { lsd, fb_dtsg: dtsg, fetchedAt: Date.now(), failures: 0 };
91434
+ ctx.lsd = lsd;
91435
+ ctx.fb_dtsg = dtsg;
91436
+ ctx.jazoest = "2" + Array.from(dtsg).reduce((a, b) => a + b.charCodeAt(0), 0);
91437
+ const spin = extractSpin(html3);
91438
+ if (Object.keys(spin).length) ctx.__spin = { ...ctx.__spin || {}, ...spin };
91439
+ if (spin.__rev) ctx.revision = spin.__rev;
91440
+ tokensSeeded = true;
91441
+ }
91442
+ } else if (url2.includes("/messages")) {
91443
+ invalidateCometTokens(ctx);
91444
+ }
91445
+ await sleep(humanDelay(650, 420));
91446
+ } catch (error2) {
91447
+ errors.push(`${url2}: ${error2 && (error2.message || error2.error || error2)}`);
91448
+ }
91449
+ }
91450
+ const extracted = extractCookies({ jar: ctx.jar });
91451
+ return {
91452
+ visited,
91453
+ cookiesApplied,
91454
+ authenticated: hasAuthenticatedSession(ctx.jar),
91455
+ tokensSeeded,
91456
+ errors: [...errors, ...extracted.count ? [] : ["no cookies extracted"]]
91457
+ };
91458
+ }
91459
+
91460
+ // src/utils/index.ts
91461
+ init_safety();
91462
+
91463
+ // src/utils/liveness.ts
91464
+ init_pacing();
91465
+ init_safety();
91466
+ var ACTIVE_MIN_MS = 6 * 60 * 1e3;
91467
+ var ACTIVE_MAX_MS = 14 * 60 * 1e3;
91468
+ var IDLE_MIN_MS = 2 * 60 * 1e3;
91469
+ var IDLE_MAX_MS = 7 * 60 * 1e3;
91470
+ function randBetween(min, max) {
91471
+ return Math.floor(min + Math.random() * (max - min));
91472
+ }
91473
+ function startLiveness(ctx, options = {}) {
91474
+ if (ctx.__livenessStop) {
91475
+ try {
91476
+ ctx.__livenessStop();
91477
+ } catch {
91478
+ }
91479
+ }
91480
+ ctx.__requestsPaced = ctx.__requestsPaced || 0;
91481
+ let stopped = false;
91482
+ let active = true;
91483
+ let nextAt = Date.now() + randBetween(ACTIVE_MIN_MS, ACTIVE_MAX_MS);
91484
+ let timer = null;
91485
+ ctx.__foreground = true;
91486
+ const schedule = () => {
91487
+ if (stopped) return;
91488
+ const wait = Math.max(1e3, nextAt - Date.now());
91489
+ timer = setTimeout(tick, wait);
91490
+ if (timer && typeof timer.unref === "function") timer.unref();
91491
+ };
91492
+ const tick = () => {
91493
+ if (stopped) return;
91494
+ active = !active;
91495
+ ctx.__foreground = active ? !!ctx.globalOptions?.online : false;
91496
+ try {
91497
+ if (active) options.foregroundPing?.();
91498
+ else options.backgroundPing?.();
91499
+ } catch {
91500
+ }
91501
+ nextAt = Date.now() + (active ? randBetween(ACTIVE_MIN_MS, ACTIVE_MAX_MS) : randBetween(IDLE_MIN_MS, IDLE_MAX_MS));
91502
+ schedule();
91503
+ };
91504
+ schedule();
91505
+ const stop = () => {
91506
+ stopped = true;
91507
+ if (timer) {
91508
+ clearTimeout(timer);
91509
+ timer = null;
91510
+ }
91511
+ ctx.__livenessStop = null;
91512
+ };
91513
+ ctx.__livenessStop = stop;
91514
+ return {
91515
+ stop,
91516
+ state: () => ({
91517
+ active,
91518
+ nextTransitionMs: Math.max(0, nextAt - Date.now()),
91519
+ requests: ctx.__requestsPaced || 0,
91520
+ breakerOpen: isBreakerOpen(ctx)
91521
+ })
91522
+ };
91523
+ }
91524
+ function canActProactively(ctx) {
91525
+ if (isBreakerOpen(ctx)) return false;
91526
+ if (ctx.__foreground === false) return false;
91527
+ return true;
91528
+ }
91529
+ async function awaitProactiveSlot(ctx, maxWaitMs = 15 * 60 * 1e3) {
91530
+ const deadline = Date.now() + maxWaitMs;
91531
+ while (Date.now() < deadline) {
91532
+ if (canActProactively(ctx)) return true;
91533
+ await sleep(humanDelay(4e3, 3e3));
91534
+ }
91535
+ return false;
90541
91536
  }
90542
91537
 
90543
91538
  // src/utils/index.ts
@@ -90569,19 +91564,32 @@ async function json2(url2, jar2, qs2, options, ctx, customHeader) {
90569
91564
  }
90570
91565
  }
90571
91566
  function makeDefaults(html3, userID, ctx) {
90572
- let reqCounter = 1;
90573
91567
  const revision = getFrom(html3, 'revision":', ",");
90574
91568
  function mergeWithDefaults(obj) {
91569
+ const reqId = (() => {
91570
+ ctx.__reqCounter = (typeof ctx.__reqCounter === "number" ? ctx.__reqCounter : 0) + 1;
91571
+ return ctx.__reqCounter.toString(36);
91572
+ })();
91573
+ const spin = ctx.__spin || {};
90575
91574
  const newObj = {
90576
91575
  av: userID,
90577
91576
  __user: userID,
90578
- __req: (reqCounter++).toString(36),
90579
- __rev: revision,
91577
+ __req: reqId,
91578
+ __rev: ctx.revision || revision,
90580
91579
  __a: 1,
90581
91580
  ...ctx && {
90582
91581
  fb_dtsg: ctx.fb_dtsg,
90583
91582
  jazoest: ctx.jazoest
90584
- }
91583
+ },
91584
+ // The Comet document token and its spin siblings gate GraphQL; include
91585
+ // them whenever they are known so no module has to remember.
91586
+ ...ctx && ctx.lsd ? { lsd: ctx.lsd } : {},
91587
+ ...spin.__spin_b ? { __spin_b: spin.__spin_b } : {},
91588
+ ...spin.__spin_r ? { __spin_r: spin.__spin_r } : {},
91589
+ ...spin.__spin_t ? { __spin_t: spin.__spin_t } : {},
91590
+ // Device pixel ratio must match the Client Hints profile the headers
91591
+ // advertise, otherwise the form and the headers disagree.
91592
+ ...getFingerprintParams(ctx?.globalOptions)
90585
91593
  };
90586
91594
  if (!obj) return newObj;
90587
91595
  for (const prop2 in obj) {
@@ -90592,13 +91600,18 @@ function makeDefaults(html3, userID, ctx) {
90592
91600
  return newObj;
90593
91601
  }
90594
91602
  return {
90595
- get: (url2, jar2, qs2, ctxx, customHeader = {}) => get(url2, jar2, mergeWithDefaults(qs2), ctx.globalOptions, ctxx || ctx, customHeader),
91603
+ // GET carries only caller-supplied query parameters. The shared form
91604
+ // defaults (av/__user/fb_dtsg/jazoest/lsd/…) are a POST body and must never
91605
+ // be appended to a document URL: Facebook treats a document GET that
91606
+ // carries form state as an AJAX call and answers with a 1357004 JSON error
91607
+ // instead of the page, which is exactly the "stale token" symptom.
91608
+ get: (url2, jar2, qs2, ctxx, customHeader = {}) => get(url2, jar2, qs2, ctx.globalOptions, ctxx || ctx, customHeader),
90596
91609
  post: (url2, jar2, form, ctxx, customHeader = {}) => post(url2, jar2, mergeWithDefaults(form), ctx.globalOptions, ctxx || ctx, customHeader),
90597
91610
  postFormData: (url2, jar2, form, qs2, ctxx, customHeader) => postFormData(
90598
91611
  url2,
90599
91612
  jar2,
90600
91613
  mergeWithDefaults(form),
90601
- mergeWithDefaults(qs2),
91614
+ qs2,
90602
91615
  ctx.globalOptions,
90603
91616
  ctxx || ctx,
90604
91617
  customHeader
@@ -90622,7 +91635,19 @@ async function setOptions(globalOptions, options = {}) {
90622
91635
  listenEvents: (value) => globalOptions.listenEvents = Boolean(value),
90623
91636
  updatePresence: (value) => globalOptions.updatePresence = Boolean(value),
90624
91637
  forceLogin: (value) => globalOptions.forceLogin = Boolean(value),
90625
- userAgent: (value) => globalOptions.userAgent = value,
91638
+ userAgent: (value) => {
91639
+ globalOptions.userAgent = value;
91640
+ globalOptions.browser = normalizeBrowserProfile({
91641
+ ...globalOptions.browser || defaultBrowserProfile,
91642
+ userAgent: value
91643
+ });
91644
+ },
91645
+ browser: (value) => {
91646
+ if (!value || typeof value !== "object") return;
91647
+ const profile = normalizeBrowserProfile(value);
91648
+ globalOptions.browser = profile;
91649
+ globalOptions.userAgent = profile.userAgent;
91650
+ },
90626
91651
  autoMarkDelivery: (value) => globalOptions.autoMarkDelivery = Boolean(value),
90627
91652
  autoMarkRead: (value) => globalOptions.autoMarkRead = Boolean(value),
90628
91653
  listenTyping: (value) => globalOptions.listenTyping = Boolean(value),
@@ -90640,8 +91665,9 @@ async function setOptions(globalOptions, options = {}) {
90640
91665
  randomUserAgent(value) {
90641
91666
  globalOptions.randomUserAgent = Boolean(value);
90642
91667
  if (value) {
90643
- const ua = randomUserAgent();
90644
- globalOptions.userAgent = ua.userAgent;
91668
+ const profile = randomUserAgent();
91669
+ globalOptions.browser = profile;
91670
+ globalOptions.userAgent = profile.userAgent;
90645
91671
  }
90646
91672
  },
90647
91673
  bypassRegion(value) {
@@ -90659,7 +91685,20 @@ async function setOptions(globalOptions, options = {}) {
90659
91685
  // src/core/models/buildAPI.ts
90660
91686
  async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRetrievingMsg) {
90661
91687
  const userID = (() => {
90662
- const cookies = jar2.getCookiesSync(fbLinkFunc());
91688
+ const origins = [
91689
+ "https://www.facebook.com",
91690
+ "https://facebook.com",
91691
+ "https://web.facebook.com",
91692
+ "https://mbasic.facebook.com",
91693
+ "https://www.messenger.com"
91694
+ ];
91695
+ let cookies = [];
91696
+ for (const origin2 of origins) {
91697
+ try {
91698
+ cookies = cookies.concat(jar2.getCookiesSync(origin2) || []);
91699
+ } catch {
91700
+ }
91701
+ }
90663
91702
  const primaryProfile = cookies.find(
90664
91703
  (val2) => val2.cookieString().startsWith("c_user=")
90665
91704
  );
@@ -90667,6 +91706,13 @@ async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRe
90667
91706
  (val2) => val2.cookieString().startsWith("i_user=")
90668
91707
  );
90669
91708
  if (!primaryProfile && !secondaryProfile) {
91709
+ const hasXs = cookies.some((val2) => val2.cookieString().startsWith("xs="));
91710
+ const hasDatr = cookies.some((val2) => val2.cookieString().startsWith("datr="));
91711
+ if (hasXs || hasDatr) {
91712
+ throw new Error(
91713
+ "Facebook session expired or invalid (cookies present but no c_user). Export a fresh appState from a logged-in browser and try again."
91714
+ );
91715
+ }
90670
91716
  throw new Error(errorRetrievingMsg);
90671
91717
  }
90672
91718
  return secondaryProfile?.cookieString().split("=")[1] || primaryProfile.cookieString().split("=")[1];
@@ -90691,7 +91737,7 @@ async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRe
90691
91737
  return null;
90692
91738
  };
90693
91739
  const dtsgData = findConfig("DTSGInitialData");
90694
- const dtsg = dtsgData ? dtsgData.token : getFrom(html3, '"token":"', '"');
91740
+ const dtsg = dtsgData ? dtsgData.token : extractDtsg(html3) || getFrom(html3, '"token":"', '"');
90695
91741
  if (typeof dtsg !== "string" || dtsg.length === 0) {
90696
91742
  throw new Error("Unable to retrieve Facebook form security token (fb_dtsg).");
90697
91743
  }
@@ -90702,6 +91748,10 @@ async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRe
90702
91748
  0
90703
91749
  )}`
90704
91750
  };
91751
+ const lsdConfig = findConfig("LSD");
91752
+ const lsd = lsdConfig && lsdConfig.token || extractLsd(html3) || void 0;
91753
+ const spin = extractSpin(html3);
91754
+ const revision = spin.__rev || getFrom(html3, 'revision":', ",").trim();
90705
91755
  const clientIDData = findConfig("MqttWebDeviceID");
90706
91756
  const clientID = clientIDData ? clientIDData.clientID : void 0;
90707
91757
  const mqttConfigData = findConfig("MqttWebConfig");
@@ -90740,8 +91790,14 @@ async function buildAPI(html3, jar2, netData, globalOptions, fbLinkFunc, errorRe
90740
91790
  callback_Task: {},
90741
91791
  region,
90742
91792
  firstListen: true,
90743
- ...dtsgResult
91793
+ ...dtsgResult,
91794
+ ...lsd ? { lsd } : {},
91795
+ ...Object.keys(spin).length ? { __spin: spin } : {},
91796
+ ...revision ? { revision } : {}
90744
91797
  };
91798
+ if (lsd && dtsg) {
91799
+ ctx.__cometTokens = { lsd, fb_dtsg: dtsg, fetchedAt: Date.now(), failures: 0 };
91800
+ }
90745
91801
  const defaultFuncs = makeDefaults(html3, userID, ctx);
90746
91802
  return [ctx, defaultFuncs, {}];
90747
91803
  }
@@ -91015,29 +92071,78 @@ var getBotInitialData_default = (defaultFuncs, api, ctx) => {
91015
92071
  };
91016
92072
  }
91017
92073
  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;
92074
+ const locale = (ctx.globalOptions?.browser?.language || "en-US").replace("-", "_");
92075
+ const url2 = `https://www.facebook.com/profile.php?id=${ctx.userID}&sk=about&locale=${locale}`;
92076
+ api.httpGet(
92077
+ url2,
92078
+ null,
92079
+ {},
92080
+ (err, data2) => {
92081
+ if (err) return callback(err);
92082
+ try {
92083
+ const accountJson = extractCurrentUser(data2);
92084
+ if (accountJson) {
92085
+ return callback(null, {
92086
+ ...accountJson,
92087
+ name: accountJson.NAME ?? accountJson.name,
92088
+ uid: accountJson.USER_ID ?? accountJson.userID ?? ctx.userID
92089
+ });
92090
+ }
91030
92091
  return callback(null, {
91031
- ...accountJson
92092
+ error: "Something went wrong. Maybe its possible that it has a limitation due to spam requests. You can try again later."
91032
92093
  });
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);
92094
+ } catch (e) {
92095
+ return callback(e);
92096
+ }
92097
+ },
92098
+ true
92099
+ );
91038
92100
  return returnPromise;
91039
92101
  };
91040
92102
  };
92103
+ function extractCurrentUser(html3) {
92104
+ if (typeof html3 !== "string") return null;
92105
+ const marker = '"CurrentUserInitialData",[],';
92106
+ const markerIndex = html3.indexOf(marker);
92107
+ const anchor = markerIndex >= 0 ? markerIndex + marker.length : html3.indexOf('"CurrentUserInitialData"');
92108
+ if (anchor < 0) return null;
92109
+ const start = html3.indexOf("{", anchor);
92110
+ if (start < 0) return null;
92111
+ let depth = 0;
92112
+ let inString = false;
92113
+ let escaped = false;
92114
+ for (let i2 = start; i2 < html3.length; i2++) {
92115
+ const ch = html3[i2];
92116
+ if (inString) {
92117
+ if (escaped) {
92118
+ escaped = false;
92119
+ } else if (ch === "\\") {
92120
+ escaped = true;
92121
+ } else if (ch === '"') {
92122
+ inString = false;
92123
+ }
92124
+ continue;
92125
+ }
92126
+ if (ch === '"') {
92127
+ inString = true;
92128
+ } else if (ch === "{") {
92129
+ depth++;
92130
+ } else if (ch === "}") {
92131
+ depth--;
92132
+ if (depth === 0) {
92133
+ try {
92134
+ const parsed = JSON.parse(html3.slice(start, i2 + 1));
92135
+ parsed.name = parsed.NAME;
92136
+ parsed.uid = parsed.USER_ID;
92137
+ return parsed;
92138
+ } catch {
92139
+ return null;
92140
+ }
92141
+ }
92142
+ }
92143
+ }
92144
+ return null;
92145
+ }
91041
92146
 
91042
92147
  // src/deltas/apis/login/logout.ts
91043
92148
  function logout_default(defaultFuncs, api, ctx) {
@@ -91047,6 +92152,13 @@ function logout_default(defaultFuncs, api, ctx) {
91047
92152
  if (ctx.globalOptions) {
91048
92153
  ctx.globalOptions.autoReconnect = false;
91049
92154
  }
92155
+ if (typeof ctx.__stopCookieKeepAlive === "function") {
92156
+ try {
92157
+ ctx.__stopCookieKeepAlive();
92158
+ } catch {
92159
+ }
92160
+ ctx.__stopCookieKeepAlive = null;
92161
+ }
91050
92162
  if (ctx.presenceInterval) {
91051
92163
  clearInterval(ctx.presenceInterval);
91052
92164
  ctx.presenceInterval = null;
@@ -93098,7 +94210,7 @@ init_constants();
93098
94210
  var SEARCH_DOC_ID = "23943555345255534";
93099
94211
  var SEARCH_FRIENDLY_NAME = "StoriesCreateMusicSelectorMainPageQuery";
93100
94212
  var GRAPHQL_URL = "https://www.facebook.com/api/graphql/";
93101
- var PRODUCT = "FB_COMPOSER";
94213
+ var PRODUCT = "FB_CAMERA";
93102
94214
  function textOf(node) {
93103
94215
  if (node == null) return "";
93104
94216
  if (typeof node === "string") return node;
@@ -93156,6 +94268,10 @@ function collectTracks(payload) {
93156
94268
  }
93157
94269
 
93158
94270
  // src/deltas/apis/music/searchMusic.ts
94271
+ function nextRequestId(ctx) {
94272
+ ctx.__reqCounter = (typeof ctx.__reqCounter === "number" ? ctx.__reqCounter : 0) + 1;
94273
+ return ctx.__reqCounter.toString(36);
94274
+ }
93159
94275
  function normalizeError(error2) {
93160
94276
  if (!error2 || typeof error2 !== "object") {
93161
94277
  const message2 = String(error2);
@@ -93177,32 +94293,53 @@ function normalizeError(error2) {
93177
94293
  }
93178
94294
  function searchMusic_default(defaultFuncs, _api, ctx) {
93179
94295
  async function runSearch(text3, count, selectedOptions, callback) {
93180
- await ensureCometTokens(ctx, defaultFuncs);
93181
94296
  const params = { first: count };
93182
94297
  if (text3) params.search_text = text3;
93183
94298
  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));
94299
+ const attempt = async (forceRefresh) => {
94300
+ await ensureCometTokens(ctx, defaultFuncs, forceRefresh);
94301
+ const form = {
94302
+ av: ctx.userID,
94303
+ __user: ctx.userID,
94304
+ __a: "1",
94305
+ __req: nextRequestId(ctx),
94306
+ fb_api_caller_class: "RelayModern",
94307
+ fb_api_req_friendly_name: SEARCH_FRIENDLY_NAME,
94308
+ doc_id: SEARCH_DOC_ID,
94309
+ variables: JSON.stringify({
94310
+ params,
94311
+ product: selectedOptions.product || PRODUCT
94312
+ }),
94313
+ server_timestamps: "true"
94314
+ };
94315
+ if (ctx.fb_dtsg) form.fb_dtsg = ctx.fb_dtsg;
94316
+ if (ctx.jazoest) form.jazoest = ctx.jazoest;
94317
+ if (ctx.lsd) form.lsd = ctx.lsd;
94318
+ const spin = ctx.__spin || {};
94319
+ if (spin.__spin_b) form.__spin_b = spin.__spin_b;
94320
+ if (spin.__spin_r) form.__spin_r = spin.__spin_r;
94321
+ if (spin.__spin_t) form.__spin_t = spin.__spin_t;
94322
+ if (ctx.revision) form.__rev = ctx.revision;
94323
+ const customHeader = {};
94324
+ if (ctx.lsd) customHeader["X-Fb-Lsd"] = ctx.lsd;
94325
+ customHeader["X-Fb-Friendly-Name"] = SEARCH_FRIENDLY_NAME;
94326
+ const raw = await defaultFuncs.post(GRAPHQL_URL, ctx.jar, form, ctx, customHeader).then(parseAndCheckLogin(ctx, defaultFuncs));
94327
+ return raw;
94328
+ };
94329
+ let parsed = await attempt(false);
94330
+ if (isStaleTokenError(parsed)) {
94331
+ invalidateCometTokens(ctx);
94332
+ parsed = await attempt(true);
94333
+ }
93205
94334
  if (!parsed) throw { error: "searchMusic returned empty object.", code: "BAD_RESPONSE" };
94335
+ if (isStaleTokenError(parsed)) {
94336
+ throw {
94337
+ error: parsed.error,
94338
+ errorSummary: parsed.errorSummary,
94339
+ errorDescription: parsed.errorDescription,
94340
+ code: "STALE_TOKEN"
94341
+ };
94342
+ }
93206
94343
  if (parsed.error) {
93207
94344
  throw {
93208
94345
  error: parsed.error,
@@ -93224,6 +94361,20 @@ function searchMusic_default(defaultFuncs, _api, ctx) {
93224
94361
  const page = collectTracks(parsed);
93225
94362
  const tracks = page.tracks.slice(0, count);
93226
94363
  if (tracks.length === 0) {
94364
+ invalidateCometTokens(ctx);
94365
+ const retried = await attempt(true);
94366
+ if (!isStaleTokenError(retried) && !retried.error && !(retried.errors || []).length) {
94367
+ const retryPage = collectTracks(retried);
94368
+ const retryTracks = retryPage.tracks.slice(0, count);
94369
+ if (retryTracks.length) {
94370
+ const result2 = retryTracks.slice();
94371
+ result2.tracks = retryTracks;
94372
+ result2.endCursor = retryPage.endCursor;
94373
+ result2.hasNextPage = retryPage.hasNextPage;
94374
+ result2.query = text3;
94375
+ return result2;
94376
+ }
94377
+ }
93227
94378
  throw {
93228
94379
  error: `No music results found for "${text3}". The Facebook music catalog may be unavailable for this account or region.`,
93229
94380
  code: "NO_RESULTS",
@@ -93507,8 +94658,9 @@ function connectLightspeed(ctx, globalCallback) {
93507
94658
  const chatOn = ctx.globalOptions.online;
93508
94659
  const foreground = false;
93509
94660
  const sessionID = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1;
93510
- const cookies = ctx.jar.getCookiesSync("https://www.facebook.com").join("; ");
94661
+ const cookies = collectSessionCookies(ctx, "https://gateway.facebook.com");
93511
94662
  const cid = ctx.clientID;
94663
+ const appId = ctx.mqttAppID || ctx.appID || "2220391788200892";
93512
94664
  const username = {
93513
94665
  u: ctx.userID,
93514
94666
  s: sessionID,
@@ -93516,7 +94668,7 @@ function connectLightspeed(ctx, globalCallback) {
93516
94668
  fg: foreground,
93517
94669
  d: cid,
93518
94670
  ct: "websocket",
93519
- aid: "2220391788200892",
94671
+ aid: appId,
93520
94672
  mqtt_sid: "",
93521
94673
  cp: 3,
93522
94674
  ecp: 10,
@@ -93526,10 +94678,12 @@ function connectLightspeed(ctx, globalCallback) {
93526
94678
  no_auto_fg: true,
93527
94679
  gas: null,
93528
94680
  pack: [],
93529
- a: ctx.globalOptions.userAgent
94681
+ a: ctx.globalOptions.userAgent || defaultBrowserProfile.userAgent,
94682
+ vi: "3",
94683
+ lc: "en_US"
93530
94684
  };
93531
94685
  const queryParams = new URLSearchParams({
93532
- "x-dgw-appid": "2220391788200892",
94686
+ "x-dgw-appid": appId,
93533
94687
  "x-dgw-appversion": "0",
93534
94688
  "x-dgw-authtype": "1:0",
93535
94689
  "x-dgw-version": "5",
@@ -93540,6 +94694,7 @@ function connectLightspeed(ctx, globalCallback) {
93540
94694
  "x-dgw-deviceid": ctx.clientID
93541
94695
  });
93542
94696
  const host = `wss://gateway.facebook.com/ws/lightspeed?${queryParams.toString()}`;
94697
+ const wsHeaders = getWebSocketHeaders(host, ctx.globalOptions);
93543
94698
  const options = {
93544
94699
  clientId: "mqttwsclient",
93545
94700
  protocolId: "MQIsdp",
@@ -93547,15 +94702,12 @@ function connectLightspeed(ctx, globalCallback) {
93547
94702
  username: JSON.stringify(username),
93548
94703
  clean: true,
93549
94704
  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
- }
94705
+ headers: { ...wsHeaders, Cookie: cookies },
94706
+ origin: wsHeaders.Origin,
94707
+ protocolVersion: 13,
94708
+ binaryType: "arraybuffer"
93557
94709
  },
93558
- keepalive: 10,
94710
+ keepalive: 10 + Math.floor(Math.random() * 10),
93559
94711
  reconnectPeriod: 0
93560
94712
  };
93561
94713
  if (ctx.globalOptions.proxy) {
@@ -93607,9 +94759,9 @@ function connectLightspeed(ctx, globalCallback) {
93607
94759
  }
93608
94760
  function reconnect(retryCount) {
93609
94761
  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);
94762
+ const delay3 = retryDelay(retryCount, 4e3, 12e4);
94763
+ log(`[Lightspeed] Reconnecting in ${(delay3 / 1e3).toFixed(1)} seconds...`);
94764
+ reconnectTimer = setTimeout(() => startConnection(retryCount + 1), delay3);
93613
94765
  }
93614
94766
  startConnection();
93615
94767
  return {
@@ -98633,11 +99785,15 @@ function themeQuery_default(defaultFuncs, _api, ctx) {
98633
99785
  doc_id: "24474714052117636"
98634
99786
  };
98635
99787
  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));
99788
+ const resData = await withCometTokens(
99789
+ ctx,
99790
+ defaultFuncs,
99791
+ () => defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form, null, {
99792
+ "x-fb-friendly-name": "MWPThreadThemeQuery_AllThemesQuery",
99793
+ "x-fb-lsd": ctx.lsd,
99794
+ referer
99795
+ }).then(parseAndCheckLogin(ctx, defaultFuncs))
99796
+ );
98641
99797
  if (resData?.errors) {
98642
99798
  throw new Error(JSON.stringify(resData.errors));
98643
99799
  }
@@ -98678,6 +99834,7 @@ function getHealthStatus_default(_defaultFuncs, _api, ctx) {
98678
99834
  return function getHealthStatus() {
98679
99835
  const mqtt3 = ctx.mqttClient;
98680
99836
  const connected = !!mqtt3 && (typeof mqtt3.connected === "boolean" ? mqtt3.connected : mqtt3.readyState === 1 || !!(mqtt3.stream && !mqtt3.stream.destroyed));
99837
+ const safety = typeof ctx.__safetySnapshot === "function" ? ctx.__safetySnapshot() : null;
98681
99838
  return {
98682
99839
  userID: ctx.userID || null,
98683
99840
  loggedIn: !!ctx.userID,
@@ -98688,8 +99845,13 @@ function getHealthStatus_default(_defaultFuncs, _api, ctx) {
98688
99845
  lastMessageAt: ctx.__mqttLastMessageAt || null
98689
99846
  },
98690
99847
  antiSuspension: {
98691
- enabled: false,
98692
- circuitBreakerOpen: false
99848
+ enabled: true,
99849
+ // The breaker is open when Facebook has signalled it is unhappy and
99850
+ // the session is deliberately pausing rather than risking a lockdown.
99851
+ circuitBreakerOpen: safety ? !safety.closed : false,
99852
+ reason: safety ? safety.reason : void 0,
99853
+ cooldownRemainingMs: safety ? safety.cooldownRemainingMs : 0,
99854
+ requestsInWindow: safety ? safety.requestsInWindow : 0
98693
99855
  },
98694
99856
  uptimeMs: typeof ctx.__startedAt === "number" ? Date.now() - ctx.__startedAt : null,
98695
99857
  timestamp: Date.now()
@@ -98750,7 +99912,6 @@ function getFriendsList_default(defaultFuncs, api, ctx) {
98750
99912
 
98751
99913
  // src/deltas/apis/mqtt/realtime.ts
98752
99914
  var import_undici = __toESM(require_undici());
98753
- var import_https_proxy_agent3 = __toESM(require_dist3());
98754
99915
  function formatNotification(data2) {
98755
99916
  if (!data2.data || !data2.data.viewer) return null;
98756
99917
  const notifEdge = data2.data.viewer.notifications_page?.edges?.[1]?.node?.notif;
@@ -98765,6 +99926,31 @@ function formatNotification(data2) {
98765
99926
  seenState: notifEdge.seen_state
98766
99927
  };
98767
99928
  }
99929
+ function collectRealtimeCookies(ctx) {
99930
+ const origins = [
99931
+ "https://www.facebook.com",
99932
+ "https://facebook.com",
99933
+ "https://www.messenger.com",
99934
+ "https://gateway.facebook.com"
99935
+ ];
99936
+ const seen = {};
99937
+ const parts = [];
99938
+ for (const origin2 of origins) {
99939
+ let list = [];
99940
+ try {
99941
+ list = ctx.jar.getCookiesSync(origin2) || [];
99942
+ } catch {
99943
+ list = [];
99944
+ }
99945
+ for (const cookie of list) {
99946
+ const name = cookie?.key;
99947
+ if (!name || seen[name]) continue;
99948
+ seen[name] = true;
99949
+ parts.push(cookie.cookieString());
99950
+ }
99951
+ }
99952
+ return parts.join("; ");
99953
+ }
98768
99954
  function realtime_default(defaultFuncs, api, ctx) {
98769
99955
  return function listenRealtime() {
98770
99956
  const emitter = new EventEmitter2();
@@ -98772,6 +99958,7 @@ function realtime_default(defaultFuncs, api, ctx) {
98772
99958
  let reconnectTimeout;
98773
99959
  let keepAliveInterval;
98774
99960
  let stopped = false;
99961
+ let retries = 0;
98775
99962
  const subscriptions = [
98776
99963
  '{"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
99964
  '{"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 +100010,9 @@ function realtime_default(defaultFuncs, api, ctx) {
98823
100010
  async function connect() {
98824
100011
  if (stopped) return;
98825
100012
  try {
100013
+ const appId = ctx.mqttAppID || ctx.appID || "2220391788200892";
98826
100014
  const queryParams = new URLSearchParams({
98827
- "x-dgw-appid": "2220391788200892",
100015
+ "x-dgw-appid": String(appId),
98828
100016
  "x-dgw-appversion": "0",
98829
100017
  "x-dgw-authtype": "1:0",
98830
100018
  "x-dgw-version": "5",
@@ -98834,23 +100022,22 @@ function realtime_default(defaultFuncs, api, ctx) {
98834
100022
  "x-dgw-app-stream-group": "group1"
98835
100023
  });
98836
100024
  const url2 = `wss://gateway.facebook.com/ws/realtime?${queryParams.toString()}`;
98837
- const cookies = ctx.jar.getCookiesSync("https://www.facebook.com").join("; ");
100025
+ const cookies = collectRealtimeCookies(ctx);
100026
+ const wsHeaders = getWebSocketHeaders(url2, ctx.globalOptions, ctx);
98838
100027
  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"
100028
+ ...wsHeaders,
100029
+ "Referer": "https://www.facebook.com/friends",
100030
+ "Cookie": cookies
98846
100031
  };
98847
100032
  const wsOptions = { headers: baseHeaders };
98848
100033
  if (ctx.globalOptions.proxy) {
98849
- wsOptions.agent = new import_https_proxy_agent3.HttpsProxyAgent(ctx.globalOptions.proxy);
100034
+ const { ProxyAgent } = await Promise.resolve().then(() => __toESM(require_undici()));
100035
+ wsOptions.dispatcher = new ProxyAgent(ctx.globalOptions.proxy);
98850
100036
  }
98851
100037
  ws2 = new import_undici.WebSocket(url2, wsOptions);
98852
100038
  ws2.onopen = () => {
98853
100039
  log("Connected via undici.WebSocket");
100040
+ retries = 0;
98854
100041
  subscriptions.forEach((payload, index3) => {
98855
100042
  const prefix = Buffer.from([14, index3, 0, payload.length]);
98856
100043
  const suffix = Buffer.from([0, 0]);
@@ -98882,7 +100069,7 @@ function realtime_default(defaultFuncs, api, ctx) {
98882
100069
  clearInterval(keepAliveInterval);
98883
100070
  keepAliveInterval = void 0;
98884
100071
  clearTimeout(reconnectTimeout);
98885
- reconnectTimeout = setTimeout(connect, 1e3);
100072
+ reconnectTimeout = setTimeout(connect, retryDelay(++retries, 2e3, 6e4));
98886
100073
  };
98887
100074
  } catch (err) {
98888
100075
  if (stopped) return;
@@ -98890,7 +100077,7 @@ function realtime_default(defaultFuncs, api, ctx) {
98890
100077
  emitter.emit("error", err);
98891
100078
  clearInterval(keepAliveInterval);
98892
100079
  clearTimeout(reconnectTimeout);
98893
- reconnectTimeout = setTimeout(connect, 1e3);
100080
+ reconnectTimeout = setTimeout(connect, retryDelay(++retries, 2e3, 6e4));
98894
100081
  }
98895
100082
  }
98896
100083
  connect();
@@ -98909,7 +100096,7 @@ function realtime_default(defaultFuncs, api, ctx) {
98909
100096
  // src/deltas/apis/mqtt/listenMqtt.ts
98910
100097
  var import_mqtt2 = __toESM(require_mqtt2());
98911
100098
  var import_websocket_stream2 = __toESM(require_websocket_stream());
98912
- var import_https_proxy_agent4 = __toESM(require_dist3());
100099
+ var import_https_proxy_agent3 = __toESM(require_dist3());
98913
100100
 
98914
100101
  // src/deltas/apis/mqtt/deltas/value.ts
98915
100102
  function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
@@ -99133,9 +100320,15 @@ var MQTT_CONFIG = {
99133
100320
  },
99134
100321
  PROTOCOL_VERSION: 3,
99135
100322
  QOS_LEVEL: 1,
99136
- INITIAL_RETRY_DELAY: 2e3,
99137
- MAX_RETRY_DELAY: 6e4,
99138
- RETRY_MULTIPLIER: 1.6
100323
+ // A dropped socket deserves a quick retry; only a refused handshake
100324
+ // (explicit throttle) gets the long backoff. Both ramps are jittered.
100325
+ INITIAL_RETRY_DELAY: 4e3,
100326
+ MAX_RETRY_DELAY: 3e5,
100327
+ RETRY_MULTIPLIER: 2,
100328
+ // A refused handshake (connack returnCode != 0) means we are being
100329
+ // throttled, not that the network blipped: wait much longer before trying.
100330
+ THROTTLE_DELAY: 9e4,
100331
+ MAX_THROTTLE_DELAY: 9e5
99139
100332
  };
99140
100333
  var SYNC_CONFIG = {
99141
100334
  API_VERSION: 11,
@@ -99144,14 +100337,15 @@ var SYNC_CONFIG = {
99144
100337
  ENCODING: "JSON"
99145
100338
  };
99146
100339
  function buildMqttUsername(ctx, sessionID) {
100340
+ const profile = resolveProfile(ctx.globalOptions);
99147
100341
  return {
99148
100342
  u: ctx.userID,
99149
100343
  s: String(sessionID),
99150
- chat_on: ctx.globalOptions.online,
100344
+ chat_on: !!ctx.globalOptions.online,
99151
100345
  fg: false,
99152
100346
  d: ctx.clientID,
99153
100347
  ct: "websocket",
99154
- aid: ctx.mqttAppID || "218474845183941",
100348
+ aid: ctx.mqttAppID || ctx.appID || "2220391788200892",
99155
100349
  mqtt_sid: "",
99156
100350
  cp: 3,
99157
100351
  ecp: 10,
@@ -99161,13 +100355,14 @@ function buildMqttUsername(ctx, sessionID) {
99161
100355
  no_auto_fg: true,
99162
100356
  gas: null,
99163
100357
  pack: [],
99164
- a: ctx.globalOptions.userAgent,
100358
+ a: profile.userAgent,
99165
100359
  vi: "3",
99166
- lc: "en_US"
100360
+ lc: (profile.language || "en-US").replace("-", "_")
99167
100361
  };
99168
100362
  }
99169
100363
  function buildMqttOptions(ctx, host, username) {
99170
- const cookies = ctx.jar.getCookiesSync("https://www.facebook.com").join("; ");
100364
+ const cookies = collectSessionCookies(ctx, host);
100365
+ const wsHeaders = getWebSocketHeaders(host, ctx.globalOptions);
99171
100366
  const options = {
99172
100367
  clientId: "mqttwsclient",
99173
100368
  protocolId: "MQIsdp",
@@ -99175,14 +100370,8 @@ function buildMqttOptions(ctx, host, username) {
99175
100370
  username: JSON.stringify(username),
99176
100371
  clean: true,
99177
100372
  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",
100373
+ headers: { ...wsHeaders, Cookie: cookies },
100374
+ origin: wsHeaders.Origin,
99186
100375
  protocolVersion: 13,
99187
100376
  binaryType: "arraybuffer"
99188
100377
  },
@@ -99192,7 +100381,7 @@ function buildMqttOptions(ctx, host, username) {
99192
100381
  reconnectPeriod: 0
99193
100382
  };
99194
100383
  if (ctx.globalOptions.proxy) {
99195
- options.wsOptions.agent = new import_https_proxy_agent4.HttpsProxyAgent(ctx.globalOptions.proxy);
100384
+ options.wsOptions.agent = new import_https_proxy_agent3.HttpsProxyAgent(ctx.globalOptions.proxy);
99196
100385
  }
99197
100386
  return options;
99198
100387
  }
@@ -99214,6 +100403,7 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99214
100403
  stopped: false,
99215
100404
  attempts: 0,
99216
100405
  delay: MQTT_CONFIG.INITIAL_RETRY_DELAY,
100406
+ throttleDelay: MQTT_CONFIG.THROTTLE_DELAY,
99217
100407
  generation: 0
99218
100408
  };
99219
100409
  const log2 = (...args) => log(...args);
@@ -99247,13 +100437,36 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99247
100437
  } catch (_3) {
99248
100438
  }
99249
100439
  }
99250
- function scheduleReconnect(reason) {
100440
+ function scheduleReconnect(reason, throttled = false) {
99251
100441
  if (lifecycle.stopped) return;
99252
100442
  if (ctx.loggedIn === false) return;
99253
100443
  if (ctx.globalOptions && ctx.globalOptions.autoReconnect === false) return;
100444
+ if (isBreakerOpen(ctx)) {
100445
+ const wait = Math.min(
100446
+ safetySnapshot(ctx).cooldownRemainingMs || MQTT_CONFIG.THROTTLE_DELAY,
100447
+ MQTT_CONFIG.MAX_THROTTLE_DELAY
100448
+ );
100449
+ clearReconnectTimer();
100450
+ lifecycle.reconnectTimer = setTimeout(() => {
100451
+ lifecycle.reconnectTimer = null;
100452
+ if (lifecycle.stopped || ctx.loggedIn === false) return;
100453
+ start();
100454
+ }, wait);
100455
+ log2(`MQTT ${reason}; safety breaker open, waiting ${(wait / 1e3).toFixed(1)}s`);
100456
+ return;
100457
+ }
99254
100458
  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);
100459
+ let delay3;
100460
+ if (throttled) {
100461
+ delay3 = Math.min(lifecycle.throttleDelay + getJitter(8e3), MQTT_CONFIG.MAX_THROTTLE_DELAY);
100462
+ lifecycle.throttleDelay = Math.min(
100463
+ lifecycle.throttleDelay * MQTT_CONFIG.RETRY_MULTIPLIER,
100464
+ MQTT_CONFIG.MAX_THROTTLE_DELAY
100465
+ );
100466
+ } else {
100467
+ delay3 = Math.min(lifecycle.delay + getJitter(1500), MQTT_CONFIG.MAX_RETRY_DELAY);
100468
+ lifecycle.delay = Math.min(lifecycle.delay * MQTT_CONFIG.RETRY_MULTIPLIER, MQTT_CONFIG.MAX_RETRY_DELAY);
100469
+ }
99257
100470
  lifecycle.attempts++;
99258
100471
  log2(`MQTT ${reason}; reconnecting in ${(delay3 / 1e3).toFixed(1)}s (attempt ${lifecycle.attempts})`);
99259
100472
  lifecycle.reconnectTimer = setTimeout(() => {
@@ -99265,7 +100478,9 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99265
100478
  function resetBackoff() {
99266
100479
  lifecycle.attempts = 0;
99267
100480
  lifecycle.delay = MQTT_CONFIG.INITIAL_RETRY_DELAY;
100481
+ lifecycle.throttleDelay = MQTT_CONFIG.THROTTLE_DELAY;
99268
100482
  }
100483
+ ctx.__resetMqttBackoff = resetBackoff;
99269
100484
  async function fetchSeqId() {
99270
100485
  if (ctx.lastSeqId) return ctx.lastSeqId;
99271
100486
  const form = {
@@ -99332,9 +100547,18 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99332
100547
  ctx.mqttClient = client2;
99333
100548
  let connected = false;
99334
100549
  let closing = false;
100550
+ let throttled = false;
100551
+ let authFailure = false;
99335
100552
  client2.on("error", (err) => {
99336
100553
  ctx.lastMqttError = err;
99337
- error("listenMqtt", new NetworkError(`MQTT connection error: ${err?.message || err}`, { originalError: err, host }));
100554
+ const msg = String(err && err.message || err || "");
100555
+ if (/connection refused|not authorized|server unavailable|bad username|identifier rejected|unacceptable protocol/i.test(msg)) {
100556
+ throttled = true;
100557
+ }
100558
+ if (isAuthFailure && isAuthFailure(err)) {
100559
+ authFailure = true;
100560
+ }
100561
+ error("listenMqtt", new NetworkError(`MQTT connection error: ${msg}`, { originalError: err, host }));
99338
100562
  });
99339
100563
  client2.on("offline", () => {
99340
100564
  if (generation !== lifecycle.generation) return;
@@ -99348,7 +100572,17 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99348
100572
  ctx.mqttConnected = false;
99349
100573
  if (closing) return;
99350
100574
  closing = true;
99351
- scheduleReconnect("connection closed");
100575
+ if (authFailure) {
100576
+ noteAuthFailure(ctx);
100577
+ Promise.resolve().then(() => repairSession(ctx, defaultFuncs)).catch(() => {
100578
+ }).then(() => {
100579
+ if (generation !== lifecycle.generation) return;
100580
+ resetBackoff();
100581
+ scheduleReconnect("session repaired after auth error");
100582
+ });
100583
+ return;
100584
+ }
100585
+ scheduleReconnect(throttled ? "connection refused (throttled)" : "connection closed", throttled);
99352
100586
  });
99353
100587
  client2.on("connect", () => {
99354
100588
  if (generation !== lifecycle.generation) return;
@@ -99452,6 +100686,13 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99452
100686
  log2("Reconnecting MQTT...");
99453
100687
  clearTimers();
99454
100688
  destroyClient();
100689
+ try {
100690
+ const last2 = ctx.lastMqttError;
100691
+ if (last2 && isAuthFailure && isAuthFailure(last2)) {
100692
+ await repairSession(ctx, defaultFuncs);
100693
+ }
100694
+ } catch (_3) {
100695
+ }
99455
100696
  try {
99456
100697
  await ensureSeqId();
99457
100698
  } catch (err) {
@@ -99511,7 +100752,9 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99511
100752
  }
99512
100753
  }
99513
100754
  ctx.firstListen = false;
100755
+ let fetchedSeqId = false;
99514
100756
  try {
100757
+ fetchedSeqId = !ctx.lastSeqId;
99515
100758
  await ensureSeqId();
99516
100759
  } catch (err) {
99517
100760
  ctx.lastMqttError = err;
@@ -99519,6 +100762,7 @@ var listenMqtt_default = (defaultFuncs, api, ctx) => {
99519
100762
  scheduleReconnect("sequence id fetch failed");
99520
100763
  return;
99521
100764
  }
100765
+ if (fetchedSeqId) await sleep(humanDelay(700, 400));
99522
100766
  await start();
99523
100767
  })().catch((err) => {
99524
100768
  error("listenMqtt startup error:", err);
@@ -99650,7 +100894,7 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
99650
100894
  if (!name || c.value === void 0 || c.value === null) {
99651
100895
  throw new Error(`Invalid appState cookie at index ${index3}.`);
99652
100896
  }
99653
- return `${name}=${String(c.value)}`;
100897
+ return formatAppStateCookie(c);
99654
100898
  });
99655
100899
  } else if (typeof appState === "string") {
99656
100900
  cookieStrings = appState.split(";").map((s) => s.trim()).filter(Boolean);
@@ -99663,9 +100907,16 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
99663
100907
  if (cookieString.indexOf("=") <= 0) {
99664
100908
  throw new Error(`Invalid appState cookie at index ${index3}.`);
99665
100909
  }
99666
- const domain = ".facebook.com";
99667
- const str = `${cookieString}; domain=${domain}; path=/;`;
99668
- jar2.setCookie(str, "https://facebook.com");
100910
+ const normalized = cookieString.replace(/;\s*domain=facebook\.com/i, "; domain=.facebook.com").replace(/;\s*domain=messenger\.com/i, "; domain=.messenger.com");
100911
+ const str = /(^|;)\s*domain=/i.test(normalized) ? normalized : `${normalized}; domain=.facebook.com; path=/; Secure; SameSite=None`;
100912
+ try {
100913
+ jar2.setCookieSync(str, "https://facebook.com");
100914
+ } catch {
100915
+ try {
100916
+ jar2.setCookieSync(`${normalized}; domain=.facebook.com; path=/; Secure; SameSite=None`, "https://www.facebook.com");
100917
+ } catch {
100918
+ }
100919
+ }
99669
100920
  });
99670
100921
  } else if (credentials.email && credentials.password) {
99671
100922
  const url2 = "https://api.facebook.com/method/auth.login";
@@ -99682,15 +100933,25 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
99682
100933
  const query = qs.stringify(params);
99683
100934
  const xurl = `${url2}?${query}`;
99684
100935
  try {
99685
- const resp2 = await axios_default.get(xurl);
100936
+ const legacyHeaders = getHeaders(
100937
+ url2,
100938
+ globalOptions,
100939
+ null,
100940
+ { "Content-Type": "application/x-www-form-urlencoded" }
100941
+ );
100942
+ const resp2 = await axios_default.get(xurl, {
100943
+ headers: legacyHeaders,
100944
+ timeout: 6e4,
100945
+ validateStatus: (status) => status >= 200 && status < 600
100946
+ });
99686
100947
  if (resp2.status !== 200) {
99687
100948
  throw new Error("Wrong password / email");
99688
100949
  }
99689
100950
  const cstrs = resp2.data["session_cookies"].map((c) => `${c.name}=${c.value}`);
99690
100951
  cstrs.forEach((cstr) => {
99691
100952
  const domain = ".facebook.com";
99692
- const str = `${cstr}; domain=${domain}; path=/;`;
99693
- jar2.setCookie(str, "https://facebook.com");
100953
+ const str = `${cstr}; domain=${domain}; path=/; Secure; SameSite=None`;
100954
+ jar2.setCookieSync(str, "https://facebook.com");
99694
100955
  });
99695
100956
  } catch (e) {
99696
100957
  throw new Error("Wrong password / email");
@@ -99803,6 +101064,46 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
99803
101064
  api.ctx = ctx;
99804
101065
  api.defaultFuncs = defaultFuncs;
99805
101066
  api.globalOptions = globalOptions;
101067
+ api.extractCookies = () => extractCookies({ jar: jar2 });
101068
+ api.refreshSession = () => refreshSessionCookies(ctx, defaultFuncs);
101069
+ api.hasAuthenticatedSession = () => hasAuthenticatedSession(jar2);
101070
+ api.repairSession = () => repairSession(ctx, defaultFuncs);
101071
+ api.warmUpSession = () => warmUpSession(ctx, defaultFuncs.get);
101072
+ ctx.__startedAt = Date.now();
101073
+ ctx.__safetySnapshot = () => safetySnapshot(ctx);
101074
+ api.getSafetyStatus = () => safetySnapshot(ctx);
101075
+ api.pauseSession = (reason) => {
101076
+ tripBreaker(ctx, reason || "manual");
101077
+ return safetySnapshot(ctx);
101078
+ };
101079
+ api.resumeSession = () => {
101080
+ resetBreaker(ctx);
101081
+ return safetySnapshot(ctx);
101082
+ };
101083
+ ctx.__onSafetyTrip = (info2) => {
101084
+ warn(
101085
+ "Account safety",
101086
+ `pausing requests for ${Math.round((info2.cooldownMs || 0) / 1e3)}s (${info2.reason})`
101087
+ );
101088
+ };
101089
+ if (globalOptions.warmUp !== false) {
101090
+ try {
101091
+ await warmUpSession(ctx, defaultFuncs.get);
101092
+ } catch (warmUpError) {
101093
+ warn("Session warm-up skipped:", warmUpError?.message || warmUpError);
101094
+ }
101095
+ }
101096
+ ctx.__stopCookieKeepAlive = scheduleSessionKeepAlive(ctx, defaultFuncs, 15 * 60 * 1e3);
101097
+ if (globalOptions.liveness !== false) {
101098
+ const liveness = startLiveness(ctx, {
101099
+ foregroundPing: () => log("Session active"),
101100
+ backgroundPing: () => log("Session idle")
101101
+ });
101102
+ ctx.__livenessHandle = liveness;
101103
+ api.getLivenessState = () => liveness.state();
101104
+ api.canActProactively = () => canActProactively(ctx);
101105
+ api.awaitProactiveSlot = (maxWaitMs) => awaitProactiveSlot(ctx, maxWaitMs);
101106
+ }
99806
101107
  return callback(null, api);
99807
101108
  } catch (error2) {
99808
101109
  error("loginHelper", error2.error || error2);
@@ -99822,6 +101123,10 @@ async function login(credentials, options, callback) {
99822
101123
  if ("logging" in options) {
99823
101124
  logOptions(options.logging);
99824
101125
  }
101126
+ const browser = options.randomUserAgent ? randomUserAgent() : normalizeBrowserProfile({
101127
+ ...options.browser || defaultBrowserProfile,
101128
+ ...options.userAgent ? { userAgent: options.userAgent } : {}
101129
+ });
99825
101130
  const defaultOptions2 = {
99826
101131
  selfListen: false,
99827
101132
  listenEvents: false,
@@ -99833,7 +101138,8 @@ async function login(credentials, options, callback) {
99833
101138
  autoReconnect: true,
99834
101139
  online: false,
99835
101140
  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",
101141
+ userAgent: browser.userAgent,
101142
+ browser,
99837
101143
  advancedProtection: false,
99838
101144
  autoRotateSession: false,
99839
101145
  randomUserAgent: false
@@ -99876,6 +101182,10 @@ async function login(credentials, options, callback) {
99876
101182
  var public_exports = {};
99877
101183
 
99878
101184
  // index.ts
101185
+ init_headers();
101186
+ init_user_agents();
101187
+ init_pacing();
101188
+ init_safety();
99879
101189
  var metaChat = Object.assign(login, {
99880
101190
  login,
99881
101191
  publicTypes: public_exports,
@@ -99966,4 +101276,4 @@ lodash/lodash.js:
99966
101276
  *)
99967
101277
  */
99968
101278
 
99969
- export { index_default as default, login, public_exports as publicTypes };
101279
+ 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 };