





















@@ -60,46 +60,45 @@ describe("sendMessageIMessage receipts", () => {
6060expect(result.receipt.sentAt).toBeGreaterThan(0);
6161});
626263-it("attaches a media receipt after attachment resolution", async () => {
63+it("sends explicit chat media-only payloads through send-attachment auto transport", async () => {
6464const client = createClient({ message_id: 12345 });
65+const runCliJson = vi
66+.fn()
67+.mockResolvedValueOnce({ messageId: "p:0/media-guid", transferGuid: "transfer-1" });
65686669const result = await sendMessageIMessage("chat_guid:chat-1", "", {
6770config: IMESSAGE_TEST_CFG,
6871 client,
6972mediaUrl: "/tmp/image.png",
7073resolveAttachmentImpl: async () => ({ path: "/tmp/image.png", contentType: "image/png" }),
74+ runCliJson,
7175});
727673-expect(result.messageId).toBe("12345");
77+expect(result.messageId).toBe("p:0/media-guid");
7478expect(result.sentText).toBe("");
7579expect(result.echoText).toBe("<media:image>");
76-expect(result.receipt.primaryPlatformMessageId).toBe("12345");
77-expect(result.receipt.platformMessageIds).toEqual(["12345"]);
78-expect(client.request).toHaveBeenCalledWith(
79-"send",
80-expect.objectContaining({
81-chat_guid: "chat-1",
82-file: "/tmp/image.png",
83-text: "",
84-}),
85-expect.any(Object),
86-);
80+expect(result.receipt.primaryPlatformMessageId).toBe("p:0/media-guid");
81+expect(result.receipt.platformMessageIds).toEqual(["p:0/media-guid"]);
82+expect(client.request).not.toHaveBeenCalled();
83+expect(runCliJson.mock.calls).toEqual([
84+[["send-attachment", "--chat", "chat-1", "--file", "/tmp/image.png", "--transport", "auto"]],
85+]);
8786expect(result.receipt.raw).toEqual([
8887{
8988channel: "imessage",
90-messageId: "12345",
89+messageId: "p:0/media-guid",
9190conversationId: "chat-1",
9291meta: { targetKind: "chat_guid" },
9392},
9493]);
9594expect(result.receipt.parts).toEqual([
9695{
9796index: 0,
98-platformMessageId: "12345",
97+platformMessageId: "p:0/media-guid",
9998kind: "media",
10099raw: {
101100channel: "imessage",
102-messageId: "12345",
101+messageId: "p:0/media-guid",
103102conversationId: "chat-1",
104103meta: { targetKind: "chat_guid" },
105104},
@@ -108,6 +107,133 @@ describe("sendMessageIMessage receipts", () => {
108107expect(result.receipt.sentAt).toBeGreaterThan(0);
109108});
110109110+it("resolves chat_id media-only payloads before using send-attachment", async () => {
111+const client = createClient({ message_id: 12345 });
112+const runCliJson = vi
113+.fn()
114+.mockResolvedValueOnce({ guid: "any;+;group-guid" })
115+.mockResolvedValueOnce({ messageId: "p:0/media-guid" });
116+117+const result = await sendMessageIMessage("chat_id:42", "", {
118+config: IMESSAGE_TEST_CFG,
119+ client,
120+mediaUrl: "/tmp/image.png",
121+resolveAttachmentImpl: async () => ({ path: "/tmp/image.png", contentType: "image/png" }),
122+ runCliJson,
123+});
124+125+expect(result.messageId).toBe("p:0/media-guid");
126+expect(client.request).not.toHaveBeenCalled();
127+expect(runCliJson.mock.calls).toEqual([
128+[["group", "--chat-id", "42"]],
129+[
130+[
131+"send-attachment",
132+"--chat",
133+"any;+;group-guid",
134+"--file",
135+"/tmp/image.png",
136+"--transport",
137+"auto",
138+],
139+],
140+]);
141+});
142+143+it("falls back to the existing rpc send path when send-attachment is unavailable", async () => {
144+const client = createClient({ message_id: 12345 });
145+const runCliJson = vi.fn().mockRejectedValueOnce(new Error("unknown command send-attachment"));
146+147+const result = await sendMessageIMessage("chat_guid:chat-1", "", {
148+config: IMESSAGE_TEST_CFG,
149+ client,
150+mediaUrl: "/tmp/image.png",
151+resolveAttachmentImpl: async () => ({ path: "/tmp/image.png", contentType: "image/png" }),
152+ runCliJson,
153+});
154+155+expect(result.messageId).toBe("12345");
156+expect(runCliJson.mock.calls).toEqual([
157+[["send-attachment", "--chat", "chat-1", "--file", "/tmp/image.png", "--transport", "auto"]],
158+]);
159+expect(client.request).toHaveBeenCalledWith(
160+"send",
161+expect.objectContaining({
162+chat_guid: "chat-1",
163+file: "/tmp/image.png",
164+text: "",
165+}),
166+expect.any(Object),
167+);
168+});
169+170+it("falls back to the existing rpc send path when chat_id lookup is unavailable", async () => {
171+const client = createClient({ message_id: 12345 });
172+const runCliJson = vi.fn().mockRejectedValueOnce(new Error("private API bridge unavailable"));
173+174+const result = await sendMessageIMessage("chat_id:42", "", {
175+config: IMESSAGE_TEST_CFG,
176+ client,
177+mediaUrl: "/tmp/image.png",
178+resolveAttachmentImpl: async () => ({ path: "/tmp/image.png", contentType: "image/png" }),
179+ runCliJson,
180+});
181+182+expect(result.messageId).toBe("12345");
183+expect(runCliJson.mock.calls).toEqual([[["group", "--chat-id", "42"]]]);
184+expect(client.request).toHaveBeenCalledWith(
185+"send",
186+expect.objectContaining({
187+chat_id: 42,
188+file: "/tmp/image.png",
189+text: "",
190+}),
191+expect.any(Object),
192+);
193+});
194+195+it("rejects failed send-attachment json instead of reporting success", async () => {
196+const client = createClient({ message_id: 12345 });
197+const runCliJson = vi
198+.fn()
199+.mockResolvedValueOnce({ success: false, error: "attachment delivery failed" });
200+201+await expect(
202+sendMessageIMessage("chat_guid:chat-1", "", {
203+config: IMESSAGE_TEST_CFG,
204+ client,
205+mediaUrl: "/tmp/image.png",
206+resolveAttachmentImpl: async () => ({ path: "/tmp/image.png", contentType: "image/png" }),
207+ runCliJson,
208+}),
209+).rejects.toThrow("attachment delivery failed");
210+expect(client.request).not.toHaveBeenCalled();
211+});
212+213+it("keeps DM handle media sends on the existing rpc send path", async () => {
214+const client = createClient({ message_id: 12345 });
215+const runCliJson = vi.fn();
216+217+await sendMessageIMessage("+15551234567", "", {
218+config: IMESSAGE_TEST_CFG,
219+ client,
220+mediaUrl: "/tmp/image.png",
221+resolveAttachmentImpl: async () => ({ path: "/tmp/image.png", contentType: "image/png" }),
222+ runCliJson,
223+});
224+225+expect(runCliJson).not.toHaveBeenCalled();
226+expect(client.request).toHaveBeenCalledWith(
227+"send",
228+expect.objectContaining({
229+to: "+15551234567",
230+file: "/tmp/image.png",
231+text: "",
232+}),
233+expect.any(Object),
234+);
235+});
236+111237it("preserves literal media placeholder text when no attachment is sent", async () => {
112238const client = createClient({ guid: "p:0/imsg-text" });
113239此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。