import { listRefs, resolveRevision } from "../../git/refs";
import type { ResolvedRevision } from "../../git/refs";
import { assertVisibleRevision } from "../../git/reachable";
import { withStore } from "../../git/store";
import { notFoundError } from "../../errors";
import type { RepoRow, TreeEntry } from "~/lib/types";
export const MAX_FILE_BYTES = 1024 * 1024;
const MAX_TREE_ENTRIES = 1000;
const decoder = new TextDecoder("utf-8", { fatal: true });
/** Resolves a branch, tag or reachable commit (default branch when omitted). Hidden commits stay hidden. */
export async function resolveRef(repo: RepoRow, ref: string | undefined): Promise<ResolvedRevision> {
const refs = await listRefs(repo);
const revision = resolveRevision(refs, ref || repo.default_branch);
if (!revision) throw notFoundError(`Unknown ref ${ref ?? repo.default_branch}`);
await assertVisibleRevision(repo, revision);
return revision;
}
export async function listTreeAt(repo: RepoRow, revision: ResolvedRevision, path: string) {
return withStore(repo.artifacts_name, async (store) => {
const commit = await store.commit(revision.sha);
const entry = commit ? await store.entryAtPath(commit.treeSha, path) : null;
if (!entry || entry.type !== "tree") throw notFoundError("Directory not found");
const entries: TreeEntry[] = await store.listTree(entry.sha, entry.path);
return { entries: entries.slice(0, MAX_TREE_ENTRIES), truncated: entries.length > MAX_TREE_ENTRIES };
});
}
export type FileRead = {
path: string;
sha: string;
size: number;
binary: boolean;
text: string | null;
base64: string | null;
};
/** Reads one blob; text when it decodes as UTF-8, base64 otherwise, and never more than MAX_FILE_BYTES. */