fix(channels): normalize MIME kind parsing and reaction fallbacks

This commit is contained in:
Peter Steinberger
2026-03-02 23:48:00 +00:00
parent 32ecd6f579
commit ea3b7dfde5
13 changed files with 114 additions and 21 deletions

View File

@@ -146,6 +146,31 @@ describe("signal mention gating", () => {
);
});
it("normalizes mixed-case parameterized attachment MIME in skipped pending history", async () => {
capturedCtx = undefined;
const groupHistories = new Map();
const handler = createSignalEventHandler(
createBaseSignalEventHandlerDeps({
cfg: createSignalConfig({ requireMention: true }),
historyLimit: 5,
groupHistories,
ignoreAttachments: false,
}),
);
await handler(
makeGroupEvent({
message: "",
attachments: [{ contentType: " Audio/Ogg; codecs=opus " }],
}),
);
expect(capturedCtx).toBeUndefined();
const entries = groupHistories.get("g1");
expect(entries).toHaveLength(1);
expect(entries[0].body).toBe("<media:audio>");
});
it("records quote text in pending history for skipped quote-only group messages", async () => {
await expectSkippedGroupHistory({ message: "", quoteText: "quoted context" }, "quoted context");
});

View File

@@ -29,7 +29,7 @@ import { resolveChannelGroupRequireMention } from "../../config/group-policy.js"
import { readSessionUpdatedAt, resolveStorePath } from "../../config/sessions.js";
import { danger, logVerbose, shouldLogVerbose } from "../../globals.js";
import { enqueueSystemEvent } from "../../infra/system-events.js";
import { mediaKindFromMime } from "../../media/constants.js";
import { kindFromMime } from "../../media/mime.js";
import { resolveAgentRoute } from "../../routing/resolve-route.js";
import {
DM_GROUP_ACCESS_REASON,
@@ -636,7 +636,7 @@ export function createSignalEventHandler(deps: SignalEventHandlerDeps) {
return "<media:attachment>";
}
const firstContentType = dataMessage.attachments?.[0]?.contentType;
const pendingKind = mediaKindFromMime(firstContentType ?? undefined);
const pendingKind = kindFromMime(firstContentType ?? undefined);
return pendingKind ? `<media:${pendingKind}>` : "<media:attachment>";
})();
const pendingBodyText = messageText || pendingPlaceholder || quoteText;
@@ -679,7 +679,7 @@ export function createSignalEventHandler(deps: SignalEventHandlerDeps) {
}
}
const kind = mediaKindFromMime(mediaType ?? undefined);
const kind = kindFromMime(mediaType ?? undefined);
if (kind) {
placeholder = `<media:${kind}>`;
} else if (dataMessage.attachments?.length) {

View File

@@ -1,6 +1,6 @@
import { loadConfig } from "../config/config.js";
import { resolveMarkdownTableMode } from "../config/markdown-tables.js";
import { mediaKindFromMime } from "../media/constants.js";
import { kindFromMime } from "../media/mime.js";
import { resolveOutboundAttachmentFromUrl } from "../media/outbound-attachment.js";
import { resolveSignalAccount } from "./accounts.js";
import { signalRpcRequest } from "./client.js";
@@ -130,7 +130,7 @@ export async function sendMessageSignal(
localRoots: opts.mediaLocalRoots,
});
attachments = [resolved.path];
const kind = mediaKindFromMime(resolved.contentType ?? undefined);
const kind = kindFromMime(resolved.contentType ?? undefined);
if (!message && kind) {
// Avoid sending an empty body when only attachments exist.
message = kind === "image" ? "<media:image>" : `<media:${kind}>`;