49 lines
1.5 KiB
TypeScript
49 lines
1.5 KiB
TypeScript
import { readFile } from "node:fs/promises"
|
|
import path from "node:path"
|
|
|
|
export type LocalFiles = Readonly<{
|
|
readText(path: string): Promise<string>
|
|
readBytes(path: string): Promise<Uint8Array>
|
|
mime(path: string): Promise<string>
|
|
}>
|
|
|
|
export type LocalAttachment =
|
|
| Readonly<{ type: "text"; mime: "image/svg+xml"; content: string }>
|
|
| Readonly<{ type: "binary"; mime: string; content: Uint8Array }>
|
|
|
|
export function readLocalAttachment(file: string) {
|
|
return readLocalAttachmentWith(
|
|
{
|
|
readText: (value) => readFile(value, "utf8"),
|
|
readBytes: (value) => readFile(value),
|
|
mime: async (value) => mimeTypes[path.extname(value).toLowerCase()] ?? "application/octet-stream",
|
|
},
|
|
file,
|
|
)
|
|
}
|
|
|
|
const mimeTypes: Record<string, string> = {
|
|
".avif": "image/avif",
|
|
".gif": "image/gif",
|
|
".jpeg": "image/jpeg",
|
|
".jpg": "image/jpeg",
|
|
".pdf": "application/pdf",
|
|
".png": "image/png",
|
|
".svg": "image/svg+xml",
|
|
".webp": "image/webp",
|
|
}
|
|
|
|
export async function readLocalAttachmentWith(files: LocalFiles, path: string): Promise<LocalAttachment | undefined> {
|
|
const mime = await files.mime(path).catch(() => undefined)
|
|
if (!mime) return
|
|
if (mime === "image/svg+xml") {
|
|
const content = await files.readText(path).catch(() => undefined)
|
|
if (!content) return
|
|
return { type: "text", mime, content }
|
|
}
|
|
if (!mime.startsWith("image/") && mime !== "application/pdf") return
|
|
const content = await files.readBytes(path).catch(() => undefined)
|
|
if (!content) return
|
|
return { type: "binary", mime, content }
|
|
}
|