From ad55832cda175ac19fc2a74b5969d68c74b68cdb Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 25 Nov 2025 06:07:11 +0100 Subject: [PATCH] fix: strip trailing punctuation from MEDIA tokens and add tests --- src/index.core.test.ts | 25 +++++++++++++++++++++++++ src/media/parse.ts | 14 ++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/index.core.test.ts b/src/index.core.test.ts index 357b90e7a..73e32773e 100644 --- a/src/index.core.test.ts +++ b/src/index.core.test.ts @@ -223,6 +223,31 @@ describe("config and templating", () => { expect(result?.mediaUrl).toBe("/tmp/pic.png"); }); + it("captures MEDIA token with trailing JSON characters", async () => { + const runSpy = vi.spyOn(index, "runCommandWithTimeout").mockResolvedValue({ + stdout: 'MEDIA:/tmp/pic.png"} trailing', + stderr: "", + code: 0, + signal: null, + killed: false, + }); + const cfg = { + inbound: { + reply: { + mode: "command" as const, + command: ["echo", "{{Body}}"], + }, + }, + }; + const result = await index.getReplyFromConfig( + { Body: "hi", From: "+1", To: "+2" }, + undefined, + cfg, + runSpy, + ); + expect(result?.mediaUrl).toBe("/tmp/pic.png"); + }); + it("ignores invalid MEDIA lines with whitespace", async () => { const runSpy = vi.spyOn(index, "runCommandWithTimeout").mockResolvedValue({ stdout: "hello\nMEDIA: not a url with spaces\nrest\n", diff --git a/src/media/parse.ts b/src/media/parse.ts index b4e2491a2..f9be623fa 100644 --- a/src/media/parse.ts +++ b/src/media/parse.ts @@ -17,15 +17,21 @@ export function splitMediaFromOutput(raw: string): { let text = trimmedRaw; let mediaUrl: string | undefined; - const mediaLine = trimmedRaw.split("\n").find((line) => MEDIA_LINE_RE.test(line)); - if (!mediaLine) { + let mediaLine = trimmedRaw.split("\n").find((line) => MEDIA_LINE_RE.test(line)); + let mediaMatch = mediaLine?.match(MEDIA_TOKEN_RE) ?? trimmedRaw.match(MEDIA_TOKEN_RE); + if (!mediaMatch) { return { text: trimmedRaw }; } + if (!mediaLine && mediaMatch) { + mediaLine = mediaMatch[0]; + } let isValidMedia = false; - const mediaMatch = mediaLine.match(MEDIA_TOKEN_RE); if (mediaMatch?.[1]) { - const candidate = normalizeMediaSource(mediaMatch[1]); + const cleaned = mediaMatch[1] + .replace(/^[`"'[{(]+/, "") + .replace(/[`"'\\})\],]+$/, ""); + const candidate = normalizeMediaSource(cleaned); const looksLikeUrl = /^https?:\/\//i.test(candidate); const looksLikePath = candidate.startsWith("/") || candidate.startsWith("./"); const hasWhitespace = /\s/.test(candidate);