From 1557c97e0e2f599ea77e362b641a12e62c1d36fe Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Wed, 4 Nov 2026 02:50:29 +0000 Subject: [PATCH 1/5] test(shared): reproduce #30576, hosted URLs nested in other links become thread links --- packages/shared/src/threadLinks.test.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/shared/src/threadLinks.test.ts b/packages/shared/src/threadLinks.test.ts index 0c19f18163e64..e8ced79531f0a 100644 --- a/packages/shared/src/threadLinks.test.ts +++ b/packages/shared/src/threadLinks.test.ts @@ -236,4 +236,14 @@ describe("hosted thread links", () => { ref("there", "t:1"), ]); }); + + it("leaves a hosted URL inside another URL or another link's label as written", () => { + const nested = [ + "https://example.com/?next=https://app.t3.codes/threads/one/same", + "[Example](https://example.com/?next=https://app.t3.codes/threads/one/same)", + "[ https://app.t3.codes/threads/one/same ](https://example.com)", + ].join("\n"); + expect(relabelThreadLinks(nested, local, () => "Title")).toBe(nested); + expect(threadLinkRefs(nested, local)).toEqual([]); + }); }); From 633178135bff5d41b90a98a4c15b8745f3069c64 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Wed, 4 Nov 2026 03:09:04 +0000 Subject: [PATCH 2/5] fix(shared): hosted thread URLs inside other links stay as written A hosted thread URL nested in another URL's query, or in a non-thread link's label or destination, was rewritten into a thread link. The link pattern was also quadratic on runs of `[` and on repeated unclosed `[a](t3-thread://v1/`. Every inline link is now matched whole, whatever its href, and only thread hrefs are rewritten. A bare hosted link needs a non-URL character before it. Labels and hrefs cannot contain `[`, so matching stays linear. Fixes pingdotgg/t3code#30576 --- packages/shared/src/threadLinks.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/threadLinks.ts b/packages/shared/src/threadLinks.ts index aba7d5f983a0a..9085f8725a939 100644 --- a/packages/shared/src/threadLinks.ts +++ b/packages/shared/src/threadLinks.ts @@ -11,8 +11,10 @@ const HOSTED_PREFIX = `${DEFAULT_HOSTED_APP_URL}/threads/`; const HOSTED_SEGMENT = "[A-Za-z0-9_%-]+"; const HOSTED_LINK = `${HOSTED_PREFIX.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&")}${HOSTED_SEGMENT}/${HOSTED_SEGMENT}`; // Code comes first in the alternation so a link written inside a code span or fence is skipped. +// Every inline link is taken whole, so a hosted URL in another link's label or href stays as written. +// Neither part may hold `[`, which keeps the scan linear: no match attempt runs past the next `[`. const THREAD_LINK_OUTSIDE_CODE = new RegExp( - String.raw`(?(\`{3,}|~{3,})[\s\S]*?(?:\2|$))|(?(\`+)[^\n]*?\4)|\[(?