@lazyneoaz/metachat 6.0.5 → 6.0.7

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.
Files changed (3) hide show
  1. package/dist/index.cjs +106 -56
  2. package/dist/index.mjs +106 -56
  3. package/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -89023,7 +89023,7 @@ var sendMessage_default = (defaultFuncs, api, ctx) => {
89023
89023
  }, null);
89024
89024
  return messageInfo;
89025
89025
  }
89026
- return async function sendMessage(msg, threadID, callback, replyToMessage, isGroup) {
89026
+ const sendMessageCore = async function(msg, threadID, callback, replyToMessage, isGroup) {
89027
89027
  if (typeof isGroup === "undefined") isGroup = null;
89028
89028
  if (!callback && (getType(threadID) === "Function" || getType(threadID) === "AsyncFunction")) {
89029
89029
  throw new Error("Pass a threadID as a second argument.");
@@ -89047,11 +89047,13 @@ var sendMessage_default = (defaultFuncs, api, ctx) => {
89047
89047
  if (msgType !== "String" && msgType !== "Object") {
89048
89048
  const err = new Error("Message should be of type string or object and not " + msgType + ".");
89049
89049
  settle2(err);
89050
+ if (legacyCallback) return null;
89050
89051
  throw err;
89051
89052
  }
89052
89053
  if (threadIDType !== "Array" && threadIDType !== "Number" && threadIDType !== "String") {
89053
89054
  const err = new Error("ThreadID should be of type number, string, or array and not " + threadIDType + ".");
89054
89055
  settle2(err);
89056
+ if (legacyCallback) return null;
89055
89057
  throw err;
89056
89058
  }
89057
89059
  if (messageIDType === "Function" || messageIDType === "Undefined" || messageIDType === "Null") {
@@ -89059,6 +89061,7 @@ var sendMessage_default = (defaultFuncs, api, ctx) => {
89059
89061
  } else if (replyToMessage && messageIDType !== "String") {
89060
89062
  const err = new Error("MessageID should be of type string and not " + messageIDType + ".");
89061
89063
  settle2(err);
89064
+ if (legacyCallback) return null;
89062
89065
  throw err;
89063
89066
  }
89064
89067
  let isSingleUser = null;
@@ -89316,6 +89319,12 @@ var sendMessage_default = (defaultFuncs, api, ctx) => {
89316
89319
  }
89317
89320
  }
89318
89321
  };
89322
+ return function sendMessage(msg, threadID, callback, replyToMessage, isGroup) {
89323
+ const promise = sendMessageCore(msg, threadID, callback, replyToMessage, isGroup);
89324
+ if (typeof callback === "function") promise.catch(() => {
89325
+ });
89326
+ return promise;
89327
+ };
89319
89328
  };
89320
89329
 
89321
89330
  // src/deltas/apis/messaging/sendTypingIndicator.ts
@@ -90856,6 +90865,7 @@ function pinMessage_default(defaultFuncs, api, ctx) {
90856
90865
  }
90857
90866
 
90858
90867
  // src/deltas/apis/mqtt/sendMessageMqtt.ts
90868
+ var DEFAULT_RETRY_DELAYS_MS = [900, 1600, 2400, 3500, 5e3, 7e3];
90859
90869
  function preUploadedId(item) {
90860
90870
  if (typeof item === "number" && Number.isFinite(item)) return String(item);
90861
90871
  if (typeof item === "string" && /^\d{6,}$/.test(item.trim())) return item.trim();
@@ -90959,6 +90969,8 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
90959
90969
  resolveFunc = resolve;
90960
90970
  rejectFunc = reject;
90961
90971
  });
90972
+ returnPromise.catch(() => {
90973
+ });
90962
90974
  const userCallback = typeof callback === "function" ? callback : null;
90963
90975
  let finished2 = false;
90964
90976
  const finish = (err, data2) => {
@@ -90975,51 +90987,14 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
90975
90987
  if (!callback) {
90976
90988
  callback = finish;
90977
90989
  }
90990
+ const done = () => userCallback ? returnPromise.then(() => null, () => null) : returnPromise;
90978
90991
  if (!ctx.mqttClient || !ctx.mqttClient.connected) {
90979
90992
  const error2 = new Error("MQTT client is not connected. Cannot send message.");
90980
90993
  finish(error2);
90981
- return returnPromise;
90994
+ return done();
90982
90995
  }
90983
90996
  const timestamp = Date.now();
90984
- const otid = generateOfflineThreadingID();
90985
- const epoch_id = (BigInt(Date.now()) << 22n).toString();
90986
- const request_id = ctx.wsReqNumber = (ctx.wsReqNumber || 0) + 1;
90987
- const payload = getSendPayload(threadID, msg, otid);
90988
- const tasks = [{
90989
- label: "46",
90990
- payload,
90991
- queue_name: threadID.toString(),
90992
- task_id: 400,
90993
- failure_count: null
90994
- }, {
90995
- label: "21",
90996
- payload: {
90997
- thread_id: threadID.toString(),
90998
- last_read_watermark_ts: timestamp,
90999
- sync_group: 1
91000
- },
91001
- queue_name: threadID.toString(),
91002
- task_id: 401,
91003
- failure_count: null
91004
- }];
91005
- if (replyToMessage) {
91006
- tasks[0].payload.reply_metadata = {
91007
- reply_source_id: replyToMessage,
91008
- reply_source_type: 1,
91009
- reply_type: 0
91010
- };
91011
- }
91012
- const form = {
91013
- app_id: "2220391788200892",
91014
- payload: {
91015
- tasks,
91016
- epoch_id,
91017
- version_id: "24804310205905615",
91018
- data_trace_id: `#${Buffer.from(String(Math.random())).toString("base64").replace(/=+$/g, "")}`
91019
- },
91020
- request_id,
91021
- type: 3
91022
- };
90997
+ let attachmentIds = null;
91023
90998
  if (msg.attachment) {
91024
90999
  try {
91025
91000
  const inputs = Array.isArray(msg.attachment) ? msg.attachment : [msg.attachment];
@@ -91036,20 +91011,62 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
91036
91011
  ids.push(file && typeof file === "object" ? String(Object.values(file)[0]) : String(file));
91037
91012
  }
91038
91013
  }
91039
- form.payload.tasks[0].payload.attachment_fbids = ids;
91014
+ attachmentIds = ids;
91040
91015
  } catch (err) {
91041
91016
  error("Attachment upload failed:", err);
91042
91017
  callback(err);
91043
- return returnPromise;
91018
+ return done();
91044
91019
  }
91045
91020
  }
91046
- form.payload.tasks.forEach((task) => {
91047
- task.payload = JSON.stringify(task.payload);
91048
- });
91049
- form.payload = JSON.stringify(form.payload);
91050
- const fallbackMessageID = `mid.${otid}`;
91051
91021
  const mqttClient = ctx.mqttClient;
91052
- const result = await new Promise((resolve) => {
91022
+ const buildForm = () => {
91023
+ const otid = generateOfflineThreadingID();
91024
+ const epoch_id = (BigInt(Date.now()) << 22n).toString();
91025
+ const request_id = ctx.wsReqNumber = (ctx.wsReqNumber || 0) + 1;
91026
+ const payload = getSendPayload(threadID, msg, otid);
91027
+ if (attachmentIds) payload.attachment_fbids = attachmentIds;
91028
+ const tasks = [{
91029
+ label: "46",
91030
+ payload,
91031
+ queue_name: threadID.toString(),
91032
+ task_id: 400,
91033
+ failure_count: null
91034
+ }, {
91035
+ label: "21",
91036
+ payload: {
91037
+ thread_id: threadID.toString(),
91038
+ last_read_watermark_ts: Date.now(),
91039
+ sync_group: 1
91040
+ },
91041
+ queue_name: threadID.toString(),
91042
+ task_id: 401,
91043
+ failure_count: null
91044
+ }];
91045
+ if (replyToMessage) {
91046
+ tasks[0].payload.reply_metadata = {
91047
+ reply_source_id: replyToMessage,
91048
+ reply_source_type: 1,
91049
+ reply_type: 0
91050
+ };
91051
+ }
91052
+ const form = {
91053
+ app_id: "2220391788200892",
91054
+ payload: {
91055
+ tasks,
91056
+ epoch_id,
91057
+ version_id: "24804310205905615",
91058
+ data_trace_id: `#${Buffer.from(String(Math.random())).toString("base64").replace(/=+$/g, "")}`
91059
+ },
91060
+ request_id,
91061
+ type: 3
91062
+ };
91063
+ form.payload.tasks.forEach((task) => {
91064
+ task.payload = JSON.stringify(task.payload);
91065
+ });
91066
+ form.payload = JSON.stringify(form.payload);
91067
+ return { form, request_id, otid };
91068
+ };
91069
+ const publishAndWait = (form, request_id) => new Promise((resolve) => {
91053
91070
  let settled = false;
91054
91071
  let timer = null;
91055
91072
  const cleanup = () => {
@@ -91078,6 +91095,7 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
91078
91095
  let threadIDFromAck = null;
91079
91096
  let failure = null;
91080
91097
  let serverError = null;
91098
+ let softFailure = null;
91081
91099
  const steps = parsed.payload?.step;
91082
91100
  const visit = (node) => {
91083
91101
  if (!Array.isArray(node)) return;
@@ -91089,10 +91107,10 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
91089
91107
  threadIDFromAck = String(node[2][1]);
91090
91108
  }
91091
91109
  if (node[1] === "markOptimisticMessageFailed") {
91092
- failure = { error: "Couldn't send.", errorDescription: "Message failed on server." };
91110
+ softFailure = typeof node[3] === "string" ? node[3] : "Message failed on server.";
91093
91111
  }
91094
91112
  if (node[1] === "updateSubscriptErrorMessage" || node[1] === "fatalError") {
91095
- serverError = typeof node[3] === "string" ? node[3] : "Couldn't send.";
91113
+ softFailure = typeof node[3] === "string" ? node[3] : typeof node[4] === "string" ? node[4] : "Couldn't send.";
91096
91114
  }
91097
91115
  }
91098
91116
  for (const child of node) visit(child);
@@ -91102,7 +91120,8 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
91102
91120
  messageID: resolvedMessageID,
91103
91121
  threadID: threadIDFromAck,
91104
91122
  failure,
91105
- serverError
91123
+ serverError,
91124
+ softFailure
91106
91125
  });
91107
91126
  };
91108
91127
  if (mqttClient && typeof mqttClient.on === "function") {
@@ -91113,24 +91132,55 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
91113
91132
  });
91114
91133
  timer = setTimeout(() => settle2({ timeout: true }), 15e3);
91115
91134
  });
91135
+ const retryDelays = (() => {
91136
+ const override = ctx.globalOptions && ctx.globalOptions.mqttSendRetryDelaysMs;
91137
+ return Array.isArray(override) && override.length ? override : DEFAULT_RETRY_DELAYS_MS;
91138
+ })();
91139
+ let result = null;
91140
+ let lastOtid = "";
91141
+ for (let attempt = 0; attempt <= retryDelays.length; attempt++) {
91142
+ const built = buildForm();
91143
+ lastOtid = built.otid;
91144
+ result = await publishAndWait(built.form, built.request_id);
91145
+ if (!result.failure && !result.serverError && !result.softFailure) break;
91146
+ if ((result.failure || result.serverError) && attempt >= 2) break;
91147
+ if (attempt < retryDelays.length) {
91148
+ await sleep(retryDelays[attempt] + Math.floor(Math.random() * 400));
91149
+ }
91150
+ }
91116
91151
  if (result.failure || result.serverError) {
91117
91152
  const err = result.failure || { error: result.serverError };
91118
91153
  if (err.error && err.error === 1545012) {
91119
91154
  warn("sendMessageMqtt [MQTT]", `Got error 1545012. Bot is not part of the conversation ${threadID}`);
91120
91155
  finish(null, null);
91121
- return returnPromise;
91156
+ return done();
91122
91157
  }
91123
91158
  error("sendMessageMqtt", "Send failed:", err.error || err);
91124
91159
  finish(err);
91125
- return returnPromise;
91160
+ return done();
91161
+ }
91162
+ if (result.softFailure) {
91163
+ warn(
91164
+ "sendMessageMqtt [MQTT]",
91165
+ `Facebook rejected the message (${result.softFailure}); thread ${threadID}. Retried ${retryDelays.length} times without success; continuing without failing the bot.`
91166
+ );
91167
+ finish(null, {
91168
+ threadID: result.threadID || threadID.toString(),
91169
+ messageID: result.messageID || null,
91170
+ timestamp,
91171
+ type: replyToMessage ? "message_reply" : "message",
91172
+ error: result.softFailure,
91173
+ success: false
91174
+ });
91175
+ return done();
91126
91176
  }
91127
91177
  finish(null, {
91128
91178
  threadID: result.threadID || threadID.toString(),
91129
- messageID: result.messageID || fallbackMessageID,
91179
+ messageID: result.messageID || `mid.${lastOtid}`,
91130
91180
  timestamp,
91131
91181
  type: replyToMessage ? "message_reply" : "message"
91132
91182
  });
91133
- return returnPromise;
91183
+ return done();
91134
91184
  };
91135
91185
  };
91136
91186
 
package/dist/index.mjs CHANGED
@@ -88991,7 +88991,7 @@ var sendMessage_default = (defaultFuncs, api, ctx) => {
88991
88991
  }, null);
88992
88992
  return messageInfo;
88993
88993
  }
88994
- return async function sendMessage(msg, threadID, callback, replyToMessage, isGroup) {
88994
+ const sendMessageCore = async function(msg, threadID, callback, replyToMessage, isGroup) {
88995
88995
  if (typeof isGroup === "undefined") isGroup = null;
88996
88996
  if (!callback && (getType(threadID) === "Function" || getType(threadID) === "AsyncFunction")) {
88997
88997
  throw new Error("Pass a threadID as a second argument.");
@@ -89015,11 +89015,13 @@ var sendMessage_default = (defaultFuncs, api, ctx) => {
89015
89015
  if (msgType !== "String" && msgType !== "Object") {
89016
89016
  const err = new Error("Message should be of type string or object and not " + msgType + ".");
89017
89017
  settle2(err);
89018
+ if (legacyCallback) return null;
89018
89019
  throw err;
89019
89020
  }
89020
89021
  if (threadIDType !== "Array" && threadIDType !== "Number" && threadIDType !== "String") {
89021
89022
  const err = new Error("ThreadID should be of type number, string, or array and not " + threadIDType + ".");
89022
89023
  settle2(err);
89024
+ if (legacyCallback) return null;
89023
89025
  throw err;
89024
89026
  }
89025
89027
  if (messageIDType === "Function" || messageIDType === "Undefined" || messageIDType === "Null") {
@@ -89027,6 +89029,7 @@ var sendMessage_default = (defaultFuncs, api, ctx) => {
89027
89029
  } else if (replyToMessage && messageIDType !== "String") {
89028
89030
  const err = new Error("MessageID should be of type string and not " + messageIDType + ".");
89029
89031
  settle2(err);
89032
+ if (legacyCallback) return null;
89030
89033
  throw err;
89031
89034
  }
89032
89035
  let isSingleUser = null;
@@ -89284,6 +89287,12 @@ var sendMessage_default = (defaultFuncs, api, ctx) => {
89284
89287
  }
89285
89288
  }
89286
89289
  };
89290
+ return function sendMessage(msg, threadID, callback, replyToMessage, isGroup) {
89291
+ const promise = sendMessageCore(msg, threadID, callback, replyToMessage, isGroup);
89292
+ if (typeof callback === "function") promise.catch(() => {
89293
+ });
89294
+ return promise;
89295
+ };
89287
89296
  };
89288
89297
 
89289
89298
  // src/deltas/apis/messaging/sendTypingIndicator.ts
@@ -90824,6 +90833,7 @@ function pinMessage_default(defaultFuncs, api, ctx) {
90824
90833
  }
90825
90834
 
90826
90835
  // src/deltas/apis/mqtt/sendMessageMqtt.ts
90836
+ var DEFAULT_RETRY_DELAYS_MS = [900, 1600, 2400, 3500, 5e3, 7e3];
90827
90837
  function preUploadedId(item) {
90828
90838
  if (typeof item === "number" && Number.isFinite(item)) return String(item);
90829
90839
  if (typeof item === "string" && /^\d{6,}$/.test(item.trim())) return item.trim();
@@ -90927,6 +90937,8 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
90927
90937
  resolveFunc = resolve;
90928
90938
  rejectFunc = reject;
90929
90939
  });
90940
+ returnPromise.catch(() => {
90941
+ });
90930
90942
  const userCallback = typeof callback === "function" ? callback : null;
90931
90943
  let finished2 = false;
90932
90944
  const finish = (err, data2) => {
@@ -90943,51 +90955,14 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
90943
90955
  if (!callback) {
90944
90956
  callback = finish;
90945
90957
  }
90958
+ const done = () => userCallback ? returnPromise.then(() => null, () => null) : returnPromise;
90946
90959
  if (!ctx.mqttClient || !ctx.mqttClient.connected) {
90947
90960
  const error2 = new Error("MQTT client is not connected. Cannot send message.");
90948
90961
  finish(error2);
90949
- return returnPromise;
90962
+ return done();
90950
90963
  }
90951
90964
  const timestamp = Date.now();
90952
- const otid = generateOfflineThreadingID();
90953
- const epoch_id = (BigInt(Date.now()) << 22n).toString();
90954
- const request_id = ctx.wsReqNumber = (ctx.wsReqNumber || 0) + 1;
90955
- const payload = getSendPayload(threadID, msg, otid);
90956
- const tasks = [{
90957
- label: "46",
90958
- payload,
90959
- queue_name: threadID.toString(),
90960
- task_id: 400,
90961
- failure_count: null
90962
- }, {
90963
- label: "21",
90964
- payload: {
90965
- thread_id: threadID.toString(),
90966
- last_read_watermark_ts: timestamp,
90967
- sync_group: 1
90968
- },
90969
- queue_name: threadID.toString(),
90970
- task_id: 401,
90971
- failure_count: null
90972
- }];
90973
- if (replyToMessage) {
90974
- tasks[0].payload.reply_metadata = {
90975
- reply_source_id: replyToMessage,
90976
- reply_source_type: 1,
90977
- reply_type: 0
90978
- };
90979
- }
90980
- const form = {
90981
- app_id: "2220391788200892",
90982
- payload: {
90983
- tasks,
90984
- epoch_id,
90985
- version_id: "24804310205905615",
90986
- data_trace_id: `#${Buffer.from(String(Math.random())).toString("base64").replace(/=+$/g, "")}`
90987
- },
90988
- request_id,
90989
- type: 3
90990
- };
90965
+ let attachmentIds = null;
90991
90966
  if (msg.attachment) {
90992
90967
  try {
90993
90968
  const inputs = Array.isArray(msg.attachment) ? msg.attachment : [msg.attachment];
@@ -91004,20 +90979,62 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
91004
90979
  ids.push(file && typeof file === "object" ? String(Object.values(file)[0]) : String(file));
91005
90980
  }
91006
90981
  }
91007
- form.payload.tasks[0].payload.attachment_fbids = ids;
90982
+ attachmentIds = ids;
91008
90983
  } catch (err) {
91009
90984
  error("Attachment upload failed:", err);
91010
90985
  callback(err);
91011
- return returnPromise;
90986
+ return done();
91012
90987
  }
91013
90988
  }
91014
- form.payload.tasks.forEach((task) => {
91015
- task.payload = JSON.stringify(task.payload);
91016
- });
91017
- form.payload = JSON.stringify(form.payload);
91018
- const fallbackMessageID = `mid.${otid}`;
91019
90989
  const mqttClient = ctx.mqttClient;
91020
- const result = await new Promise((resolve) => {
90990
+ const buildForm = () => {
90991
+ const otid = generateOfflineThreadingID();
90992
+ const epoch_id = (BigInt(Date.now()) << 22n).toString();
90993
+ const request_id = ctx.wsReqNumber = (ctx.wsReqNumber || 0) + 1;
90994
+ const payload = getSendPayload(threadID, msg, otid);
90995
+ if (attachmentIds) payload.attachment_fbids = attachmentIds;
90996
+ const tasks = [{
90997
+ label: "46",
90998
+ payload,
90999
+ queue_name: threadID.toString(),
91000
+ task_id: 400,
91001
+ failure_count: null
91002
+ }, {
91003
+ label: "21",
91004
+ payload: {
91005
+ thread_id: threadID.toString(),
91006
+ last_read_watermark_ts: Date.now(),
91007
+ sync_group: 1
91008
+ },
91009
+ queue_name: threadID.toString(),
91010
+ task_id: 401,
91011
+ failure_count: null
91012
+ }];
91013
+ if (replyToMessage) {
91014
+ tasks[0].payload.reply_metadata = {
91015
+ reply_source_id: replyToMessage,
91016
+ reply_source_type: 1,
91017
+ reply_type: 0
91018
+ };
91019
+ }
91020
+ const form = {
91021
+ app_id: "2220391788200892",
91022
+ payload: {
91023
+ tasks,
91024
+ epoch_id,
91025
+ version_id: "24804310205905615",
91026
+ data_trace_id: `#${Buffer.from(String(Math.random())).toString("base64").replace(/=+$/g, "")}`
91027
+ },
91028
+ request_id,
91029
+ type: 3
91030
+ };
91031
+ form.payload.tasks.forEach((task) => {
91032
+ task.payload = JSON.stringify(task.payload);
91033
+ });
91034
+ form.payload = JSON.stringify(form.payload);
91035
+ return { form, request_id, otid };
91036
+ };
91037
+ const publishAndWait = (form, request_id) => new Promise((resolve) => {
91021
91038
  let settled = false;
91022
91039
  let timer = null;
91023
91040
  const cleanup = () => {
@@ -91046,6 +91063,7 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
91046
91063
  let threadIDFromAck = null;
91047
91064
  let failure = null;
91048
91065
  let serverError = null;
91066
+ let softFailure = null;
91049
91067
  const steps = parsed.payload?.step;
91050
91068
  const visit = (node) => {
91051
91069
  if (!Array.isArray(node)) return;
@@ -91057,10 +91075,10 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
91057
91075
  threadIDFromAck = String(node[2][1]);
91058
91076
  }
91059
91077
  if (node[1] === "markOptimisticMessageFailed") {
91060
- failure = { error: "Couldn't send.", errorDescription: "Message failed on server." };
91078
+ softFailure = typeof node[3] === "string" ? node[3] : "Message failed on server.";
91061
91079
  }
91062
91080
  if (node[1] === "updateSubscriptErrorMessage" || node[1] === "fatalError") {
91063
- serverError = typeof node[3] === "string" ? node[3] : "Couldn't send.";
91081
+ softFailure = typeof node[3] === "string" ? node[3] : typeof node[4] === "string" ? node[4] : "Couldn't send.";
91064
91082
  }
91065
91083
  }
91066
91084
  for (const child of node) visit(child);
@@ -91070,7 +91088,8 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
91070
91088
  messageID: resolvedMessageID,
91071
91089
  threadID: threadIDFromAck,
91072
91090
  failure,
91073
- serverError
91091
+ serverError,
91092
+ softFailure
91074
91093
  });
91075
91094
  };
91076
91095
  if (mqttClient && typeof mqttClient.on === "function") {
@@ -91081,24 +91100,55 @@ var sendMessageMqtt_default = (defaultFuncs, api, ctx) => {
91081
91100
  });
91082
91101
  timer = setTimeout(() => settle2({ timeout: true }), 15e3);
91083
91102
  });
91103
+ const retryDelays = (() => {
91104
+ const override = ctx.globalOptions && ctx.globalOptions.mqttSendRetryDelaysMs;
91105
+ return Array.isArray(override) && override.length ? override : DEFAULT_RETRY_DELAYS_MS;
91106
+ })();
91107
+ let result = null;
91108
+ let lastOtid = "";
91109
+ for (let attempt = 0; attempt <= retryDelays.length; attempt++) {
91110
+ const built = buildForm();
91111
+ lastOtid = built.otid;
91112
+ result = await publishAndWait(built.form, built.request_id);
91113
+ if (!result.failure && !result.serverError && !result.softFailure) break;
91114
+ if ((result.failure || result.serverError) && attempt >= 2) break;
91115
+ if (attempt < retryDelays.length) {
91116
+ await sleep(retryDelays[attempt] + Math.floor(Math.random() * 400));
91117
+ }
91118
+ }
91084
91119
  if (result.failure || result.serverError) {
91085
91120
  const err = result.failure || { error: result.serverError };
91086
91121
  if (err.error && err.error === 1545012) {
91087
91122
  warn("sendMessageMqtt [MQTT]", `Got error 1545012. Bot is not part of the conversation ${threadID}`);
91088
91123
  finish(null, null);
91089
- return returnPromise;
91124
+ return done();
91090
91125
  }
91091
91126
  error("sendMessageMqtt", "Send failed:", err.error || err);
91092
91127
  finish(err);
91093
- return returnPromise;
91128
+ return done();
91129
+ }
91130
+ if (result.softFailure) {
91131
+ warn(
91132
+ "sendMessageMqtt [MQTT]",
91133
+ `Facebook rejected the message (${result.softFailure}); thread ${threadID}. Retried ${retryDelays.length} times without success; continuing without failing the bot.`
91134
+ );
91135
+ finish(null, {
91136
+ threadID: result.threadID || threadID.toString(),
91137
+ messageID: result.messageID || null,
91138
+ timestamp,
91139
+ type: replyToMessage ? "message_reply" : "message",
91140
+ error: result.softFailure,
91141
+ success: false
91142
+ });
91143
+ return done();
91094
91144
  }
91095
91145
  finish(null, {
91096
91146
  threadID: result.threadID || threadID.toString(),
91097
- messageID: result.messageID || fallbackMessageID,
91147
+ messageID: result.messageID || `mid.${lastOtid}`,
91098
91148
  timestamp,
91099
91149
  type: replyToMessage ? "message_reply" : "message"
91100
91150
  });
91101
- return returnPromise;
91151
+ return done();
91102
91152
  };
91103
91153
  };
91104
91154
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyneoaz/metachat",
3
- "version": "6.0.5",
3
+ "version": "6.0.7",
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 && node test/reaction-validation.test.cjs && node test/api-surface-fixes.test.cjs && node test/threadinfo-regression.test.cjs && node test/new-modules.test.cjs && node test/mention-parsing.test.cjs && node test/pending-support.test.cjs && node test/music-token-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 && node test/new-modules.test.cjs && node test/mention-parsing.test.cjs && node test/pending-support.test.cjs && node test/music-token-resilience.test.cjs && node test/send-failure.test.cjs",
61
61
  "audit": "npm audit",
62
62
  "audit:fix": "npm audit fix"
63
63
  },