authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-03-01 19:18:41-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-01 20:06:21-08:00
log58b932ffb8f20566c2c5ac58c252a911c7e80693
tree69efaaead2c64e3fe4d68edaefda3d61d64484ce
parentd58af33fba73936659158ba2167a00475889d1e5

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

3 files changed, 12 insertions(+), 2 deletions(-)

apps/server/src/attachmentStore.test.ts+9
...@@ -34,6 +34,15 @@ describe("attachmentStore", () => {...@@ -34,6 +34,15 @@ describe("attachmentStore", () => {
34 expect(parseThreadSegmentFromAttachmentId(fooBarId)).toBe("foo-bar");34 expect(parseThreadSegmentFromAttachmentId(fooBarId)).toBe("foo-bar");
35 });35 });
3636
37 it("normalizes created thread segments to lowercase", () => {
38 const attachmentId = createAttachmentId("Thread.Foo");
39 expect(attachmentId).toBeTruthy();
40 if (!attachmentId) {
41 return;
42 }
43 expect(parseThreadSegmentFromAttachmentId(attachmentId)).toBe("thread-foo");
44 });
45
37 it("resolves attachment path by id using the extension that exists on disk", () => {46 it("resolves attachment path by id using the extension that exists on disk", () => {
38 const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3code-attachment-store-"));47 const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3code-attachment-store-"));
39 try {48 try {
apps/server/src/attachmentStore.ts+1
...@@ -23,6 +23,7 @@ const ATTACHMENT_ID_PATTERN = new RegExp(...@@ -23,6 +23,7 @@ const ATTACHMENT_ID_PATTERN = new RegExp(
23export function toSafeThreadAttachmentSegment(threadId: string): string | null {23export function toSafeThreadAttachmentSegment(threadId: string): string | null {
24 const segment = threadId24 const segment = threadId
25 .trim()25 .trim()
26 .toLowerCase()
26 .replace(/[^a-z0-9_-]+/gi, "-")27 .replace(/[^a-z0-9_-]+/gi, "-")
27 .replace(/-+/g, "-")28 .replace(/-+/g, "-")
28 .replace(/^[-_]+|[-_]+$/g, "")29 .replace(/^[-_]+|[-_]+$/g, "")
apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts+2-2
...@@ -733,7 +733,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => {...@@ -733,7 +733,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => {
733 const projectionPipeline = yield* OrchestrationProjectionPipeline;733 const projectionPipeline = yield* OrchestrationProjectionPipeline;
734 const eventStore = yield* OrchestrationEventStore;734 const eventStore = yield* OrchestrationEventStore;
735 const now = new Date().toISOString();735 const now = new Date().toISOString();
736 const threadId = ThreadId.makeUnsafe("thread revert.files");736 const threadId = ThreadId.makeUnsafe("Thread Revert.Files");
737 const keepAttachmentId = "thread-revert-files-00000000-0000-4000-8000-000000000001";737 const keepAttachmentId = "thread-revert-files-00000000-0000-4000-8000-000000000001";
738 const removeAttachmentId = "thread-revert-files-00000000-0000-4000-8000-000000000002";738 const removeAttachmentId = "thread-revert-files-00000000-0000-4000-8000-000000000002";
739 const otherThreadAttachmentId =739 const otherThreadAttachmentId =
...@@ -948,7 +948,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => {...@@ -948,7 +948,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => {
948 const projectionPipeline = yield* OrchestrationProjectionPipeline;948 const projectionPipeline = yield* OrchestrationProjectionPipeline;
949 const eventStore = yield* OrchestrationEventStore;949 const eventStore = yield* OrchestrationEventStore;
950 const now = new Date().toISOString();950 const now = new Date().toISOString();
951 const threadId = ThreadId.makeUnsafe("thread delete.files");951 const threadId = ThreadId.makeUnsafe("Thread Delete.Files");
952 const attachmentId = "thread-delete-files-00000000-0000-4000-8000-000000000001";952 const attachmentId = "thread-delete-files-00000000-0000-4000-8000-000000000001";
953 const otherThreadAttachmentId =953 const otherThreadAttachmentId =
954 "thread-delete-files-extra-00000000-0000-4000-8000-000000000002";954 "thread-delete-files-extra-00000000-0000-4000-8000-000000000002";