${error}
`; } /** An admin page: the site's own look, with the console's sections and sign-out on top. */ export function adminPage(c: Context, ctx: AdminContext, title: string, body: Html): string { const tab = ([href, name]: (typeof SECTIONS)[number]) => html`${name}`; return page(ctx, { title: `${title} · admin`, description: "", path: c.req.path, body: html`To revoke access, rotate the write key in Scaleway and update kepr.toml.
`; } /** §24's Status section at `/admin`: the bucket, each repo's format, backups, the running version. */ export function registerStatus(app: Hono, ctx: AdminContext): void { app.get("/admin", async (c) => { let bucket: Html; try { const repos = await listRepos(ctx.sync.bucket); const formats = await Promise.all( repos.map(async (repo) => { try { await checkFormat(ctx.sync.bucket, repo); return html`Bucket reachable: ${plural(repos.length, "repo")}.
Bucket unreachable: ${String(error)}
`; } const { version } = (await Bun.file(`${import.meta.dir}/../../package.json`).json()) as { version: string; }; const lines = (await sourceLines()).toLocaleString("en-US"); const newest = backups(ctx.dataDir).at(-1); const backup = newest ? html`Last backup: ${newest.replace( /^(\d{4})(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)Z$/, "$1-$2-$3 $4:$5:$6 UTC", )}. download backup
` : html`No backup yet.
`; return c.html( adminPage( c, ctx, "status", html`Running kepr ${version}: ${lines} lines of TypeScript.