@lazyneoaz/metachat 5.0.1 → 5.1.1

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
@@ -75558,6 +75558,7 @@ __export(utils_exports2, {
75558
75558
  BASE_COOLDOWN_MS: () => BASE_COOLDOWN_MS,
75559
75559
  BRAND: () => BRAND,
75560
75560
  CHROME_MAJORS: () => CHROME_MAJORS,
75561
+ CORE_REACTIONS: () => CORE_REACTIONS,
75561
75562
  ConfigurationError: () => ConfigurationError,
75562
75563
  DESKTOP_PLATFORMS: () => DESKTOP_PLATFORMS,
75563
75564
  FCAError: () => FCAError,
@@ -75569,6 +75570,7 @@ __export(utils_exports2, {
75569
75570
  NotFoundError: () => NotFoundError,
75570
75571
  PING_GRACE_MS: () => PING_GRACE_MS,
75571
75572
  PermissionError: () => PermissionError,
75573
+ REACTION_ALIASES: () => REACTION_ALIASES,
75572
75574
  RateLimitError: () => RateLimitError,
75573
75575
  RealtimeHealth: () => RealtimeHealth,
75574
75576
  RecoverySupervisor: () => RecoverySupervisor,
@@ -75650,6 +75652,8 @@ __export(utils_exports2, {
75650
75652
  isAuthFailure: () => isAuthFailure,
75651
75653
  isBreakerOpen: () => isBreakerOpen,
75652
75654
  isLoggedOutDocument: () => isLoggedOutDocument,
75655
+ isNonCriticalError: () => isNonCriticalError,
75656
+ isReactionEmoji: () => isReactionEmoji,
75653
75657
  isReadableStream: () => isReadableStream2,
75654
75658
  isStaleTokenError: () => isStaleTokenError,
75655
75659
  json: () => json2,
@@ -75660,6 +75664,7 @@ __export(utils_exports2, {
75660
75664
  meta: () => meta,
75661
75665
  missingSessionCookies: () => missingSessionCookies,
75662
75666
  normalizeBrowserProfile: () => normalizeBrowserProfile,
75667
+ normalizeReaction: () => normalizeReaction,
75663
75668
  noteAction: () => noteAction,
75664
75669
  noteAuthFailure: () => noteAuthFailure,
75665
75670
  noteCheckpoint: () => noteCheckpoint,
@@ -75681,6 +75686,7 @@ __export(utils_exports2, {
75681
75686
  resetBreaker: () => resetBreaker,
75682
75687
  resolveProfile: () => resolveProfile,
75683
75688
  retryDelay: () => retryDelay,
75689
+ retryOnNonCritical: () => retryOnNonCritical,
75684
75690
  safetySnapshot: () => safetySnapshot,
75685
75691
  saveCookies: () => saveCookies,
75686
75692
  scheduleSessionKeepAlive: () => scheduleSessionKeepAlive,
@@ -90726,7 +90732,7 @@ async function publishLsRequestWithAck(params) {
90726
90732
  }, timeoutMs);
90727
90733
  });
90728
90734
  }
90729
- function buildWsTaskContent(ctx, tasks, versionId) {
90735
+ function buildWsTaskContent(ctx, tasks, versionId, appId = "2220391788200892") {
90730
90736
  ctx.wsReqNumber = (ctx.wsReqNumber || 0) + 1;
90731
90737
  if (ctx.wsTaskNumber === void 0 || ctx.wsTaskNumber === null) {
90732
90738
  ctx.wsTaskNumber = 0;
@@ -90738,7 +90744,7 @@ function buildWsTaskContent(ctx, tasks, versionId) {
90738
90744
  if (task.failure_count === void 0) task.failure_count = null;
90739
90745
  });
90740
90746
  return {
90741
- app_id: "2220391788200892",
90747
+ app_id: appId,
90742
90748
  payload: JSON.stringify({
90743
90749
  data_trace_id: null,
90744
90750
  epoch_id: parseInt(
@@ -90757,6 +90763,30 @@ function buildWsTaskContent(ctx, tasks, versionId) {
90757
90763
  var import_form_data3 = __toESM(require_form_data2());
90758
90764
  init_constants();
90759
90765
  init_user_agents();
90766
+
90767
+ // src/utils/transient.ts
90768
+ var NON_CRITICAL_CODES = /* @__PURE__ */ new Set([1357004, 1357001, 1357031]);
90769
+ function isNonCriticalError(value) {
90770
+ if (!value || typeof value !== "object") return false;
90771
+ const body = value.body && typeof value.body === "object" ? value.body : value;
90772
+ if (body.isNotCritical === 1 || body.is_not_critical === 1) return true;
90773
+ const num = Number(body.error ?? body.errorCode ?? body.code);
90774
+ if (NON_CRITICAL_CODES.has(num)) return true;
90775
+ const text3 = String(body.errorDescription || body.errorSummary || body.message || "");
90776
+ return /re-?open(ing)? your browser|try again(?: later)?|temporarily unavailable/i.test(text3);
90777
+ }
90778
+ async function retryOnNonCritical(operation, refresh) {
90779
+ try {
90780
+ const first2 = await operation();
90781
+ if (!isNonCriticalError(first2)) return first2;
90782
+ } catch (error2) {
90783
+ if (!isNonCriticalError(error2)) throw error2;
90784
+ }
90785
+ await refresh();
90786
+ return operation();
90787
+ }
90788
+
90789
+ // src/utils/attachments.ts
90760
90790
  function cleanJsonResponse(value) {
90761
90791
  if (typeof value !== "string") return value;
90762
90792
  const normalized = value.replace(/^for\s*\(;;\);\s*/i, "");
@@ -90849,18 +90879,76 @@ function buildUploadQuery(ctx) {
90849
90879
  return qs2;
90850
90880
  }
90851
90881
  var EXTENSION_BY_MIME = {
90882
+ // video
90852
90883
  "video/mp4": "mp4",
90884
+ "video/quicktime": "mov",
90885
+ "video/webm": "webm",
90886
+ "video/x-matroska": "mkv",
90887
+ "video/x-msvideo": "avi",
90888
+ "video/mpeg": "mpeg",
90889
+ "video/3gpp": "3gp",
90890
+ // audio
90853
90891
  "audio/mp4": "m4a",
90892
+ "audio/x-m4a": "m4a",
90854
90893
  "audio/mpeg": "mp3",
90855
90894
  "audio/mp3": "mp3",
90856
90895
  "audio/aac": "aac",
90857
90896
  "audio/ogg": "ogg",
90897
+ "audio/opus": "opus",
90858
90898
  "audio/wav": "wav",
90899
+ "audio/x-wav": "wav",
90900
+ "audio/webm": "weba",
90901
+ "audio/flac": "flac",
90902
+ "audio/x-flac": "flac",
90903
+ "audio/3gpp": "3gp",
90904
+ // image
90859
90905
  "image/jpeg": "jpg",
90906
+ "image/jpg": "jpg",
90860
90907
  "image/png": "png",
90861
90908
  "image/gif": "gif",
90862
- "image/webp": "webp"
90909
+ "image/webp": "webp",
90910
+ "image/bmp": "bmp",
90911
+ "image/tiff": "tiff",
90912
+ "image/svg+xml": "svg",
90913
+ "image/heic": "heic",
90914
+ "image/heif": "heif",
90915
+ "image/avif": "avif",
90916
+ // documents / archives
90917
+ "application/pdf": "pdf",
90918
+ "application/zip": "zip",
90919
+ "application/x-zip-compressed": "zip",
90920
+ "application/x-rar-compressed": "rar",
90921
+ "application/vnd.rar": "rar",
90922
+ "application/x-7z-compressed": "7z",
90923
+ "application/gzip": "gz",
90924
+ "application/x-tar": "tar",
90925
+ "text/plain": "txt",
90926
+ "text/csv": "csv",
90927
+ "text/html": "html",
90928
+ "text/calendar": "ics",
90929
+ "application/json": "json",
90930
+ "application/xml": "xml",
90931
+ "text/xml": "xml",
90932
+ "application/msword": "doc",
90933
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
90934
+ "application/vnd.ms-excel": "xls",
90935
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
90936
+ "application/vnd.ms-powerpoint": "ppt",
90937
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx",
90938
+ "application/vnd.android.package-archive": "apk",
90939
+ "application/x-msdownload": "exe",
90940
+ "application/octet-stream": "bin"
90863
90941
  };
90942
+ function extensionForMime(mime) {
90943
+ if (!mime) return "";
90944
+ const normalized = String(mime).toLowerCase().split(";")[0].trim();
90945
+ if (EXTENSION_BY_MIME[normalized]) return EXTENSION_BY_MIME[normalized];
90946
+ const subtype = normalized.split("/")[1] || "";
90947
+ if (!subtype) return "";
90948
+ if (/\+([a-z0-9]+)$/.test(subtype)) return subtype.replace(/.*\+/, "");
90949
+ const cleaned = subtype.replace(/^vnd\./, "").replace(/^x-/, "").replace(/[-.]/g, "");
90950
+ return /^[a-z0-9]{1,10}$/.test(cleaned) ? cleaned : "";
90951
+ }
90864
90952
  function sniffMime(buffer) {
90865
90953
  if (buffer.length < 12) return "";
90866
90954
  const b = buffer;
@@ -90885,11 +90973,11 @@ function sniffMime(buffer) {
90885
90973
  }
90886
90974
  function normalizeFilename(filename, mime) {
90887
90975
  const base = filename && String(filename).trim() ? String(filename).trim() : `file-${Date.now()}`;
90888
- const ext = EXTENSION_BY_MIME[mime] || "";
90889
- const match = /\.[a-z0-9]{1,5}$/i.exec(base);
90976
+ const ext = extensionForMime(mime);
90977
+ const match = /\.[a-z0-9]{1,6}$/i.exec(base);
90890
90978
  const currentExt = match ? match[0].slice(1).toLowerCase() : "";
90891
90979
  if (ext && currentExt !== ext) {
90892
- const audioOverride = (ext === "m4a" || ext === "mp3" || ext === "aac" || ext === "ogg" || ext === "wav") && (currentExt === "mp4" || currentExt === "m4v" || currentExt === "");
90980
+ const audioOverride = (ext === "m4a" || ext === "mp3" || ext === "aac" || ext === "ogg" || ext === "wav" || ext === "opus" || ext === "flac") && (currentExt === "mp4" || currentExt === "m4v" || currentExt === "");
90893
90981
  if (audioOverride || !currentExt) {
90894
90982
  return currentExt ? `${base.slice(0, base.length - currentExt.length - 1)}.${ext}` : `${base}.${ext}`;
90895
90983
  }
@@ -90916,12 +91004,12 @@ async function uploadMercuryAttachment(ctx, defaultFuncs, attachment) {
90916
91004
  data2 = cleanJsonResponse(res && res.body !== void 0 ? res.body : res);
90917
91005
  } catch (error2) {
90918
91006
  lastError = error2;
90919
- if (attempt === 0 && isTransientUploadError(error2)) continue;
91007
+ if (attempt === 0 && isNonCriticalError(error2)) continue;
90920
91008
  throw error2;
90921
91009
  }
90922
91010
  if (extractAttachmentIds(data2).length) return finalizeUpload(data2);
90923
91011
  lastError = buildNoMetadataError(data2);
90924
- if (attempt === 0 && isTransientUploadError(lastError)) continue;
91012
+ if (attempt === 0 && isNonCriticalError(lastError)) continue;
90925
91013
  throw lastError;
90926
91014
  }
90927
91015
  throw lastError || buildNoMetadataError(null);
@@ -90932,14 +91020,6 @@ function buildNoMetadataError(data2) {
90932
91020
  err.body = data2;
90933
91021
  return err;
90934
91022
  }
90935
- function isTransientUploadError(value) {
90936
- const body = value && (value.body || value);
90937
- if (!body || typeof body !== "object") return false;
90938
- const num = Number(body.error ?? body.errorCode);
90939
- if (num === 1357004 || num === 1357001) return true;
90940
- const text3 = String(body.errorDescription || body.errorSummary || value?.message || "");
90941
- return /re-?open(ing)? your browser|try again|temporarily unavailable/i.test(text3);
90942
- }
90943
91023
  async function refreshUploadTokens(ctx, defaultFuncs) {
90944
91024
  ctx.lsd = void 0;
90945
91025
  ctx.master = ctx.master || {};
@@ -91052,6 +91132,68 @@ async function uploadGroupImage(ctx, defaultFuncs, image) {
91052
91132
  return cleanJsonResponse(res && res.body !== void 0 ? res.body : res);
91053
91133
  }
91054
91134
 
91135
+ // src/utils/reactions.ts
91136
+ var CORE_REACTIONS = [
91137
+ "\u{1F60D}",
91138
+ "\u{1F606}",
91139
+ "\u{1F62E}",
91140
+ "\u{1F622}",
91141
+ "\u{1F620}",
91142
+ "\u{1F44D}",
91143
+ "\u{1F44E}",
91144
+ "\u2764",
91145
+ "\u{1F497}",
91146
+ ""
91147
+ ];
91148
+ var REACTION_ALIASES = {
91149
+ ":heart_eyes:": "\u{1F60D}",
91150
+ ":love:": "\u{1F60D}",
91151
+ ":laughing:": "\u{1F606}",
91152
+ ":haha:": "\u{1F606}",
91153
+ ":open_mouth:": "\u{1F62E}",
91154
+ ":wow:": "\u{1F62E}",
91155
+ ":cry:": "\u{1F622}",
91156
+ ":sad:": "\u{1F622}",
91157
+ ":angry:": "\u{1F620}",
91158
+ ":thumbsup:": "\u{1F44D}",
91159
+ ":like:": "\u{1F44D}",
91160
+ ":thumbsdown:": "\u{1F44E}",
91161
+ ":dislike:": "\u{1F44E}",
91162
+ ":heart:": "\u2764",
91163
+ ":glowingheart:": "\u{1F497}"
91164
+ };
91165
+ function isReactionEmoji(value) {
91166
+ if (value == null) return false;
91167
+ const text3 = String(value).trim();
91168
+ if (!text3) return false;
91169
+ if (CORE_REACTIONS.indexOf(text3) !== -1) return true;
91170
+ let clusters;
91171
+ try {
91172
+ const seg = new Intl.Segmenter(void 0, { granularity: "grapheme" });
91173
+ clusters = Array.from(seg.segment(text3), (s) => s.segment);
91174
+ } catch {
91175
+ clusters = Array.from(text3);
91176
+ }
91177
+ if (clusters.length !== 1) return false;
91178
+ const only = clusters[0];
91179
+ if (!new RegExp("\\p{Extended_Pictographic}", "u").test(only) && !/\uFE0F|\u20E3/u.test(only)) return false;
91180
+ if (!/[\p{Extended_Pictographic}\uFE0F\u20E3]/u.test(only)) return false;
91181
+ if (/[\u0000-\u001F\u007F]/.test(only)) return false;
91182
+ return true;
91183
+ }
91184
+ function normalizeReaction(value, options = {}) {
91185
+ const raw = value == null ? "" : String(value).trim();
91186
+ if (raw === "") {
91187
+ if (options.allowRemove) return "";
91188
+ throw new Error("Reaction is not a valid emoji.");
91189
+ }
91190
+ const resolved = REACTION_ALIASES[raw] !== void 0 ? REACTION_ALIASES[raw] : raw;
91191
+ if (!options.forceCustom && !isReactionEmoji(resolved)) {
91192
+ throw new Error(`Reaction is not a valid emoji: ${JSON.stringify(raw)}`);
91193
+ }
91194
+ return resolved;
91195
+ }
91196
+
91055
91197
  // src/utils/lsd.ts
91056
91198
  var TOKEN_TTL_MS = 10 * 60 * 1e3;
91057
91199
  var STALE_TOKEN_ERRORS = /* @__PURE__ */ new Set([
@@ -92981,6 +93123,8 @@ function gcmember_default(defaultFuncs, api, ctx) {
92981
93123
  let queryPayload;
92982
93124
  let query;
92983
93125
  let finalUsers = usersToModify;
93126
+ let versionId;
93127
+ let appId;
92984
93128
  if (action === "add") {
92985
93129
  const usersToAdd = usersToModify.filter((id) => !currentMembers.includes(id));
92986
93130
  if (usersToAdd.length === 0) {
@@ -92988,8 +93132,8 @@ function gcmember_default(defaultFuncs, api, ctx) {
92988
93132
  }
92989
93133
  finalUsers = usersToAdd;
92990
93134
  queryPayload = {
92991
- thread_key: parseInt(threadID),
92992
- contact_ids: finalUsers.map((id) => parseInt(id)),
93135
+ thread_key: threadID,
93136
+ contact_ids: finalUsers,
92993
93137
  sync_group: 1
92994
93138
  };
92995
93139
  query = {
@@ -92998,6 +93142,8 @@ function gcmember_default(defaultFuncs, api, ctx) {
92998
93142
  payload: JSON.stringify(queryPayload),
92999
93143
  queue_name: String(threadID)
93000
93144
  };
93145
+ versionId = "24502707779384158";
93146
+ appId = "772021112871879";
93001
93147
  } else {
93002
93148
  const userToRemove = usersToModify[0];
93003
93149
  if (!currentMembers.includes(userToRemove)) {
@@ -93011,8 +93157,10 @@ function gcmember_default(defaultFuncs, api, ctx) {
93011
93157
  payload: JSON.stringify(queryPayload),
93012
93158
  queue_name: "remove_participant_v2"
93013
93159
  };
93160
+ versionId = "25002366262773827";
93161
+ appId = "2220391788200892";
93014
93162
  }
93015
- const content = buildWsTaskContent(ctx, [query], "24631415369801570");
93163
+ const content = buildWsTaskContent(ctx, [query], versionId, appId);
93016
93164
  await publishLsRequestWithAck({
93017
93165
  client: ctx.mqttClient,
93018
93166
  content,
@@ -93648,7 +93796,8 @@ var allowedProperties = {
93648
93796
  emojiSize: true,
93649
93797
  body: true,
93650
93798
  mentions: true,
93651
- location: true
93799
+ location: true,
93800
+ edit: true
93652
93801
  };
93653
93802
  var sendMessage_default = (defaultFuncs, api, ctx) => {
93654
93803
  async function uploadAttachment(attachments) {
@@ -93770,6 +93919,18 @@ var sendMessage_default = (defaultFuncs, api, ctx) => {
93770
93919
  if (msgType === "String") {
93771
93920
  msg = { body: msg };
93772
93921
  }
93922
+ if (Array.isArray(msg.edit) && msg.edit.length > 0) {
93923
+ let body = String(msg.body || "");
93924
+ const edits = [...msg.edit].sort((a, b) => Number(b?.[1] ?? 0) - Number(a?.[1] ?? 0));
93925
+ for (const entry of edits) {
93926
+ const text3 = Array.isArray(entry) ? String(entry[0] ?? "") : String(entry ?? "");
93927
+ const rawOffset = Array.isArray(entry) ? Number(entry[1]) : NaN;
93928
+ const offset = Number.isFinite(rawOffset) ? Math.max(0, Math.min(body.length, rawOffset)) : body.length;
93929
+ body = body.slice(0, offset) + text3 + body.slice(offset);
93930
+ }
93931
+ msg.body = body;
93932
+ delete msg.edit;
93933
+ }
93773
93934
  const finish = (err, data2) => {
93774
93935
  settle2(err, data2);
93775
93936
  return data2;
@@ -94043,45 +94204,6 @@ function sendTypingIndicator_default(defaultFuncs, api, ctx) {
94043
94204
  }
94044
94205
 
94045
94206
  // src/deltas/apis/messaging/setMessageReaction.ts
94046
- var VALID_REACTIONS = [
94047
- "\u{1F60D}",
94048
- // :heart_eyes:
94049
- "\u{1F606}",
94050
- // :laughing:
94051
- "\u{1F62E}",
94052
- // :open_mouth:
94053
- "\u{1F622}",
94054
- // :cry:
94055
- "\u{1F620}",
94056
- // :angry:
94057
- "\u{1F44D}",
94058
- // :thumbsup:
94059
- "\u{1F44E}",
94060
- // :thumbsdown:
94061
- "\u2764",
94062
- // :heart:
94063
- "\u{1F497}",
94064
- // :glowingheart:
94065
- ""
94066
- // remove
94067
- ];
94068
- var ALIASES = {
94069
- ":heart_eyes:": "\u{1F60D}",
94070
- ":love:": "\u{1F60D}",
94071
- ":laughing:": "\u{1F606}",
94072
- ":haha:": "\u{1F606}",
94073
- ":open_mouth:": "\u{1F62E}",
94074
- ":wow:": "\u{1F62E}",
94075
- ":cry:": "\u{1F622}",
94076
- ":sad:": "\u{1F622}",
94077
- ":angry:": "\u{1F620}",
94078
- ":thumbsup:": "\u{1F44D}",
94079
- ":like:": "\u{1F44D}",
94080
- ":thumbsdown:": "\u{1F44E}",
94081
- ":dislike:": "\u{1F44E}",
94082
- ":heart:": "\u2764",
94083
- ":glowingheart:": "\u{1F497}"
94084
- };
94085
94207
  function setMessageReaction_default(defaultFuncs, _api, ctx) {
94086
94208
  return async function setMessageReaction(reaction, messageID, callback, forceCustomReaction) {
94087
94209
  const cb = typeof callback === "function" ? callback : void 0;
@@ -94098,11 +94220,14 @@ function setMessageReaction_default(defaultFuncs, _api, ctx) {
94098
94220
  if (!messageID) {
94099
94221
  throw { error: "setMessageReaction: messageID is required." };
94100
94222
  }
94101
- let value = reaction == null ? "" : String(reaction);
94102
- if (ALIASES[value] !== void 0) {
94103
- value = ALIASES[value];
94104
- } else if (value !== "" && VALID_REACTIONS.indexOf(value) === -1 && !forceCustomReaction) {
94105
- throw { error: "Reaction is not a valid emoji." };
94223
+ let value;
94224
+ try {
94225
+ value = normalizeReaction(reaction, {
94226
+ allowRemove: true,
94227
+ forceCustom: !!forceCustomReaction
94228
+ });
94229
+ } catch (validationError) {
94230
+ throw { error: validationError?.message || "Reaction is not a valid emoji." };
94106
94231
  }
94107
94232
  const variables = {
94108
94233
  data: {
@@ -94894,33 +95019,35 @@ function searchMusic_default(defaultFuncs, _api, ctx) {
94894
95019
  }
94895
95020
  const page = collectTracks(parsed);
94896
95021
  const tracks = page.tracks.slice(0, count);
94897
- if (tracks.length === 0) {
95022
+ if (tracks.length) {
95023
+ const result = tracks.slice();
95024
+ result.tracks = tracks;
95025
+ result.endCursor = page.endCursor;
95026
+ result.hasNextPage = page.hasNextPage;
95027
+ result.query = text3;
95028
+ return result;
95029
+ }
95030
+ for (let retry = 0; retry < 3; retry++) {
94898
95031
  invalidateCometTokens(ctx);
95032
+ await sleep(600 + retry * 900);
94899
95033
  const retried = await attempt(true);
94900
- if (!isStaleTokenError(retried) && !retried.error && !(retried.errors || []).length) {
94901
- const retryPage = collectTracks(retried);
94902
- const retryTracks = retryPage.tracks.slice(0, count);
94903
- if (retryTracks.length) {
94904
- const result2 = retryTracks.slice();
94905
- result2.tracks = retryTracks;
94906
- result2.endCursor = retryPage.endCursor;
94907
- result2.hasNextPage = retryPage.hasNextPage;
94908
- result2.query = text3;
94909
- return result2;
94910
- }
95034
+ if (isStaleTokenError(retried) || retried?.error || (retried?.errors || []).length) continue;
95035
+ const retryPage = collectTracks(retried);
95036
+ const retryTracks = retryPage.tracks.slice(0, count);
95037
+ if (retryTracks.length) {
95038
+ const result = retryTracks.slice();
95039
+ result.tracks = retryTracks;
95040
+ result.endCursor = retryPage.endCursor;
95041
+ result.hasNextPage = retryPage.hasNextPage;
95042
+ result.query = text3;
95043
+ return result;
94911
95044
  }
94912
- throw {
94913
- error: `No music results found for "${text3}". The Facebook music catalog may be unavailable for this account or region.`,
94914
- code: "NO_RESULTS",
94915
- query: text3
94916
- };
94917
95045
  }
94918
- const result = tracks.slice();
94919
- result.tracks = tracks;
94920
- result.endCursor = page.endCursor;
94921
- result.hasNextPage = page.hasNextPage;
94922
- result.query = text3;
94923
- return result;
95046
+ throw {
95047
+ error: `No music results found for "${text3}". The Facebook music catalog may be unavailable for this account or region.`,
95048
+ code: "NO_RESULTS",
95049
+ query: text3
95050
+ };
94924
95051
  }
94925
95052
  return function searchMusic(query = "", options = {}, callback) {
94926
95053
  const selectedOptions = typeof options === "function" ? {} : options || {};
@@ -99077,15 +99204,22 @@ function story_default(defaultFuncs, api, ctx) {
99077
99204
  }
99078
99205
  async function sendStoryReply(storyIdOrUrl, message, isReaction) {
99079
99206
  try {
99080
- const allowedReactions = ["\u2764\uFE0F", "\u{1F44D}", "\u{1F917}", "\u{1F606}", "\u{1F621}", "\u{1F622}", "\u{1F62E}"];
99081
99207
  if (!storyIdOrUrl) throw new Error("Story ID or URL is required.");
99082
99208
  if (!message) throw new Error("A message or reaction is required.");
99209
+ let reactionValue = message;
99210
+ if (isReaction) {
99211
+ try {
99212
+ reactionValue = normalizeReaction(message);
99213
+ } catch (validationError) {
99214
+ throw new Error(validationError?.message || "Reaction is not a valid emoji.");
99215
+ }
99216
+ }
99083
99217
  let storyID = getStoryIDFromURL(storyIdOrUrl);
99084
99218
  if (!storyID) storyID = storyIdOrUrl;
99085
99219
  const variables = {
99086
99220
  input: {
99087
99221
  attribution_id_v2: "StoriesCometSuspenseRoot.react,comet.stories.viewer,via_cold_start",
99088
- message,
99222
+ message: reactionValue,
99089
99223
  story_id: storyID,
99090
99224
  story_reply_type: isReaction ? "LIGHT_WEIGHT" : "TEXT",
99091
99225
  actor_id: ctx.userID,
@@ -99093,12 +99227,9 @@ function story_default(defaultFuncs, api, ctx) {
99093
99227
  }
99094
99228
  };
99095
99229
  if (isReaction) {
99096
- if (!allowedReactions.includes(message)) {
99097
- throw new Error(`Invalid reaction. Please use one of: ${allowedReactions.join(" ")}`);
99098
- }
99099
99230
  variables.input.lightweight_reaction_actions = {
99100
99231
  offsets: [0],
99101
- reaction: message
99232
+ reaction: reactionValue
99102
99233
  };
99103
99234
  }
99104
99235
  const form = {
@@ -99507,14 +99638,32 @@ function getThreadInfo_default(defaultFuncs, api, ctx) {
99507
99638
  throw new Error("getThreadInfo: malformed response from GraphQL.");
99508
99639
  }
99509
99640
  const threadInfos = {};
99510
- for (let i2 = Math.min(resData.length - 2, threadIDs.length - 1); i2 >= 0; i2--) {
99641
+ let matched = 0;
99642
+ for (let i2 = 0; i2 < resData.length; i2++) {
99511
99643
  const res = resData[i2];
99512
- if (!res || res.error_results || !res[Object.keys(res)[0]]?.data) continue;
99513
- const threadInfo = formatThreadGraphQLResponse(res[Object.keys(res)[0]].data);
99644
+ if (!res || typeof res !== "object" || res.error_results) continue;
99645
+ const keys = Object.keys(res);
99646
+ const queryKey = keys.find((k) => /^o\d+$/.test(k));
99647
+ let index3;
99648
+ if (queryKey) {
99649
+ index3 = Number(queryKey.slice(1));
99650
+ } else if (typeof res.__ar === "number" || res.error !== void 0) {
99651
+ continue;
99652
+ } else {
99653
+ index3 = i2;
99654
+ }
99655
+ if (index3 < 0 || index3 >= threadIDs.length) continue;
99656
+ const data2 = res[queryKey || keys[0]];
99657
+ if (!data2 || !data2.data) continue;
99658
+ const threadInfo = formatThreadGraphQLResponse(data2.data);
99514
99659
  if (threadInfo) {
99515
- threadInfos[threadInfo.threadID || threadIDs[threadIDs.length - 1 - i2]] = threadInfo;
99660
+ threadInfos[threadInfo.threadID || threadIDs[index3]] = threadInfo;
99661
+ matched++;
99516
99662
  }
99517
99663
  }
99664
+ if (matched === 0) {
99665
+ throw new Error("getThreadInfo: malformed response from GraphQL.");
99666
+ }
99518
99667
  return Array.isArray(threadID) ? threadInfos : Object.values(threadInfos)[0] || null;
99519
99668
  } catch (err) {
99520
99669
  error("getThreadInfo", err);
@@ -100053,7 +100202,10 @@ var getUserInfo_default = (defaultFuncs, api, ctx) => {
100053
100202
  form[`ids[${i2}]`] = v;
100054
100203
  });
100055
100204
  const getGenderString = (code) => code === 1 ? "male" : code === 2 ? "female" : "no specific gender";
100056
- defaultFuncs.post("https://www.facebook.com/chat/user_info/", ctx.jar, form).then((resData) => parseAndCheckLogin(ctx, defaultFuncs)(resData)).then((resData) => {
100205
+ const performFetch = () => defaultFuncs.post("https://www.facebook.com/chat/user_info/", ctx.jar, form).then((resData) => parseAndCheckLogin(ctx, defaultFuncs)(resData));
100206
+ retryOnNonCritical(performFetch, () => {
100207
+ invalidateCometTokens?.(ctx);
100208
+ }).then((resData) => {
100057
100209
  if (resData?.error && resData?.error !== 3252001) throw resData;
100058
100210
  const retObj = {};
100059
100211
  const profiles = resData?.payload?.profiles;
@@ -101564,6 +101716,7 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
101564
101716
  }
101565
101717
  if (listenMqtt_default) {
101566
101718
  api["listenMqtt"] = listenMqtt_default(defaultFuncs, api, ctx);
101719
+ api["listen"] = api["listenMqtt"];
101567
101720
  }
101568
101721
  };
101569
101722
  api.getCurrentUserID = () => ctx.userID;
@@ -101888,7 +102041,9 @@ lodash/lodash.js:
101888
102041
  *)
101889
102042
  */
101890
102043
 
102044
+ exports.CORE_REACTIONS = CORE_REACTIONS;
101891
102045
  exports.PING_GRACE_MS = PING_GRACE_MS;
102046
+ exports.REACTION_ALIASES = REACTION_ALIASES;
101892
102047
  exports.RealtimeHealth = RealtimeHealth;
101893
102048
  exports.RecoverySupervisor = RecoverySupervisor;
101894
102049
  exports.SILENT_WINDOW_MS = SILENT_WINDOW_MS;
@@ -101914,10 +102069,13 @@ exports.invalidateCometTokens = invalidateCometTokens;
101914
102069
  exports.isAuthFailure = isAuthFailure;
101915
102070
  exports.isBreakerOpen = isBreakerOpen;
101916
102071
  exports.isLoggedOutDocument = isLoggedOutDocument;
102072
+ exports.isNonCriticalError = isNonCriticalError;
102073
+ exports.isReactionEmoji = isReactionEmoji;
101917
102074
  exports.isStaleTokenError = isStaleTokenError;
101918
102075
  exports.login = login;
101919
102076
  exports.missingSessionCookies = missingSessionCookies;
101920
102077
  exports.normalizeBrowserProfile = normalizeBrowserProfile;
102078
+ exports.normalizeReaction = normalizeReaction;
101921
102079
  exports.noteAction = noteAction;
101922
102080
  exports.noteAuthFailure = noteAuthFailure;
101923
102081
  exports.noteCheckpoint = noteCheckpoint;
@@ -101931,6 +102089,7 @@ exports.reserveRequest = reserveRequest;
101931
102089
  exports.resetBreaker = resetBreaker;
101932
102090
  exports.resolveProfile = resolveProfile;
101933
102091
  exports.retryDelay = retryDelay;
102092
+ exports.retryOnNonCritical = retryOnNonCritical;
101934
102093
  exports.safetySnapshot = safetySnapshot;
101935
102094
  exports.sleep = sleep;
101936
102095
  exports.startLiveness = startLiveness;
package/dist/index.d.mts CHANGED
@@ -1261,6 +1261,25 @@ declare function uploadMercuryAttachment(ctx: any, defaultFuncs: any, attachment
1261
1261
  */
1262
1262
  declare function uploadGroupImage(ctx: any, defaultFuncs: any, image: any): Promise<any>;
1263
1263
 
1264
+ /**
1265
+ * Shared reaction validation for every surface that sends a reaction.
1266
+ * Facebook accepts any single emoji; a whitelist silently rejects valid picks.
1267
+ */
1268
+ declare const CORE_REACTIONS: string[];
1269
+ declare const REACTION_ALIASES: Record<string, string>;
1270
+ declare function isReactionEmoji(value: unknown): boolean;
1271
+ declare function normalizeReaction(value: unknown, options?: {
1272
+ allowRemove?: boolean;
1273
+ forceCustom?: boolean;
1274
+ }): string;
1275
+
1276
+ /**
1277
+ * Facebook "non-critical" errors (e.g. 1357004) are retryable and must not be
1278
+ * treated as auth failures or checkpoints.
1279
+ */
1280
+ declare function isNonCriticalError(value: any): boolean;
1281
+ declare function retryOnNonCritical<T = any>(operation: () => Promise<T>, refresh: () => void | Promise<void>): Promise<T>;
1282
+
1264
1283
  type ApiContext = ApiContext$1;
1265
1284
  type ApiInternal = Api;
1266
1285
  type DefaultFuncs = DefaultFuncs$1;
@@ -1271,4 +1290,4 @@ declare const _default: typeof login$1 & {
1271
1290
  default: typeof login$1;
1272
1291
  };
1273
1292
 
1274
- export { type API, type AddedStickerPackInfo, type AiTheme, type AnyAttachment, type ApiContext, type ApiInternal, type Attachment, type AudioAttachment, type BrowserProfile, type Callback, type CommentMessage, type CommentResult, type Coordinates, type DefaultFuncs, type EmojiEvent, type Event, type FileAttachment, type GroupNameEvent, type ListenEvent, type LivenessHandle, type LivenessState, type LoginCredentials, type LoginOptions, type Mention, type Message, type MessageID, type MessageObject, type MessageReply, type MusicTag, type MusicTrack, type NicknameEvent, PING_GRACE_MS, type PhotoAttachment, type Reaction, RealtimeHealth, type RealtimeHealthState, type RecoveryEvent, type RecoveryOptions, type RecoveryRuntime, type RecoveryState, RecoverySupervisor, SILENT_WINDOW_MS, type SearchMusicOptions, type SearchMusicResult, type ShareAttachment, type ShareResult, type StickerAttachment, type StickerInfo, type StickerPackInfo, type ThreadID, type ThreadInfo, type ThreadThemeEvent, type TypingIndicator, type UnsendMessageEvent, type UserID, type UserInfo, type VideoAttachment, type WarmUpResult, acquireCookies, applySetCookie, awaitProactiveSlot, canActProactively, cleanJsonResponse, collectSessionCookies, _default as default, defaultBrowserProfile, ensureCometTokens, extractCookies, extractCookiesFromBody, extractCookiesFromJar, extractCookiesFromSetCookie, extractCurrentUser, getFingerprintParams, getHeaders, getWebSocketHeaders, hasAuthenticatedSession, humanDelay, invalidateCometTokens, isAuthFailure, isBreakerOpen, isLoggedOutDocument, isStaleTokenError, login$1 as login, missingSessionCookies, normalizeBrowserProfile, noteAction, noteAuthFailure, noteCheckpoint, noteRateLimit, paceRequest, publicTypes, randomUserAgent, refreshSessionCookies, repairSession, reserveRequest, resetBreaker, resolveProfile, retryDelay, safetySnapshot, sleep, startLiveness, startRealtimeSupervisor, startRecovery, tripBreaker, uploadGroupImage, uploadMercuryAttachment, warmUpSession, withCometTokens, withSessionRetry };
1293
+ export { type API, type AddedStickerPackInfo, type AiTheme, type AnyAttachment, type ApiContext, type ApiInternal, type Attachment, type AudioAttachment, type BrowserProfile, CORE_REACTIONS, type Callback, type CommentMessage, type CommentResult, type Coordinates, type DefaultFuncs, type EmojiEvent, type Event, type FileAttachment, type GroupNameEvent, type ListenEvent, type LivenessHandle, type LivenessState, type LoginCredentials, type LoginOptions, type Mention, type Message, type MessageID, type MessageObject, type MessageReply, type MusicTag, type MusicTrack, type NicknameEvent, PING_GRACE_MS, type PhotoAttachment, REACTION_ALIASES, type Reaction, RealtimeHealth, type RealtimeHealthState, type RecoveryEvent, type RecoveryOptions, type RecoveryRuntime, type RecoveryState, RecoverySupervisor, SILENT_WINDOW_MS, type SearchMusicOptions, type SearchMusicResult, type ShareAttachment, type ShareResult, type StickerAttachment, type StickerInfo, type StickerPackInfo, type ThreadID, type ThreadInfo, type ThreadThemeEvent, type TypingIndicator, type UnsendMessageEvent, type UserID, type UserInfo, type VideoAttachment, type WarmUpResult, acquireCookies, applySetCookie, awaitProactiveSlot, canActProactively, cleanJsonResponse, collectSessionCookies, _default as default, defaultBrowserProfile, ensureCometTokens, extractCookies, extractCookiesFromBody, extractCookiesFromJar, extractCookiesFromSetCookie, extractCurrentUser, getFingerprintParams, getHeaders, getWebSocketHeaders, hasAuthenticatedSession, humanDelay, invalidateCometTokens, isAuthFailure, isBreakerOpen, isLoggedOutDocument, isNonCriticalError, isReactionEmoji, isStaleTokenError, login$1 as login, missingSessionCookies, normalizeBrowserProfile, normalizeReaction, noteAction, noteAuthFailure, noteCheckpoint, noteRateLimit, paceRequest, publicTypes, randomUserAgent, refreshSessionCookies, repairSession, reserveRequest, resetBreaker, resolveProfile, retryDelay, retryOnNonCritical, safetySnapshot, sleep, startLiveness, startRealtimeSupervisor, startRecovery, tripBreaker, uploadGroupImage, uploadMercuryAttachment, warmUpSession, withCometTokens, withSessionRetry };
package/dist/index.d.ts CHANGED
@@ -1261,6 +1261,25 @@ declare function uploadMercuryAttachment(ctx: any, defaultFuncs: any, attachment
1261
1261
  */
1262
1262
  declare function uploadGroupImage(ctx: any, defaultFuncs: any, image: any): Promise<any>;
1263
1263
 
1264
+ /**
1265
+ * Shared reaction validation for every surface that sends a reaction.
1266
+ * Facebook accepts any single emoji; a whitelist silently rejects valid picks.
1267
+ */
1268
+ declare const CORE_REACTIONS: string[];
1269
+ declare const REACTION_ALIASES: Record<string, string>;
1270
+ declare function isReactionEmoji(value: unknown): boolean;
1271
+ declare function normalizeReaction(value: unknown, options?: {
1272
+ allowRemove?: boolean;
1273
+ forceCustom?: boolean;
1274
+ }): string;
1275
+
1276
+ /**
1277
+ * Facebook "non-critical" errors (e.g. 1357004) are retryable and must not be
1278
+ * treated as auth failures or checkpoints.
1279
+ */
1280
+ declare function isNonCriticalError(value: any): boolean;
1281
+ declare function retryOnNonCritical<T = any>(operation: () => Promise<T>, refresh: () => void | Promise<void>): Promise<T>;
1282
+
1264
1283
  type ApiContext = ApiContext$1;
1265
1284
  type ApiInternal = Api;
1266
1285
  type DefaultFuncs = DefaultFuncs$1;
@@ -1271,4 +1290,4 @@ declare const _default: typeof login$1 & {
1271
1290
  default: typeof login$1;
1272
1291
  };
1273
1292
 
1274
- export { type API, type AddedStickerPackInfo, type AiTheme, type AnyAttachment, type ApiContext, type ApiInternal, type Attachment, type AudioAttachment, type BrowserProfile, type Callback, type CommentMessage, type CommentResult, type Coordinates, type DefaultFuncs, type EmojiEvent, type Event, type FileAttachment, type GroupNameEvent, type ListenEvent, type LivenessHandle, type LivenessState, type LoginCredentials, type LoginOptions, type Mention, type Message, type MessageID, type MessageObject, type MessageReply, type MusicTag, type MusicTrack, type NicknameEvent, PING_GRACE_MS, type PhotoAttachment, type Reaction, RealtimeHealth, type RealtimeHealthState, type RecoveryEvent, type RecoveryOptions, type RecoveryRuntime, type RecoveryState, RecoverySupervisor, SILENT_WINDOW_MS, type SearchMusicOptions, type SearchMusicResult, type ShareAttachment, type ShareResult, type StickerAttachment, type StickerInfo, type StickerPackInfo, type ThreadID, type ThreadInfo, type ThreadThemeEvent, type TypingIndicator, type UnsendMessageEvent, type UserID, type UserInfo, type VideoAttachment, type WarmUpResult, acquireCookies, applySetCookie, awaitProactiveSlot, canActProactively, cleanJsonResponse, collectSessionCookies, _default as default, defaultBrowserProfile, ensureCometTokens, extractCookies, extractCookiesFromBody, extractCookiesFromJar, extractCookiesFromSetCookie, extractCurrentUser, getFingerprintParams, getHeaders, getWebSocketHeaders, hasAuthenticatedSession, humanDelay, invalidateCometTokens, isAuthFailure, isBreakerOpen, isLoggedOutDocument, isStaleTokenError, login$1 as login, missingSessionCookies, normalizeBrowserProfile, noteAction, noteAuthFailure, noteCheckpoint, noteRateLimit, paceRequest, publicTypes, randomUserAgent, refreshSessionCookies, repairSession, reserveRequest, resetBreaker, resolveProfile, retryDelay, safetySnapshot, sleep, startLiveness, startRealtimeSupervisor, startRecovery, tripBreaker, uploadGroupImage, uploadMercuryAttachment, warmUpSession, withCometTokens, withSessionRetry };
1293
+ export { type API, type AddedStickerPackInfo, type AiTheme, type AnyAttachment, type ApiContext, type ApiInternal, type Attachment, type AudioAttachment, type BrowserProfile, CORE_REACTIONS, type Callback, type CommentMessage, type CommentResult, type Coordinates, type DefaultFuncs, type EmojiEvent, type Event, type FileAttachment, type GroupNameEvent, type ListenEvent, type LivenessHandle, type LivenessState, type LoginCredentials, type LoginOptions, type Mention, type Message, type MessageID, type MessageObject, type MessageReply, type MusicTag, type MusicTrack, type NicknameEvent, PING_GRACE_MS, type PhotoAttachment, REACTION_ALIASES, type Reaction, RealtimeHealth, type RealtimeHealthState, type RecoveryEvent, type RecoveryOptions, type RecoveryRuntime, type RecoveryState, RecoverySupervisor, SILENT_WINDOW_MS, type SearchMusicOptions, type SearchMusicResult, type ShareAttachment, type ShareResult, type StickerAttachment, type StickerInfo, type StickerPackInfo, type ThreadID, type ThreadInfo, type ThreadThemeEvent, type TypingIndicator, type UnsendMessageEvent, type UserID, type UserInfo, type VideoAttachment, type WarmUpResult, acquireCookies, applySetCookie, awaitProactiveSlot, canActProactively, cleanJsonResponse, collectSessionCookies, _default as default, defaultBrowserProfile, ensureCometTokens, extractCookies, extractCookiesFromBody, extractCookiesFromJar, extractCookiesFromSetCookie, extractCurrentUser, getFingerprintParams, getHeaders, getWebSocketHeaders, hasAuthenticatedSession, humanDelay, invalidateCometTokens, isAuthFailure, isBreakerOpen, isLoggedOutDocument, isNonCriticalError, isReactionEmoji, isStaleTokenError, login$1 as login, missingSessionCookies, normalizeBrowserProfile, normalizeReaction, noteAction, noteAuthFailure, noteCheckpoint, noteRateLimit, paceRequest, publicTypes, randomUserAgent, refreshSessionCookies, repairSession, reserveRequest, resetBreaker, resolveProfile, retryDelay, retryOnNonCritical, safetySnapshot, sleep, startLiveness, startRealtimeSupervisor, startRecovery, tripBreaker, uploadGroupImage, uploadMercuryAttachment, warmUpSession, withCometTokens, withSessionRetry };
package/dist/index.mjs CHANGED
@@ -75523,6 +75523,7 @@ __export(utils_exports2, {
75523
75523
  BASE_COOLDOWN_MS: () => BASE_COOLDOWN_MS,
75524
75524
  BRAND: () => BRAND,
75525
75525
  CHROME_MAJORS: () => CHROME_MAJORS,
75526
+ CORE_REACTIONS: () => CORE_REACTIONS,
75526
75527
  ConfigurationError: () => ConfigurationError,
75527
75528
  DESKTOP_PLATFORMS: () => DESKTOP_PLATFORMS,
75528
75529
  FCAError: () => FCAError,
@@ -75534,6 +75535,7 @@ __export(utils_exports2, {
75534
75535
  NotFoundError: () => NotFoundError,
75535
75536
  PING_GRACE_MS: () => PING_GRACE_MS,
75536
75537
  PermissionError: () => PermissionError,
75538
+ REACTION_ALIASES: () => REACTION_ALIASES,
75537
75539
  RateLimitError: () => RateLimitError,
75538
75540
  RealtimeHealth: () => RealtimeHealth,
75539
75541
  RecoverySupervisor: () => RecoverySupervisor,
@@ -75615,6 +75617,8 @@ __export(utils_exports2, {
75615
75617
  isAuthFailure: () => isAuthFailure,
75616
75618
  isBreakerOpen: () => isBreakerOpen,
75617
75619
  isLoggedOutDocument: () => isLoggedOutDocument,
75620
+ isNonCriticalError: () => isNonCriticalError,
75621
+ isReactionEmoji: () => isReactionEmoji,
75618
75622
  isReadableStream: () => isReadableStream2,
75619
75623
  isStaleTokenError: () => isStaleTokenError,
75620
75624
  json: () => json2,
@@ -75625,6 +75629,7 @@ __export(utils_exports2, {
75625
75629
  meta: () => meta,
75626
75630
  missingSessionCookies: () => missingSessionCookies,
75627
75631
  normalizeBrowserProfile: () => normalizeBrowserProfile,
75632
+ normalizeReaction: () => normalizeReaction,
75628
75633
  noteAction: () => noteAction,
75629
75634
  noteAuthFailure: () => noteAuthFailure,
75630
75635
  noteCheckpoint: () => noteCheckpoint,
@@ -75646,6 +75651,7 @@ __export(utils_exports2, {
75646
75651
  resetBreaker: () => resetBreaker,
75647
75652
  resolveProfile: () => resolveProfile,
75648
75653
  retryDelay: () => retryDelay,
75654
+ retryOnNonCritical: () => retryOnNonCritical,
75649
75655
  safetySnapshot: () => safetySnapshot,
75650
75656
  saveCookies: () => saveCookies,
75651
75657
  scheduleSessionKeepAlive: () => scheduleSessionKeepAlive,
@@ -90691,7 +90697,7 @@ async function publishLsRequestWithAck(params) {
90691
90697
  }, timeoutMs);
90692
90698
  });
90693
90699
  }
90694
- function buildWsTaskContent(ctx, tasks, versionId) {
90700
+ function buildWsTaskContent(ctx, tasks, versionId, appId = "2220391788200892") {
90695
90701
  ctx.wsReqNumber = (ctx.wsReqNumber || 0) + 1;
90696
90702
  if (ctx.wsTaskNumber === void 0 || ctx.wsTaskNumber === null) {
90697
90703
  ctx.wsTaskNumber = 0;
@@ -90703,7 +90709,7 @@ function buildWsTaskContent(ctx, tasks, versionId) {
90703
90709
  if (task.failure_count === void 0) task.failure_count = null;
90704
90710
  });
90705
90711
  return {
90706
- app_id: "2220391788200892",
90712
+ app_id: appId,
90707
90713
  payload: JSON.stringify({
90708
90714
  data_trace_id: null,
90709
90715
  epoch_id: parseInt(
@@ -90722,6 +90728,30 @@ function buildWsTaskContent(ctx, tasks, versionId) {
90722
90728
  var import_form_data3 = __toESM(require_form_data2());
90723
90729
  init_constants();
90724
90730
  init_user_agents();
90731
+
90732
+ // src/utils/transient.ts
90733
+ var NON_CRITICAL_CODES = /* @__PURE__ */ new Set([1357004, 1357001, 1357031]);
90734
+ function isNonCriticalError(value) {
90735
+ if (!value || typeof value !== "object") return false;
90736
+ const body = value.body && typeof value.body === "object" ? value.body : value;
90737
+ if (body.isNotCritical === 1 || body.is_not_critical === 1) return true;
90738
+ const num = Number(body.error ?? body.errorCode ?? body.code);
90739
+ if (NON_CRITICAL_CODES.has(num)) return true;
90740
+ const text3 = String(body.errorDescription || body.errorSummary || body.message || "");
90741
+ return /re-?open(ing)? your browser|try again(?: later)?|temporarily unavailable/i.test(text3);
90742
+ }
90743
+ async function retryOnNonCritical(operation, refresh) {
90744
+ try {
90745
+ const first2 = await operation();
90746
+ if (!isNonCriticalError(first2)) return first2;
90747
+ } catch (error2) {
90748
+ if (!isNonCriticalError(error2)) throw error2;
90749
+ }
90750
+ await refresh();
90751
+ return operation();
90752
+ }
90753
+
90754
+ // src/utils/attachments.ts
90725
90755
  function cleanJsonResponse(value) {
90726
90756
  if (typeof value !== "string") return value;
90727
90757
  const normalized = value.replace(/^for\s*\(;;\);\s*/i, "");
@@ -90814,18 +90844,76 @@ function buildUploadQuery(ctx) {
90814
90844
  return qs2;
90815
90845
  }
90816
90846
  var EXTENSION_BY_MIME = {
90847
+ // video
90817
90848
  "video/mp4": "mp4",
90849
+ "video/quicktime": "mov",
90850
+ "video/webm": "webm",
90851
+ "video/x-matroska": "mkv",
90852
+ "video/x-msvideo": "avi",
90853
+ "video/mpeg": "mpeg",
90854
+ "video/3gpp": "3gp",
90855
+ // audio
90818
90856
  "audio/mp4": "m4a",
90857
+ "audio/x-m4a": "m4a",
90819
90858
  "audio/mpeg": "mp3",
90820
90859
  "audio/mp3": "mp3",
90821
90860
  "audio/aac": "aac",
90822
90861
  "audio/ogg": "ogg",
90862
+ "audio/opus": "opus",
90823
90863
  "audio/wav": "wav",
90864
+ "audio/x-wav": "wav",
90865
+ "audio/webm": "weba",
90866
+ "audio/flac": "flac",
90867
+ "audio/x-flac": "flac",
90868
+ "audio/3gpp": "3gp",
90869
+ // image
90824
90870
  "image/jpeg": "jpg",
90871
+ "image/jpg": "jpg",
90825
90872
  "image/png": "png",
90826
90873
  "image/gif": "gif",
90827
- "image/webp": "webp"
90874
+ "image/webp": "webp",
90875
+ "image/bmp": "bmp",
90876
+ "image/tiff": "tiff",
90877
+ "image/svg+xml": "svg",
90878
+ "image/heic": "heic",
90879
+ "image/heif": "heif",
90880
+ "image/avif": "avif",
90881
+ // documents / archives
90882
+ "application/pdf": "pdf",
90883
+ "application/zip": "zip",
90884
+ "application/x-zip-compressed": "zip",
90885
+ "application/x-rar-compressed": "rar",
90886
+ "application/vnd.rar": "rar",
90887
+ "application/x-7z-compressed": "7z",
90888
+ "application/gzip": "gz",
90889
+ "application/x-tar": "tar",
90890
+ "text/plain": "txt",
90891
+ "text/csv": "csv",
90892
+ "text/html": "html",
90893
+ "text/calendar": "ics",
90894
+ "application/json": "json",
90895
+ "application/xml": "xml",
90896
+ "text/xml": "xml",
90897
+ "application/msword": "doc",
90898
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
90899
+ "application/vnd.ms-excel": "xls",
90900
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
90901
+ "application/vnd.ms-powerpoint": "ppt",
90902
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx",
90903
+ "application/vnd.android.package-archive": "apk",
90904
+ "application/x-msdownload": "exe",
90905
+ "application/octet-stream": "bin"
90828
90906
  };
90907
+ function extensionForMime(mime) {
90908
+ if (!mime) return "";
90909
+ const normalized = String(mime).toLowerCase().split(";")[0].trim();
90910
+ if (EXTENSION_BY_MIME[normalized]) return EXTENSION_BY_MIME[normalized];
90911
+ const subtype = normalized.split("/")[1] || "";
90912
+ if (!subtype) return "";
90913
+ if (/\+([a-z0-9]+)$/.test(subtype)) return subtype.replace(/.*\+/, "");
90914
+ const cleaned = subtype.replace(/^vnd\./, "").replace(/^x-/, "").replace(/[-.]/g, "");
90915
+ return /^[a-z0-9]{1,10}$/.test(cleaned) ? cleaned : "";
90916
+ }
90829
90917
  function sniffMime(buffer) {
90830
90918
  if (buffer.length < 12) return "";
90831
90919
  const b = buffer;
@@ -90850,11 +90938,11 @@ function sniffMime(buffer) {
90850
90938
  }
90851
90939
  function normalizeFilename(filename, mime) {
90852
90940
  const base = filename && String(filename).trim() ? String(filename).trim() : `file-${Date.now()}`;
90853
- const ext = EXTENSION_BY_MIME[mime] || "";
90854
- const match = /\.[a-z0-9]{1,5}$/i.exec(base);
90941
+ const ext = extensionForMime(mime);
90942
+ const match = /\.[a-z0-9]{1,6}$/i.exec(base);
90855
90943
  const currentExt = match ? match[0].slice(1).toLowerCase() : "";
90856
90944
  if (ext && currentExt !== ext) {
90857
- const audioOverride = (ext === "m4a" || ext === "mp3" || ext === "aac" || ext === "ogg" || ext === "wav") && (currentExt === "mp4" || currentExt === "m4v" || currentExt === "");
90945
+ const audioOverride = (ext === "m4a" || ext === "mp3" || ext === "aac" || ext === "ogg" || ext === "wav" || ext === "opus" || ext === "flac") && (currentExt === "mp4" || currentExt === "m4v" || currentExt === "");
90858
90946
  if (audioOverride || !currentExt) {
90859
90947
  return currentExt ? `${base.slice(0, base.length - currentExt.length - 1)}.${ext}` : `${base}.${ext}`;
90860
90948
  }
@@ -90881,12 +90969,12 @@ async function uploadMercuryAttachment(ctx, defaultFuncs, attachment) {
90881
90969
  data2 = cleanJsonResponse(res && res.body !== void 0 ? res.body : res);
90882
90970
  } catch (error2) {
90883
90971
  lastError = error2;
90884
- if (attempt === 0 && isTransientUploadError(error2)) continue;
90972
+ if (attempt === 0 && isNonCriticalError(error2)) continue;
90885
90973
  throw error2;
90886
90974
  }
90887
90975
  if (extractAttachmentIds(data2).length) return finalizeUpload(data2);
90888
90976
  lastError = buildNoMetadataError(data2);
90889
- if (attempt === 0 && isTransientUploadError(lastError)) continue;
90977
+ if (attempt === 0 && isNonCriticalError(lastError)) continue;
90890
90978
  throw lastError;
90891
90979
  }
90892
90980
  throw lastError || buildNoMetadataError(null);
@@ -90897,14 +90985,6 @@ function buildNoMetadataError(data2) {
90897
90985
  err.body = data2;
90898
90986
  return err;
90899
90987
  }
90900
- function isTransientUploadError(value) {
90901
- const body = value && (value.body || value);
90902
- if (!body || typeof body !== "object") return false;
90903
- const num = Number(body.error ?? body.errorCode);
90904
- if (num === 1357004 || num === 1357001) return true;
90905
- const text3 = String(body.errorDescription || body.errorSummary || value?.message || "");
90906
- return /re-?open(ing)? your browser|try again|temporarily unavailable/i.test(text3);
90907
- }
90908
90988
  async function refreshUploadTokens(ctx, defaultFuncs) {
90909
90989
  ctx.lsd = void 0;
90910
90990
  ctx.master = ctx.master || {};
@@ -91017,6 +91097,68 @@ async function uploadGroupImage(ctx, defaultFuncs, image) {
91017
91097
  return cleanJsonResponse(res && res.body !== void 0 ? res.body : res);
91018
91098
  }
91019
91099
 
91100
+ // src/utils/reactions.ts
91101
+ var CORE_REACTIONS = [
91102
+ "\u{1F60D}",
91103
+ "\u{1F606}",
91104
+ "\u{1F62E}",
91105
+ "\u{1F622}",
91106
+ "\u{1F620}",
91107
+ "\u{1F44D}",
91108
+ "\u{1F44E}",
91109
+ "\u2764",
91110
+ "\u{1F497}",
91111
+ ""
91112
+ ];
91113
+ var REACTION_ALIASES = {
91114
+ ":heart_eyes:": "\u{1F60D}",
91115
+ ":love:": "\u{1F60D}",
91116
+ ":laughing:": "\u{1F606}",
91117
+ ":haha:": "\u{1F606}",
91118
+ ":open_mouth:": "\u{1F62E}",
91119
+ ":wow:": "\u{1F62E}",
91120
+ ":cry:": "\u{1F622}",
91121
+ ":sad:": "\u{1F622}",
91122
+ ":angry:": "\u{1F620}",
91123
+ ":thumbsup:": "\u{1F44D}",
91124
+ ":like:": "\u{1F44D}",
91125
+ ":thumbsdown:": "\u{1F44E}",
91126
+ ":dislike:": "\u{1F44E}",
91127
+ ":heart:": "\u2764",
91128
+ ":glowingheart:": "\u{1F497}"
91129
+ };
91130
+ function isReactionEmoji(value) {
91131
+ if (value == null) return false;
91132
+ const text3 = String(value).trim();
91133
+ if (!text3) return false;
91134
+ if (CORE_REACTIONS.indexOf(text3) !== -1) return true;
91135
+ let clusters;
91136
+ try {
91137
+ const seg = new Intl.Segmenter(void 0, { granularity: "grapheme" });
91138
+ clusters = Array.from(seg.segment(text3), (s) => s.segment);
91139
+ } catch {
91140
+ clusters = Array.from(text3);
91141
+ }
91142
+ if (clusters.length !== 1) return false;
91143
+ const only = clusters[0];
91144
+ if (!new RegExp("\\p{Extended_Pictographic}", "u").test(only) && !/\uFE0F|\u20E3/u.test(only)) return false;
91145
+ if (!/[\p{Extended_Pictographic}\uFE0F\u20E3]/u.test(only)) return false;
91146
+ if (/[\u0000-\u001F\u007F]/.test(only)) return false;
91147
+ return true;
91148
+ }
91149
+ function normalizeReaction(value, options = {}) {
91150
+ const raw = value == null ? "" : String(value).trim();
91151
+ if (raw === "") {
91152
+ if (options.allowRemove) return "";
91153
+ throw new Error("Reaction is not a valid emoji.");
91154
+ }
91155
+ const resolved = REACTION_ALIASES[raw] !== void 0 ? REACTION_ALIASES[raw] : raw;
91156
+ if (!options.forceCustom && !isReactionEmoji(resolved)) {
91157
+ throw new Error(`Reaction is not a valid emoji: ${JSON.stringify(raw)}`);
91158
+ }
91159
+ return resolved;
91160
+ }
91161
+
91020
91162
  // src/utils/lsd.ts
91021
91163
  var TOKEN_TTL_MS = 10 * 60 * 1e3;
91022
91164
  var STALE_TOKEN_ERRORS = /* @__PURE__ */ new Set([
@@ -92946,6 +93088,8 @@ function gcmember_default(defaultFuncs, api, ctx) {
92946
93088
  let queryPayload;
92947
93089
  let query;
92948
93090
  let finalUsers = usersToModify;
93091
+ let versionId;
93092
+ let appId;
92949
93093
  if (action === "add") {
92950
93094
  const usersToAdd = usersToModify.filter((id) => !currentMembers.includes(id));
92951
93095
  if (usersToAdd.length === 0) {
@@ -92953,8 +93097,8 @@ function gcmember_default(defaultFuncs, api, ctx) {
92953
93097
  }
92954
93098
  finalUsers = usersToAdd;
92955
93099
  queryPayload = {
92956
- thread_key: parseInt(threadID),
92957
- contact_ids: finalUsers.map((id) => parseInt(id)),
93100
+ thread_key: threadID,
93101
+ contact_ids: finalUsers,
92958
93102
  sync_group: 1
92959
93103
  };
92960
93104
  query = {
@@ -92963,6 +93107,8 @@ function gcmember_default(defaultFuncs, api, ctx) {
92963
93107
  payload: JSON.stringify(queryPayload),
92964
93108
  queue_name: String(threadID)
92965
93109
  };
93110
+ versionId = "24502707779384158";
93111
+ appId = "772021112871879";
92966
93112
  } else {
92967
93113
  const userToRemove = usersToModify[0];
92968
93114
  if (!currentMembers.includes(userToRemove)) {
@@ -92976,8 +93122,10 @@ function gcmember_default(defaultFuncs, api, ctx) {
92976
93122
  payload: JSON.stringify(queryPayload),
92977
93123
  queue_name: "remove_participant_v2"
92978
93124
  };
93125
+ versionId = "25002366262773827";
93126
+ appId = "2220391788200892";
92979
93127
  }
92980
- const content = buildWsTaskContent(ctx, [query], "24631415369801570");
93128
+ const content = buildWsTaskContent(ctx, [query], versionId, appId);
92981
93129
  await publishLsRequestWithAck({
92982
93130
  client: ctx.mqttClient,
92983
93131
  content,
@@ -93613,7 +93761,8 @@ var allowedProperties = {
93613
93761
  emojiSize: true,
93614
93762
  body: true,
93615
93763
  mentions: true,
93616
- location: true
93764
+ location: true,
93765
+ edit: true
93617
93766
  };
93618
93767
  var sendMessage_default = (defaultFuncs, api, ctx) => {
93619
93768
  async function uploadAttachment(attachments) {
@@ -93735,6 +93884,18 @@ var sendMessage_default = (defaultFuncs, api, ctx) => {
93735
93884
  if (msgType === "String") {
93736
93885
  msg = { body: msg };
93737
93886
  }
93887
+ if (Array.isArray(msg.edit) && msg.edit.length > 0) {
93888
+ let body = String(msg.body || "");
93889
+ const edits = [...msg.edit].sort((a, b) => Number(b?.[1] ?? 0) - Number(a?.[1] ?? 0));
93890
+ for (const entry of edits) {
93891
+ const text3 = Array.isArray(entry) ? String(entry[0] ?? "") : String(entry ?? "");
93892
+ const rawOffset = Array.isArray(entry) ? Number(entry[1]) : NaN;
93893
+ const offset = Number.isFinite(rawOffset) ? Math.max(0, Math.min(body.length, rawOffset)) : body.length;
93894
+ body = body.slice(0, offset) + text3 + body.slice(offset);
93895
+ }
93896
+ msg.body = body;
93897
+ delete msg.edit;
93898
+ }
93738
93899
  const finish = (err, data2) => {
93739
93900
  settle2(err, data2);
93740
93901
  return data2;
@@ -94008,45 +94169,6 @@ function sendTypingIndicator_default(defaultFuncs, api, ctx) {
94008
94169
  }
94009
94170
 
94010
94171
  // src/deltas/apis/messaging/setMessageReaction.ts
94011
- var VALID_REACTIONS = [
94012
- "\u{1F60D}",
94013
- // :heart_eyes:
94014
- "\u{1F606}",
94015
- // :laughing:
94016
- "\u{1F62E}",
94017
- // :open_mouth:
94018
- "\u{1F622}",
94019
- // :cry:
94020
- "\u{1F620}",
94021
- // :angry:
94022
- "\u{1F44D}",
94023
- // :thumbsup:
94024
- "\u{1F44E}",
94025
- // :thumbsdown:
94026
- "\u2764",
94027
- // :heart:
94028
- "\u{1F497}",
94029
- // :glowingheart:
94030
- ""
94031
- // remove
94032
- ];
94033
- var ALIASES = {
94034
- ":heart_eyes:": "\u{1F60D}",
94035
- ":love:": "\u{1F60D}",
94036
- ":laughing:": "\u{1F606}",
94037
- ":haha:": "\u{1F606}",
94038
- ":open_mouth:": "\u{1F62E}",
94039
- ":wow:": "\u{1F62E}",
94040
- ":cry:": "\u{1F622}",
94041
- ":sad:": "\u{1F622}",
94042
- ":angry:": "\u{1F620}",
94043
- ":thumbsup:": "\u{1F44D}",
94044
- ":like:": "\u{1F44D}",
94045
- ":thumbsdown:": "\u{1F44E}",
94046
- ":dislike:": "\u{1F44E}",
94047
- ":heart:": "\u2764",
94048
- ":glowingheart:": "\u{1F497}"
94049
- };
94050
94172
  function setMessageReaction_default(defaultFuncs, _api, ctx) {
94051
94173
  return async function setMessageReaction(reaction, messageID, callback, forceCustomReaction) {
94052
94174
  const cb = typeof callback === "function" ? callback : void 0;
@@ -94063,11 +94185,14 @@ function setMessageReaction_default(defaultFuncs, _api, ctx) {
94063
94185
  if (!messageID) {
94064
94186
  throw { error: "setMessageReaction: messageID is required." };
94065
94187
  }
94066
- let value = reaction == null ? "" : String(reaction);
94067
- if (ALIASES[value] !== void 0) {
94068
- value = ALIASES[value];
94069
- } else if (value !== "" && VALID_REACTIONS.indexOf(value) === -1 && !forceCustomReaction) {
94070
- throw { error: "Reaction is not a valid emoji." };
94188
+ let value;
94189
+ try {
94190
+ value = normalizeReaction(reaction, {
94191
+ allowRemove: true,
94192
+ forceCustom: !!forceCustomReaction
94193
+ });
94194
+ } catch (validationError) {
94195
+ throw { error: validationError?.message || "Reaction is not a valid emoji." };
94071
94196
  }
94072
94197
  const variables = {
94073
94198
  data: {
@@ -94859,33 +94984,35 @@ function searchMusic_default(defaultFuncs, _api, ctx) {
94859
94984
  }
94860
94985
  const page = collectTracks(parsed);
94861
94986
  const tracks = page.tracks.slice(0, count);
94862
- if (tracks.length === 0) {
94987
+ if (tracks.length) {
94988
+ const result = tracks.slice();
94989
+ result.tracks = tracks;
94990
+ result.endCursor = page.endCursor;
94991
+ result.hasNextPage = page.hasNextPage;
94992
+ result.query = text3;
94993
+ return result;
94994
+ }
94995
+ for (let retry = 0; retry < 3; retry++) {
94863
94996
  invalidateCometTokens(ctx);
94997
+ await sleep(600 + retry * 900);
94864
94998
  const retried = await attempt(true);
94865
- if (!isStaleTokenError(retried) && !retried.error && !(retried.errors || []).length) {
94866
- const retryPage = collectTracks(retried);
94867
- const retryTracks = retryPage.tracks.slice(0, count);
94868
- if (retryTracks.length) {
94869
- const result2 = retryTracks.slice();
94870
- result2.tracks = retryTracks;
94871
- result2.endCursor = retryPage.endCursor;
94872
- result2.hasNextPage = retryPage.hasNextPage;
94873
- result2.query = text3;
94874
- return result2;
94875
- }
94999
+ if (isStaleTokenError(retried) || retried?.error || (retried?.errors || []).length) continue;
95000
+ const retryPage = collectTracks(retried);
95001
+ const retryTracks = retryPage.tracks.slice(0, count);
95002
+ if (retryTracks.length) {
95003
+ const result = retryTracks.slice();
95004
+ result.tracks = retryTracks;
95005
+ result.endCursor = retryPage.endCursor;
95006
+ result.hasNextPage = retryPage.hasNextPage;
95007
+ result.query = text3;
95008
+ return result;
94876
95009
  }
94877
- throw {
94878
- error: `No music results found for "${text3}". The Facebook music catalog may be unavailable for this account or region.`,
94879
- code: "NO_RESULTS",
94880
- query: text3
94881
- };
94882
95010
  }
94883
- const result = tracks.slice();
94884
- result.tracks = tracks;
94885
- result.endCursor = page.endCursor;
94886
- result.hasNextPage = page.hasNextPage;
94887
- result.query = text3;
94888
- return result;
95011
+ throw {
95012
+ error: `No music results found for "${text3}". The Facebook music catalog may be unavailable for this account or region.`,
95013
+ code: "NO_RESULTS",
95014
+ query: text3
95015
+ };
94889
95016
  }
94890
95017
  return function searchMusic(query = "", options = {}, callback) {
94891
95018
  const selectedOptions = typeof options === "function" ? {} : options || {};
@@ -99042,15 +99169,22 @@ function story_default(defaultFuncs, api, ctx) {
99042
99169
  }
99043
99170
  async function sendStoryReply(storyIdOrUrl, message, isReaction) {
99044
99171
  try {
99045
- const allowedReactions = ["\u2764\uFE0F", "\u{1F44D}", "\u{1F917}", "\u{1F606}", "\u{1F621}", "\u{1F622}", "\u{1F62E}"];
99046
99172
  if (!storyIdOrUrl) throw new Error("Story ID or URL is required.");
99047
99173
  if (!message) throw new Error("A message or reaction is required.");
99174
+ let reactionValue = message;
99175
+ if (isReaction) {
99176
+ try {
99177
+ reactionValue = normalizeReaction(message);
99178
+ } catch (validationError) {
99179
+ throw new Error(validationError?.message || "Reaction is not a valid emoji.");
99180
+ }
99181
+ }
99048
99182
  let storyID = getStoryIDFromURL(storyIdOrUrl);
99049
99183
  if (!storyID) storyID = storyIdOrUrl;
99050
99184
  const variables = {
99051
99185
  input: {
99052
99186
  attribution_id_v2: "StoriesCometSuspenseRoot.react,comet.stories.viewer,via_cold_start",
99053
- message,
99187
+ message: reactionValue,
99054
99188
  story_id: storyID,
99055
99189
  story_reply_type: isReaction ? "LIGHT_WEIGHT" : "TEXT",
99056
99190
  actor_id: ctx.userID,
@@ -99058,12 +99192,9 @@ function story_default(defaultFuncs, api, ctx) {
99058
99192
  }
99059
99193
  };
99060
99194
  if (isReaction) {
99061
- if (!allowedReactions.includes(message)) {
99062
- throw new Error(`Invalid reaction. Please use one of: ${allowedReactions.join(" ")}`);
99063
- }
99064
99195
  variables.input.lightweight_reaction_actions = {
99065
99196
  offsets: [0],
99066
- reaction: message
99197
+ reaction: reactionValue
99067
99198
  };
99068
99199
  }
99069
99200
  const form = {
@@ -99472,14 +99603,32 @@ function getThreadInfo_default(defaultFuncs, api, ctx) {
99472
99603
  throw new Error("getThreadInfo: malformed response from GraphQL.");
99473
99604
  }
99474
99605
  const threadInfos = {};
99475
- for (let i2 = Math.min(resData.length - 2, threadIDs.length - 1); i2 >= 0; i2--) {
99606
+ let matched = 0;
99607
+ for (let i2 = 0; i2 < resData.length; i2++) {
99476
99608
  const res = resData[i2];
99477
- if (!res || res.error_results || !res[Object.keys(res)[0]]?.data) continue;
99478
- const threadInfo = formatThreadGraphQLResponse(res[Object.keys(res)[0]].data);
99609
+ if (!res || typeof res !== "object" || res.error_results) continue;
99610
+ const keys = Object.keys(res);
99611
+ const queryKey = keys.find((k) => /^o\d+$/.test(k));
99612
+ let index3;
99613
+ if (queryKey) {
99614
+ index3 = Number(queryKey.slice(1));
99615
+ } else if (typeof res.__ar === "number" || res.error !== void 0) {
99616
+ continue;
99617
+ } else {
99618
+ index3 = i2;
99619
+ }
99620
+ if (index3 < 0 || index3 >= threadIDs.length) continue;
99621
+ const data2 = res[queryKey || keys[0]];
99622
+ if (!data2 || !data2.data) continue;
99623
+ const threadInfo = formatThreadGraphQLResponse(data2.data);
99479
99624
  if (threadInfo) {
99480
- threadInfos[threadInfo.threadID || threadIDs[threadIDs.length - 1 - i2]] = threadInfo;
99625
+ threadInfos[threadInfo.threadID || threadIDs[index3]] = threadInfo;
99626
+ matched++;
99481
99627
  }
99482
99628
  }
99629
+ if (matched === 0) {
99630
+ throw new Error("getThreadInfo: malformed response from GraphQL.");
99631
+ }
99483
99632
  return Array.isArray(threadID) ? threadInfos : Object.values(threadInfos)[0] || null;
99484
99633
  } catch (err) {
99485
99634
  error("getThreadInfo", err);
@@ -100018,7 +100167,10 @@ var getUserInfo_default = (defaultFuncs, api, ctx) => {
100018
100167
  form[`ids[${i2}]`] = v;
100019
100168
  });
100020
100169
  const getGenderString = (code) => code === 1 ? "male" : code === 2 ? "female" : "no specific gender";
100021
- defaultFuncs.post("https://www.facebook.com/chat/user_info/", ctx.jar, form).then((resData) => parseAndCheckLogin(ctx, defaultFuncs)(resData)).then((resData) => {
100170
+ const performFetch = () => defaultFuncs.post("https://www.facebook.com/chat/user_info/", ctx.jar, form).then((resData) => parseAndCheckLogin(ctx, defaultFuncs)(resData));
100171
+ retryOnNonCritical(performFetch, () => {
100172
+ invalidateCometTokens?.(ctx);
100173
+ }).then((resData) => {
100022
100174
  if (resData?.error && resData?.error !== 3252001) throw resData;
100023
100175
  const retObj = {};
100024
100176
  const profiles = resData?.payload?.profiles;
@@ -101529,6 +101681,7 @@ async function loginHelper(credentials, globalOptions, callback, setOptionsFunc,
101529
101681
  }
101530
101682
  if (listenMqtt_default) {
101531
101683
  api["listenMqtt"] = listenMqtt_default(defaultFuncs, api, ctx);
101684
+ api["listen"] = api["listenMqtt"];
101532
101685
  }
101533
101686
  };
101534
101687
  api.getCurrentUserID = () => ctx.userID;
@@ -101853,4 +102006,4 @@ lodash/lodash.js:
101853
102006
  *)
101854
102007
  */
101855
102008
 
101856
- export { PING_GRACE_MS, RealtimeHealth, RecoverySupervisor, SILENT_WINDOW_MS, acquireCookies, applySetCookie, awaitProactiveSlot, canActProactively, cleanJsonResponse, collectSessionCookies, index_default as default, defaultBrowserProfile, ensureCometTokens, extractCookies, extractCookiesFromBody, extractCookiesFromJar, extractCookiesFromSetCookie, extractCurrentUser, getFingerprintParams, getHeaders, getWebSocketHeaders, hasAuthenticatedSession, humanDelay, invalidateCometTokens, isAuthFailure, isBreakerOpen, isLoggedOutDocument, isStaleTokenError, login, missingSessionCookies, normalizeBrowserProfile, noteAction, noteAuthFailure, noteCheckpoint, noteRateLimit, paceRequest, public_exports as publicTypes, randomUserAgent, refreshSessionCookies, repairSession, reserveRequest, resetBreaker, resolveProfile, retryDelay, safetySnapshot, sleep, startLiveness, startRealtimeSupervisor, startRecovery, tripBreaker, uploadGroupImage, uploadMercuryAttachment, warmUpSession, withCometTokens, withSessionRetry };
102009
+ export { CORE_REACTIONS, PING_GRACE_MS, REACTION_ALIASES, RealtimeHealth, RecoverySupervisor, SILENT_WINDOW_MS, acquireCookies, applySetCookie, awaitProactiveSlot, canActProactively, cleanJsonResponse, collectSessionCookies, index_default as default, defaultBrowserProfile, ensureCometTokens, extractCookies, extractCookiesFromBody, extractCookiesFromJar, extractCookiesFromSetCookie, extractCurrentUser, getFingerprintParams, getHeaders, getWebSocketHeaders, hasAuthenticatedSession, humanDelay, invalidateCometTokens, isAuthFailure, isBreakerOpen, isLoggedOutDocument, isNonCriticalError, isReactionEmoji, isStaleTokenError, login, missingSessionCookies, normalizeBrowserProfile, normalizeReaction, noteAction, noteAuthFailure, noteCheckpoint, noteRateLimit, paceRequest, public_exports as publicTypes, randomUserAgent, refreshSessionCookies, repairSession, reserveRequest, resetBreaker, resolveProfile, retryDelay, retryOnNonCritical, safetySnapshot, sleep, startLiveness, startRealtimeSupervisor, startRecovery, tripBreaker, uploadGroupImage, uploadMercuryAttachment, warmUpSession, withCometTokens, withSessionRetry };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyneoaz/metachat",
3
- "version": "5.0.1",
3
+ "version": "5.1.1",
4
4
  "description": "A modern TypeScript Facebook Chat API client for building reliable Messenger bots, with built-in anti-detection protection, automatic cookie refresh, music search, and AI theme support.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -57,7 +57,7 @@
57
57
  "prepublishOnly": "npm run build",
58
58
  "lint": "npm run typecheck",
59
59
  "format": "prettier --write \"src/**/*.ts\" \"index.ts\"",
60
- "test": "npm run build && node test/smoke.test.cjs && node test/smoke.test.mjs && node test/music-search.test.cjs && node test/mqtt-lifecycle.test.cjs && node test/session-reliability.test.cjs && node test/anti-detection.test.cjs && node test/account-safety.test.cjs && node test/liveness.test.cjs && node test/recovery.test.cjs && node test/cookie-acquisition.test.cjs && node test/realtime-health.test.cjs && node test/attachment-resilience.test.cjs",
60
+ "test": "npm run build && node test/smoke.test.cjs && node test/smoke.test.mjs && node test/music-search.test.cjs && node test/mqtt-lifecycle.test.cjs && node test/session-reliability.test.cjs && node test/anti-detection.test.cjs && node test/account-safety.test.cjs && node test/liveness.test.cjs && node test/recovery.test.cjs && node test/cookie-acquisition.test.cjs && node test/realtime-health.test.cjs && node test/attachment-resilience.test.cjs && node test/reaction-validation.test.cjs && node test/api-surface-fixes.test.cjs && node test/threadinfo-regression.test.cjs",
61
61
  "audit": "npm audit",
62
62
  "audit:fix": "npm audit fix"
63
63
  },