@lazyneoaz/metachat 4.0.4 → 4.0.5

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