import { HttpError } from "../errors";
import { findObject, openObject } from "./objects";
import { parseLfsPointer } from "./pointer";
import { chargeBandwidth } from "./quota";
import type { RepoRow } from "~/lib/types";
const IMAGE_TYPES_BY_EXTENSION: Record<string, string> = {
png: "image/png",
jpg: "image/jpeg",
jpeg: "image/jpeg",
gif: "image/gif",
webp: "image/webp",
avif: "image/avif",
ico: "image/x-icon",
};
/** LFS content has no sniffed type, so images are typed by extension to stay previewable. */
export function lfsImageType(path: string): string {
const extension = path.split(".").pop()?.toLowerCase() ?? "";
return IMAGE_TYPES_BY_EXTENSION[extension] ?? "application/octet-stream";
}
/** Swaps an LFS pointer for its stored content, charging the owner's bandwidth; null when bytes are not a pointer. */
export async function lfsContentFor(
repo: Pick<RepoRow, "id" | "fork_of_id" | "owner_id" | "visibility">,
bytes: Uint8Array,
): Promise<R2ObjectBody | null> {
const pointer = parseLfsPointer(bytes);
if (!pointer) return null;
const object = await openObject(repo, pointer.oid);
if (!object) return null;
try {
await chargeBandwidth(repo.owner_id, object.size, repo.id);
} catch (error) {
await object.body.cancel();
if (error instanceof HttpError) return null;
throw error;
}
return object;
}