mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-15 11:20:36 +08:00
Repos need not carry a `xyz.radicle.project` payload; the default branch can come from `xyz.radicle.crefs` alone. Such repos got no counts and no default branch, and failed schema validation in explorer, which broke the parse of a whole listing. httpd: - Add top-level `cobs` with issue, patch and bucketed release counts - Add top-level `defaultBranch`, qualified like the crefs payload - Omit a count the node cannot determine instead of reporting zero - Drop `head`: the tip is `refs[defaultBranch]` - Keep counts in the project payload for older clients until a major release - Keep the project payload when a COB read fails - Keep `meta.releases` a single count: delegate + other - Log and skip canonical ref rules and refs that fail to read, so one bad ref doesn't drop the default branch tip explorer: - Model `cobs` and `defaultBranch`, adapting older nodes to one shape - Resolve the default branch from the crefs HEAD on older nodes - Collect the shims for older httpd in http-client/lib/compat.ts, each naming the httpd release that the client can drop it with - Add `defaultBranchTip`, replacing `head`, with a fallback to the legacy `meta.head` - Make the project payload and its legacy meta optional - Fall back to the RID for the repo name, and show a placeholder for a missing name in repo cards and the header - Hide a counter instead of reading a missing count as zero - Fall back to a full-page check for "More" without counts - Add a `repo.sourceUnavailable` route for repos without a default branch or tip - Browse explicit revisions and offer the branch selector without a default branch - List these repos in repo grids and on the landing page - Say the node is older or built without releases - Scope release pages in the client, so views never call the shims - Read OG worker repos through the same compat shims - Share the repo name and default branch helpers with the OG worker CI: - Add check:open-graph, a wrangler deploy dry run - Run it in GitHub CI, Buildkite and check:ci - Install explorer's dependencies first: the worker resolves compat.ts imports, such as zod, from there Tests: - Test that a build without releases omits the count - Test that one failing rule keeps the others - Test the repo shape across httpd versions and the release shims - Test `hasMorePages` and `repoName` - Test repos without a project payload end to end
54 lines
1.4 KiB
TypeScript
54 lines
1.4 KiB
TypeScript
import type { BaseUrl, Repo, RepoListQuery } from "@http-client";
|
|
|
|
import { loadRepoActivity, type WeeklyActivity } from "@app/lib/commit";
|
|
import { HttpdClient } from "@http-client";
|
|
|
|
export interface RepoInfo {
|
|
repo: Repo;
|
|
baseUrl: BaseUrl;
|
|
activity: Promise<WeeklyActivity[]>;
|
|
}
|
|
|
|
export async function fetchRepoInfos(
|
|
baseUrl: BaseUrl,
|
|
query?: RepoListQuery,
|
|
delegate?: string,
|
|
activitySignal?: AbortSignal,
|
|
): Promise<RepoInfo[]> {
|
|
const api = new HttpdClient(baseUrl);
|
|
let repos: Repo[];
|
|
|
|
if (delegate) {
|
|
repos = await api.repo.getByDelegate(delegate, query);
|
|
} else {
|
|
repos = await api.repo.getAll(query);
|
|
}
|
|
|
|
return repos.map(repo => ({
|
|
repo,
|
|
baseUrl,
|
|
activity: loadRepoActivity(repo.rid, baseUrl, activitySignal).catch(e => {
|
|
if (import.meta.env.DEV && (e as Error)?.name !== "AbortError") {
|
|
console.warn("loadRepoActivity failed for", repo.rid, e);
|
|
}
|
|
return [];
|
|
}),
|
|
}));
|
|
}
|
|
|
|
export async function sortRepoInfosByActivity(
|
|
repos: RepoInfo[],
|
|
): Promise<RepoInfo[]> {
|
|
const withActivity = await Promise.all(
|
|
repos.map(async r => ({ info: r, activity: await r.activity })),
|
|
);
|
|
return withActivity
|
|
.sort((a, b) => {
|
|
if (a.activity.length === 0 && b.activity.length === 0) return 0;
|
|
if (a.activity.length === 0) return 1;
|
|
if (b.activity.length === 0) return -1;
|
|
return b.activity[0].time - a.activity[0].time;
|
|
})
|
|
.map(x => x.info);
|
|
}
|