From 58b932ffb8f20566c2c5ac58c252a911c7e80693 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Sun, 1 Mar 2026 19:18:41 -0800 Subject: [PATCH] Normalize attachment thread segments to lowercase - Lowercase sanitized thread segments when creating attachment IDs - Add coverage for mixed-case thread IDs in attachment store and projection pipeline tests --- apps/server/src/attachmentStore.test.ts | 9 +++++++++ apps/server/src/attachmentStore.ts | 1 + .../src/orchestration/Layers/ProjectionPipeline.test.ts | 4 ++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/server/src/attachmentStore.test.ts b/apps/server/src/attachmentStore.test.ts index 147084c56583ee1ca6bb44332cc693b88e057f2f..8e1bc4218e34e0bfcd91b1595f497606b7902d0b 100644 --- a/apps/server/src/attachmentStore.test.ts +++ b/apps/server/src/attachmentStore.test.ts @@ -34,6 +34,15 @@ describe("attachmentStore", () => { expect(parseThreadSegmentFromAttachmentId(fooBarId)).toBe("foo-bar"); }); + it("normalizes created thread segments to lowercase", () => { + const attachmentId = createAttachmentId("Thread.Foo"); + expect(attachmentId).toBeTruthy(); + if (!attachmentId) { + return; + } + expect(parseThreadSegmentFromAttachmentId(attachmentId)).toBe("thread-foo"); + }); + it("resolves attachment path by id using the extension that exists on disk", () => { const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3code-attachment-store-")); try { diff --git a/apps/server/src/attachmentStore.ts b/apps/server/src/attachmentStore.ts index 59b6e499b2fc4a332525b8d3ebcdff86b6a7c3a8..248047e913a4e60c614b5f3cd1950a747789a048 100644 --- a/apps/server/src/attachmentStore.ts +++ b/apps/server/src/attachmentStore.ts @@ -23,6 +23,7 @@ const ATTACHMENT_ID_PATTERN = new RegExp( export function toSafeThreadAttachmentSegment(threadId: string): string | null { const segment = threadId .trim() + .toLowerCase() .replace(/[^a-z0-9_-]+/gi, "-") .replace(/-+/g, "-") .replace(/^[-_]+|[-_]+$/g, "") diff --git a/apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts b/apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts index ba1b0afdc4619da67a875a0bd76ba1e940ece898..741aa16f160522da476536891733acc50bf399e6 100644 --- a/apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts +++ b/apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts @@ -733,7 +733,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => { const projectionPipeline = yield* OrchestrationProjectionPipeline; const eventStore = yield* OrchestrationEventStore; const now = new Date().toISOString(); - const threadId = ThreadId.makeUnsafe("thread revert.files"); + const threadId = ThreadId.makeUnsafe("Thread Revert.Files"); const keepAttachmentId = "thread-revert-files-00000000-0000-4000-8000-000000000001"; const removeAttachmentId = "thread-revert-files-00000000-0000-4000-8000-000000000002"; const otherThreadAttachmentId = @@ -948,7 +948,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => { const projectionPipeline = yield* OrchestrationProjectionPipeline; const eventStore = yield* OrchestrationEventStore; const now = new Date().toISOString(); - const threadId = ThreadId.makeUnsafe("thread delete.files"); + const threadId = ThreadId.makeUnsafe("Thread Delete.Files"); const attachmentId = "thread-delete-files-00000000-0000-4000-8000-000000000001"; const otherThreadAttachmentId = "thread-delete-files-extra-00000000-0000-4000-8000-000000000002"; -- 2.54.0