























1+import { describe, expect, it } from "vitest";
2+import { resolveFeishuMessageDedupeKey } from "./dedupe-key.js";
3+import type { FeishuMessageEvent } from "./event-types.js";
4+5+function textEvent(overrides: {
6+messageId: string;
7+createTime?: string;
8+senderOpenId?: string;
9+chatId?: string;
10+text?: string;
11+}): FeishuMessageEvent {
12+return {
13+sender: { sender_id: { open_id: overrides.senderOpenId ?? "ou-user" } },
14+message: {
15+message_id: overrides.messageId,
16+chat_id: overrides.chatId ?? "oc-dm",
17+chat_type: "p2p",
18+message_type: "text",
19+content: JSON.stringify({ text: overrides.text ?? "hello" }),
20+create_time: overrides.createTime,
21+},
22+};
23+}
24+25+describe("resolveFeishuMessageDedupeKey", () => {
26+it("collapses redelivered text with a fresh message_id but identical sender/chat/create_time/content (#46778)", () => {
27+const first = resolveFeishuMessageDedupeKey(
28+textEvent({ messageId: "om_first", createTime: "1710000000000" }),
29+);
30+const retry = resolveFeishuMessageDedupeKey(
31+textEvent({ messageId: "om_second", createTime: "1710000000000" }),
32+);
33+expect(first).toBeDefined();
34+expect(retry).toBe(first);
35+});
36+37+it("keeps genuine repeat sends distinct via create_time", () => {
38+const a = resolveFeishuMessageDedupeKey(
39+textEvent({ messageId: "om_a", createTime: "1710000000000" }),
40+);
41+const b = resolveFeishuMessageDedupeKey(
42+textEvent({ messageId: "om_b", createTime: "1710000001000" }),
43+);
44+expect(a).not.toBe(b);
45+});
46+47+it("does not collide across senders, chats, or content", () => {
48+const base = textEvent({ messageId: "om_1", createTime: "1710000000000" });
49+const otherSender = textEvent({
50+messageId: "om_2",
51+createTime: "1710000000000",
52+senderOpenId: "ou-other",
53+});
54+const otherChat = textEvent({ messageId: "om_3", createTime: "1710000000000", chatId: "oc-2" });
55+const otherText = textEvent({ messageId: "om_4", createTime: "1710000000000", text: "bye" });
56+const baseKey = resolveFeishuMessageDedupeKey(base);
57+expect(resolveFeishuMessageDedupeKey(otherSender)).not.toBe(baseKey);
58+expect(resolveFeishuMessageDedupeKey(otherChat)).not.toBe(baseKey);
59+expect(resolveFeishuMessageDedupeKey(otherText)).not.toBe(baseKey);
60+});
61+62+it("falls back to message_id for text without a stable retry anchor", () => {
63+const key = resolveFeishuMessageDedupeKey(textEvent({ messageId: "om_no_time" }));
64+expect(key).toBe("om_no_time");
65+});
66+67+it("falls back to message_id for malformed create_time", () => {
68+const key = resolveFeishuMessageDedupeKey(
69+textEvent({ messageId: "om_bad_time", createTime: "1710000000000ms" }),
70+);
71+expect(key).toBe("om_bad_time");
72+});
73+74+it("keeps media keyed by message_id plus media key", () => {
75+const event: FeishuMessageEvent = {
76+sender: { sender_id: { open_id: "ou-user" } },
77+message: {
78+message_id: "om_media",
79+chat_id: "oc-dm",
80+chat_type: "p2p",
81+message_type: "image",
82+content: JSON.stringify({ image_key: "img_123" }),
83+create_time: "1710000000000",
84+},
85+};
86+expect(resolveFeishuMessageDedupeKey(event)).toBe(
87+JSON.stringify(["om_media", "image_key:img_123"]),
88+);
89+});
90+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。