clone

nostr relays on demand at <name>.bind.ws: claim one with your key, pay in zaps past the free allowance

main
bindws / src / git-catalog.ts
git-catalog.ts 1.7K
1// SQL Git namespaces retain their signed repository identity for quotas and2// portable backups. Their hash is independent of the relay's hostname.3import type { Relay } from "./relay.ts";45export const GIT_CATALOG_SCHEMA = `CREATE TABLE IF NOT EXISTS git_sqlite_catalog (6 repository TEXT PRIMARY KEY, owner TEXT NOT NULL, identifier TEXT NOT NULL, alternative INTEGER NOT NULL7);8CREATE INDEX IF NOT EXISTS git_sqlite_catalog_owner ON git_sqlite_catalog(owner);`;910// sqliteGitBytes is a logical payload breakdown, already included in the11// database's physical SQLite meter. It is never added to the R2 media meter.12export function sqliteGitBytes(relay: Relay, owner?: string, namespace = ""): number {13 const row = owner === undefined14 ? gitSql<{ bytes: number }>(relay, "SELECT coalesce(sum(compressed_bytes + metadata_bytes),0) AS bytes FROM git_sqlite_meta").one()15 : gitSql<{ bytes: number }>(relay, "SELECT coalesce(sum(m.compressed_bytes + m.metadata_bytes),0) AS bytes FROM git_sqlite_meta m LEFT JOIN git_sqlite_catalog c ON c.repository=m.repository WHERE c.owner=? OR m.repository=?", owner, namespace).one();16 return row.bytes;17}1819// gitSql accounts for SQL work outside the object store, including failed writes.20export function gitSql<T extends Record<string, SqlStorageValue> = Record<string, SqlStorageValue>>(relay: Relay, query: string, ...bindings: SqlStorageValue[]) {21 const cursor = relay.sql.exec<T>(query, ...bindings);22 let rows: T[];23 try { rows = cursor.toArray(); }24 finally { relay.meterPush(cursor.rowsRead, cursor.rowsWritten); }25 return { toArray: () => rows, one: () => { if (rows.length !== 1) throw new Error("Expected one Git SQL row"); return rows[0]; } };26}