import { XrpcRequestError } from './bobbin.ts'; import type { Getter } from './reads.ts'; export interface DefaultBranch { name: string; hash: string; when: string; } export interface TreeFile { name: string; mode: string; size: number; } export interface TreeResponse { ref: string; files: TreeFile[]; } export interface BlobResponse { content: string; encoding: 'utf-8' | 'base64'; size: number; isBinary?: boolean; } export function createGit(pool: Getter, repoUri: string) { return { getDefaultBranch(): Promise { return pool.get('sh.tangled.repo.getDefaultBranch', { repo: repoUri }); }, listTree(ref: string): Promise { return pool.get('sh.tangled.repo.tree', { repo: repoUri, ref }); }, async getBlob(ref: string, path: string): Promise { let data: BlobResponse; try { data = await pool.get('sh.tangled.repo.blob', { repo: repoUri, ref, path }); } catch (err) { // A 4xx means the path/ref doesn't exist — treat as absent. Anything // else (pool exhaustion, 5xx) is a real failure and propagates. if (err instanceof XrpcRequestError) return null; throw err; } if (data.isBinary) return null; return data.encoding === 'base64' ? decodeBase64Utf8(data.content) : data.content; }, }; } /** Decode base64 as UTF-8 (atob alone yields Latin-1, mangling non-ASCII text). */ function decodeBase64Utf8(b64: string): string { const bin = atob(b64); const bytes = new Uint8Array(bin.length); for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i); return new TextDecoder().decode(bytes); } export type Git = ReturnType;