diff --git a/apps/server/src/wsServer.test.ts b/apps/server/src/wsServer.test.ts
index f12792a318..573fa77eb9 100644
--- a/apps/server/src/wsServer.test.ts
+++ b/apps/server/src/wsServer.test.ts
@@ -648,6 +648,24 @@ describe("WebSocket Server", () => {
expect(await response.text()).toContain("static-root");
});
+ it("serves immutable cache headers for static asset files", async () => {
+ const stateDir = makeTempDir("t3code-state-static-assets-");
+ const staticDir = makeTempDir("t3code-static-assets-");
+ const assetsDir = path.join(staticDir, "assets");
+ fs.mkdirSync(assetsDir, { recursive: true });
+ fs.writeFileSync(path.join(staticDir, "index.html"), "
static-root
", "utf8");
+ fs.writeFileSync(path.join(assetsDir, "index-abc123.js"), "console.log('hello');", "utf8");
+
+ server = await createTestServer({ cwd: "/test/project", stateDir, staticDir });
+ const addr = server.address();
+ const port = typeof addr === "object" && addr !== null ? addr.port : 0;
+ expect(port).toBeGreaterThan(0);
+
+ const response = await fetch(`http://127.0.0.1:${port}/assets/index-abc123.js`);
+ expect(response.status).toBe(200);
+ expect(response.headers.get("cache-control")).toBe("public, max-age=31536000, immutable");
+ });
+
it("rejects static path traversal attempts", async () => {
const stateDir = makeTempDir("t3code-state-static-traversal-");
const staticDir = makeTempDir("t3code-static-traversal-");
diff --git a/apps/server/src/wsServer.ts b/apps/server/src/wsServer.ts
index 2e6ac51b7f..1870e83364 100644
--- a/apps/server/src/wsServer.ts
+++ b/apps/server/src/wsServer.ts
@@ -565,7 +565,12 @@ export const createServer = Effect.fn(function* (): Effect.fn.Return<
respond(500, { "Content-Type": "text/plain" }, "Internal Server Error");
return;
}
- respond(200, { "Content-Type": contentType }, data);
+ const headers: Record = { "Content-Type": contentType };
+ const normalizedStaticRelativePath = staticRelativePath.replace(/\\/g, "/");
+ if (normalizedStaticRelativePath.startsWith("assets/")) {
+ headers["Cache-Control"] = "public, max-age=31536000, immutable";
+ }
+ respond(200, headers, data);
}),
).catch(() => {
if (!res.headersSent) {