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
Open Graph
Worker on open-graph.radicle.network that serves OG meta tags and preview card
images for social media embeds.
How it works
radicle.network is a plain static SPA. A Cloudflare Redirect Rule 302s social
media crawlers to open-graph.radicle.network, which returns HTML with OG tags.
The og:image points to /cards/... on the same domain, where the worker
renders PNG cards via Satori + resvg-wasm.
Browsers and search crawlers hit the SPA directly — no worker cost.
Routes
/*— OG HTML with meta tags (cached 2 hours)/cards/*— PNG card images (cached 2 hours)
Card routes mirror app routes: /cards/nodes/:host/:rid,
/cards/nodes/:host/:rid/issues/:id, etc. When API fetches fail, cards degrade:
specific item -> repo -> node -> home.
Cloudflare Redirect Rule
Rules > Redirect Rules on the radicle.dev zone:
(http.host eq "radicle.network") and (
(http.user_agent contains "Twitterbot") or
(http.user_agent contains "facebookexternalhit") or
(http.user_agent contains "Facebot") or
(http.user_agent contains "LinkedInBot") or
(http.user_agent contains "Slackbot") or
(http.user_agent contains "Discordbot") or
(http.user_agent contains "TelegramBot") or
(http.user_agent contains "WhatsApp") or
(http.user_agent contains "Pinterestbot") or
(http.user_agent contains "ZulipURLPreview") or
(http.user_agent contains "Bluesky Cardyb") or
(http.user_agent contains "Mastodon")
)
Dynamic 302 to
concat("https://open-graph.radicle.network", http.request.uri.path)
Rate Limiting
Security > WAF > Rate limiting rules on the radicle.network zone:
Verified bots are rate limited to 50 requests per 10 seconds across all of
radicle.network, with a 1 minute block.
Deploy
npm run deploy:open-graph # worker
npm run start:open-graph # local dev