dsh-feishu-bot 0.19.8 → 0.19.9
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/cli.js +63 -0
- package/dist/cli.js.map +1 -1
- package/dist/plugin.js +63 -0
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -12138,6 +12138,34 @@ async function tryHandleCommand(text, ctx) {
|
|
|
12138
12138
|
import { createHash } from "crypto";
|
|
12139
12139
|
var CARD_STREAM_THROTTLE_MS = 100;
|
|
12140
12140
|
var CARD_PATCH_ATTEMPTS = 2;
|
|
12141
|
+
var MAX_CARD_WITHDRAW_RECOVERIES = 3;
|
|
12142
|
+
function isMessageWithdrawn(error) {
|
|
12143
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12144
|
+
const stack = [error];
|
|
12145
|
+
while (stack.length > 0) {
|
|
12146
|
+
const node = stack.pop();
|
|
12147
|
+
if (node === null || node === void 0) continue;
|
|
12148
|
+
if (typeof node === "string") {
|
|
12149
|
+
if (node.toLowerCase().includes("withdrawn")) return true;
|
|
12150
|
+
continue;
|
|
12151
|
+
}
|
|
12152
|
+
if (typeof node !== "object" || seen.has(node)) continue;
|
|
12153
|
+
seen.add(node);
|
|
12154
|
+
if (Array.isArray(node)) {
|
|
12155
|
+
for (const item of node) stack.push(item);
|
|
12156
|
+
continue;
|
|
12157
|
+
}
|
|
12158
|
+
const record = node;
|
|
12159
|
+
if (record["code"] === 230011) return true;
|
|
12160
|
+
if (typeof record["message"] === "string" && record["message"].toLowerCase().includes("withdrawn")) return true;
|
|
12161
|
+
if (typeof record["msg"] === "string" && record["msg"].toLowerCase().includes("withdrawn")) return true;
|
|
12162
|
+
for (const key of ["response", "data", "error", "errors"]) {
|
|
12163
|
+
const value = record[key];
|
|
12164
|
+
if (value !== void 0 && value !== null) stack.push(value);
|
|
12165
|
+
}
|
|
12166
|
+
}
|
|
12167
|
+
return false;
|
|
12168
|
+
}
|
|
12141
12169
|
function toLarkSendOptions(options) {
|
|
12142
12170
|
const sendOptions = {};
|
|
12143
12171
|
if (options?.replyTo) sendOptions.replyTo = options.replyTo;
|
|
@@ -12172,6 +12200,7 @@ var ResilientCardStreamController = class {
|
|
|
12172
12200
|
timer;
|
|
12173
12201
|
inFlight;
|
|
12174
12202
|
reanchorInFlight;
|
|
12203
|
+
recoveries = 0;
|
|
12175
12204
|
async update(card) {
|
|
12176
12205
|
if (this.closed || this.failed) return;
|
|
12177
12206
|
this.latest = card;
|
|
@@ -12219,6 +12248,7 @@ var ResilientCardStreamController = class {
|
|
|
12219
12248
|
for (let attempt = 1; attempt <= CARD_PATCH_ATTEMPTS; attempt += 1) {
|
|
12220
12249
|
try {
|
|
12221
12250
|
await this.channel.updateCard(this.messageId, snapshot);
|
|
12251
|
+
this.recoveries = 0;
|
|
12222
12252
|
return;
|
|
12223
12253
|
} catch (error) {
|
|
12224
12254
|
lastError = error;
|
|
@@ -12227,6 +12257,19 @@ var ResilientCardStreamController = class {
|
|
|
12227
12257
|
attempt,
|
|
12228
12258
|
error: error instanceof Error ? error.message : String(error)
|
|
12229
12259
|
});
|
|
12260
|
+
if (isMessageWithdrawn(error) && this.recoveries < MAX_CARD_WITHDRAW_RECOVERIES) {
|
|
12261
|
+
try {
|
|
12262
|
+
await this.healFromWithdrawal();
|
|
12263
|
+
} catch (healError) {
|
|
12264
|
+
log.warn("lark-card-stream", "heal-failed", {
|
|
12265
|
+
messageId: this.messageId,
|
|
12266
|
+
error: healError instanceof Error ? healError.message : String(healError)
|
|
12267
|
+
});
|
|
12268
|
+
break;
|
|
12269
|
+
}
|
|
12270
|
+
attempt -= 1;
|
|
12271
|
+
continue;
|
|
12272
|
+
}
|
|
12230
12273
|
}
|
|
12231
12274
|
}
|
|
12232
12275
|
this.failed = true;
|
|
@@ -12246,6 +12289,26 @@ var ResilientCardStreamController = class {
|
|
|
12246
12289
|
});
|
|
12247
12290
|
}
|
|
12248
12291
|
}
|
|
12292
|
+
/**
|
|
12293
|
+
* Re-create the process card at the conversation tail after the target message
|
|
12294
|
+
* was withdrawn (Feishu `230011` / "The message was withdrawn"). The message
|
|
12295
|
+
* is already gone, so there is nothing to recall: we send a fresh card carrying
|
|
12296
|
+
* the latest snapshot and rebind the controller to its new message id. Unlike
|
|
12297
|
+
* `reanchor()` this must NOT `await this.inFlight`, because we are already
|
|
12298
|
+
* running inside the in-flight flush; the recovery budget
|
|
12299
|
+
* (`MAX_CARD_WITHDRAW_RECOVERIES`) is enforced by the caller so a hostile loop
|
|
12300
|
+
* cannot spawn cards forever.
|
|
12301
|
+
*/
|
|
12302
|
+
async healFromWithdrawal() {
|
|
12303
|
+
const card = this.latest;
|
|
12304
|
+
if (card === void 0) throw new Error("Feishu card re-creation has no snapshot to send");
|
|
12305
|
+
this.dirty = false;
|
|
12306
|
+
const sent = await this.channel.send(this.chatId, { card }, {});
|
|
12307
|
+
if (!sent.messageId) throw new Error("Feishu card re-creation returned no message_id");
|
|
12308
|
+
this.messageId = sent.messageId;
|
|
12309
|
+
this.failed = false;
|
|
12310
|
+
this.recoveries += 1;
|
|
12311
|
+
}
|
|
12249
12312
|
/**
|
|
12250
12313
|
* Recall the current card and re-create it as the newest top-level message in
|
|
12251
12314
|
* the chat, rebinding the controller to the fresh message id. Because Feishu
|