From a9e89ff343cd9b7d69e0dd21399f46af0667565a Mon Sep 17 00:00:00 2001 From: sabraman Date: Sun, 22 Mar 2026 23:30:33 +0300 Subject: [PATCH 1/2] fix: serve jpeg project favicons with image mime --- apps/server/src/projectFaviconRoute.test.ts | 19 +++++++++++++++++++ apps/server/src/projectFaviconRoute.ts | 1 + 2 files changed, 20 insertions(+) diff --git a/apps/server/src/projectFaviconRoute.test.ts b/apps/server/src/projectFaviconRoute.test.ts index a346e513eb..03d9893fff 100644 --- a/apps/server/src/projectFaviconRoute.test.ts +++ b/apps/server/src/projectFaviconRoute.test.ts @@ -117,6 +117,25 @@ describe("tryHandleProjectFaviconRequest", () => { }); }); + it("serves jpeg icons discovered from source metadata with the correct content type", async () => { + const projectDir = makeTempDir("t3code-favicon-route-jpeg-"); + const iconPath = path.join(projectDir, "public", "brand", "logo.jpeg"); + fs.mkdirSync(path.dirname(iconPath), { recursive: true }); + fs.writeFileSync( + path.join(projectDir, "index.html"), + '', + ); + fs.writeFileSync(iconPath, "jpeg-favicon", "utf8"); + + await withRouteServer(async (baseUrl) => { + const pathname = `/api/project-favicon?cwd=${encodeURIComponent(projectDir)}`; + const response = await request(baseUrl, pathname); + expect(response.statusCode).toBe(200); + expect(response.contentType).toContain("image/jpeg"); + expect(response.body).toBe("jpeg-favicon"); + }); + }); + it("resolves icon link when href appears before rel in HTML", async () => { const projectDir = makeTempDir("t3code-favicon-route-html-order-"); const iconPath = path.join(projectDir, "public", "brand", "logo.svg"); diff --git a/apps/server/src/projectFaviconRoute.ts b/apps/server/src/projectFaviconRoute.ts index cf234ad894..895693e962 100644 --- a/apps/server/src/projectFaviconRoute.ts +++ b/apps/server/src/projectFaviconRoute.ts @@ -5,6 +5,7 @@ import path from "node:path"; const FAVICON_MIME_TYPES: Record = { ".png": "image/png", ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", ".svg": "image/svg+xml", ".ico": "image/x-icon", }; From 5206d85bce24920f476f72a2d172e76030e7ba2c Mon Sep 17 00:00:00 2001 From: sabraman Date: Sun, 22 Mar 2026 23:55:46 +0300 Subject: [PATCH 2/2] refactor: reuse shared mime lookup for project favicons --- apps/server/src/projectFaviconRoute.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/apps/server/src/projectFaviconRoute.ts b/apps/server/src/projectFaviconRoute.ts index 895693e962..6fd1b3b2e7 100644 --- a/apps/server/src/projectFaviconRoute.ts +++ b/apps/server/src/projectFaviconRoute.ts @@ -1,14 +1,7 @@ import fs from "node:fs"; import http from "node:http"; import path from "node:path"; - -const FAVICON_MIME_TYPES: Record = { - ".png": "image/png", - ".jpg": "image/jpeg", - ".jpeg": "image/jpeg", - ".svg": "image/svg+xml", - ".ico": "image/x-icon", -}; +import Mime from "@effect/platform-node/Mime"; const FALLBACK_FAVICON_SVG = ``; @@ -72,8 +65,7 @@ function isPathWithinProject(projectCwd: string, candidatePath: string): boolean } function serveFaviconFile(filePath: string, res: http.ServerResponse): void { - const ext = path.extname(filePath).toLowerCase(); - const contentType = FAVICON_MIME_TYPES[ext] ?? "application/octet-stream"; + const contentType = Mime.getType(filePath) ?? "application/octet-stream"; fs.readFile(filePath, (readErr, data) => { if (readErr) { res.writeHead(500, { "Content-Type": "text/plain" });