import { repoDb } from "../scoped-db";
import { accountsById } from "../people";
import { randomId } from "../crypto";
import { assertBelowCap } from "../limits";
import { HttpError, forbidden, notFoundError } from "../errors";
const MAX_LOCKS_PER_REPO = 1000;
const MAX_LOCK_PATH = 1024;
export const DEFAULT_LOCK_PAGE = 100;
export const MAX_LOCK_PAGE = 100;
export type LfsLock = { id: string; path: string; locked_at: string; owner: { name: string } };
type LockRow = { id: string; path: string; created_at: number; owner_id: string; owner_name: string };
const LOCK_SELECT = "SELECT l.id, l.path, l.created_at, l.owner_id FROM lfs_locks l";
/** Owner names come from the D1 directory; locks whose owner account is gone are dropped, as the old join did. */
async function withOwners(rows: Array<Omit<LockRow, "owner_name">>): Promise<LockRow[]> {
const owners = await accountsById(rows.map((row) => row.owner_id));
return rows.flatMap((row) => {
const owner = owners.get(row.owner_id);
return owner ? [{ ...row, owner_name: owner.name }] : [];
});
}
async function findLock(repoId: string, where: string, value: string): Promise<LockRow | null> {
const row = await repoDb(repoId).first<Omit<LockRow, "owner_name">>(
`${LOCK_SELECT} WHERE l.repo_id = ? AND ${where}`,
repoId,
value,
);
return row ? ((await withOwners([row]))[0] ?? null) : null;
}
export function lockJson(row: LockRow): LfsLock {
return {
id: row.id,
path: row.path,
locked_at: new Date(row.created_at).toISOString(),