Skip to content

Commit 9b1590c

Browse files
committed
fix(outbound): ignore media sends without delivery identity
1 parent b3dc274 commit 9b1590c

2 files changed

Lines changed: 49 additions & 4 deletions

File tree

src/infra/outbound/deliver.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2180,6 +2180,48 @@ describe("deliverOutboundPayloads", () => {
21802180
expect(sendMediaOptions?.accountId).toBeUndefined();
21812181
});
21822182

2183+
it("suppresses plugin media sends when the adapter returns no delivery identity", async () => {
2184+
const sendMedia = vi.fn().mockResolvedValue({ channel: "matrix", messageId: "" });
2185+
const payloadOutcomes: unknown[] = [];
2186+
setActivePluginRegistry(
2187+
createTestRegistry([
2188+
{
2189+
pluginId: "matrix",
2190+
source: "test",
2191+
plugin: createOutboundTestPlugin({
2192+
id: "matrix",
2193+
outbound: {
2194+
deliveryMode: "direct",
2195+
sendText: vi.fn().mockResolvedValue({ channel: "matrix", messageId: "text-1" }),
2196+
sendMedia,
2197+
},
2198+
}),
2199+
},
2200+
]),
2201+
);
2202+
2203+
const results = await deliverOutboundPayloads({
2204+
cfg: {},
2205+
channel: "matrix",
2206+
to: "!explicit:example",
2207+
payloads: [{ text: "voice caption", mediaUrl: "file:///tmp/cron-tts.mp3" }],
2208+
skipQueue: true,
2209+
onPayloadDeliveryOutcome: (outcome) => {
2210+
payloadOutcomes.push(outcome);
2211+
},
2212+
});
2213+
2214+
expect(sendMedia).toHaveBeenCalledTimes(1);
2215+
expect(results).toStrictEqual([]);
2216+
expect(payloadOutcomes).toStrictEqual([
2217+
{
2218+
index: 0,
2219+
status: "suppressed",
2220+
reason: "adapter_returned_no_identity",
2221+
},
2222+
]);
2223+
});
2224+
21832225
it("forwards audioAsVoice through generic plugin media delivery", async () => {
21842226
const sendMedia = vi.fn(async () => ({
21852227
channel: "matrix" as const,

src/infra/outbound/deliver.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,10 +1891,14 @@ async function deliverOutboundPayloadsCore(
18911891
unit.overrides,
18921892
)
18931893
: await deliveryHandler.sendMedia(unit.caption ?? "", unit.mediaUrl, unit.overrides);
1894+
if (!hasDeliveryResultIdentity(delivery)) {
1895+
continue;
1896+
}
18941897
results.push(delivery);
18951898
firstMessageId ??= delivery.messageId;
18961899
lastMessageId = delivery.messageId;
18971900
}
1901+
const deliveredResults = results.slice(beforeCount);
18981902
await maybePinDeliveredMessage({
18991903
handler: deliveryHandler,
19001904
payload: effectivePayload,
@@ -1906,9 +1910,8 @@ async function deliverOutboundPayloadsCore(
19061910
handler: deliveryHandler,
19071911
payload: effectivePayload,
19081912
target: deliveryTarget,
1909-
results: results.slice(beforeCount),
1913+
results: deliveredResults,
19101914
});
1911-
const deliveredResults = results.slice(beforeCount);
19121915
if (deliveredResults.length > 0) {
19131916
recordPayloadOutcome({
19141917
index: payloadIndex,
@@ -1924,9 +1927,9 @@ async function deliverOutboundPayloadsCore(
19241927
}),
19251928
);
19261929
}
1927-
completeDeliveryDiagnostics(results.length - beforeCount);
1930+
completeDeliveryDiagnostics(deliveredResults.length);
19281931
emitMessageSent({
1929-
success: true,
1932+
success: deliveredResults.length > 0,
19301933
content: payloadSummary.hookContent ?? payloadSummary.text,
19311934
messageId: lastMessageId,
19321935
});

0 commit comments

Comments
 (0)