Files
Alfred/src/server/static.ts
2026-05-26 18:21:06 +08:00

61 lines
1.6 KiB
TypeScript

export interface StaticAssets {
files: Record<string, Blob>;
indexHtml: Blob;
}
const CONTENT_TYPES: Record<string, string> = {
".css": "text/css; charset=utf-8",
".html": "text/html; charset=utf-8",
".js": "text/javascript; charset=utf-8",
".json": "application/json; charset=utf-8",
".mjs": "text/javascript; charset=utf-8",
".png": "image/png",
".svg": "image/svg+xml",
".woff": "font/woff",
".woff2": "font/woff2",
};
export function contentTypeFor(path: string): string {
const dot = path.lastIndexOf(".");
if (dot === -1) return "application/octet-stream";
const ext = path.slice(dot);
return CONTENT_TYPES[ext] ?? "application/octet-stream";
}
export function hasFileExtension(path: string): boolean {
const lastSlash = path.lastIndexOf("/");
const segment = lastSlash === -1 ? path : path.slice(lastSlash + 1);
return segment.includes(".");
}
export function htmlResponse(html: Blob): Response {
return new Response(html, {
headers: {
"Cache-Control": "no-cache",
"Content-Type": "text/html; charset=utf-8",
},
});
}
export function serveStaticAsset(pathname: string, assets: StaticAssets): Response {
if (pathname === "/") {
return htmlResponse(assets.indexHtml);
}
const file = assets.files[pathname];
if (file) {
return new Response(file, {
headers: {
"Cache-Control": "public, max-age=31536000, immutable",
"Content-Type": contentTypeFor(pathname),
},
});
}
if (hasFileExtension(pathname)) {
return new Response("Not found", { status: 404 });
}
return htmlResponse(assets.indexHtml);
}