---
import DownloadSizes from './DownloadSizes.astro';
import { discoveryServiceCount } from '../data/discovery-coverage';
import stats from '../data/stats.json';
const formatCount = (value: number | string) => {
const count = Number(value);
return new Intl.NumberFormat('en-US').format(Number.isFinite(count) ? count : 0);
};
const formatDate = (value: string) => {
if (!value) return '—';
const date = new Date(value);
return Number.isNaN(date.getTime()) ? value : date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric', timeZone: 'UTC' });
};
const base = import.meta.env.BASE_URL;
// The platform figures come from the same snapshot the download row renders,
// so the count can never drift from the data again. `binarySizes` carries one
// key per shipped release target — linux-x86_64, linux-aarch64, macos-aarch64,
// windows-x86_64 and windows-aarch64 — and this card used to hard-code "3"
// (OS families) while the download row silently dropped linux-aarch64.
const binarySizes = (stats.binarySizes ?? {}) as Record<string, number | undefined>;
const targetKeys = Object.keys(binarySizes);
const platformCount = targetKeys.length;
const familyLabels: Record<string, string> = { macos: 'macOS', linux: 'Linux', windows: 'Windows' };
const archLabels: Record<string, string> = { aarch64: 'ARM', x86_64: 'x86_64' };
const distinct = (values: string[]) => [...new Set(values)];
const familyOrder = ['macos', 'linux', 'windows'];
const platformFamilies = distinct(targetKeys.map((key) => key.split('-')[0])).sort((left, right) => {
const leftIndex = familyOrder.indexOf(left);
const rightIndex = familyOrder.indexOf(right);
return (leftIndex < 0 ? familyOrder.length : leftIndex) - (rightIndex < 0 ? familyOrder.length : rightIndex);
});
const platformFamilyLabel = platformFamilies.map((family) => familyLabels[family] ?? family).join(' · ');
const platformArchLabel = distinct(targetKeys.map((key) => key.split('-')[1]))
.map((arch) => archLabels[arch] ?? arch)
.join(' + ');
---
<section class="stats-section section" aria-labelledby="stats-title">
<div class="container">
<div class="stats-heading mb-7 flex flex-wrap items-end justify-between gap-x-12 gap-y-3">
<div>
<span class="eyebrow">public pulse</span>
<h2 id="stats-title" class="mt-1 mb-2 text-[clamp(22px,2.6vw,32px)] leading-[1.15]">Small binary.<br />Real reach.</h2>
</div>
<p class="m-0 max-w-[58ch] text-sm text-(--muted)">Build-time numbers from the public package and release channels, with a quiet optional refresh in your browser.</p>
</div>
<div class="relative">
<div class="stats stats-vertical w-full border border-base-300 bg-base-100 sm:stats-horizontal stats-grid" aria-live="polite">
<div class="stat stat-card">
<div class="stat-title stat-label">package version</div>
<div class="stat-value" data-stat="version">v{stats.version}</div>
<div class="stat-desc">the current published line</div>
</div>
<div class="stat stat-card">
<div class="stat-title stat-label">crates.io downloads</div>
<div class="stat-value" data-stat="crateDownloads">{formatCount(stats.crateDownloads)}</div>
<div class="stat-desc"><span data-stat="crateDownloads30d">{formatCount(stats.crateDownloads30d)}</span> in the last 30 days</div>
</div>
<div class="stat stat-card">
<div class="stat-title stat-label">platforms</div>
<div class="stat-value">{platformCount}</div>
<div class="stat-desc">{platformFamilyLabel} ({platformArchLabel})</div>
</div>
<div class="stat stat-card">
<div class="stat-title stat-label">services</div>
<div class="stat-value">{discoveryServiceCount}</div>
<div class="stat-desc">one namespaced binary</div>
</div>
</div>
<div class="stat-sparks" aria-hidden="true">
<span class="stat-spark stat-spark-a"></span>
<span class="stat-spark stat-spark-b"></span>
<span class="stat-spark stat-spark-c"></span>
<span class="stat-spark stat-spark-d"></span>
<span class="stat-spark stat-spark-e"></span>
<span class="stat-spark stat-spark-f"></span>
</div>
</div>
{/* aria-label only reaches assistive tech on an element that has a role,
so this is a labelled region rather than a div that silently drops it. */}
<section class="stats-release-strip" aria-label="Release snapshot">
<div>
<span class="stat-label mb-0.5">latest release</span>
<strong class="text-base font-normal" data-stat="latestRelease">{stats.latestRelease || '—'}</strong>
<time class="mt-0.5 block text-xs text-(--muted)" data-stat="latestReleaseDate" datetime={stats.latestReleaseDate}>{formatDate(stats.latestReleaseDate)}</time>
</div>
<div>
<span class="stat-label mb-0.5">GitHub asset downloads</span>
<strong class="text-base font-normal" data-stat="githubDownloads">{formatCount(stats.githubDownloads)}</strong>
<span class="mt-0.5 block text-xs text-(--muted)">across all public releases</span>
</div>
</section>
<div class="stats-footnote">
<span class="status-dot" aria-hidden="true"></span>
<span>Snapshot refreshed <time data-stat="updatedAt" datetime={stats.updatedAt}>{formatDate(stats.updatedAt)}</time></span>
<a href={`${base}install/`}>Install the binary <span aria-hidden="true">→</span></a>
</div>
<DownloadSizes />
<noscript><p class="stats-noscript">Live refresh is off. These are the build-time public snapshot values.</p></noscript>
</div>
</section>
<script is:inline type="module">
const endpoints = {
crates: 'https://crates.io/api/v1/crates/grr-cli',
releases: 'https://api.github.com/repos/debanjanbasu/grr-cli/releases',
};
const numberText = (value) => {
const count = Number(value);
return Number.isFinite(count) ? new Intl.NumberFormat('en-US').format(count) : null;
};
const setText = (key, value) => {
const nextValue = String(value);
document.querySelectorAll(`[data-stat="${key}"]`).forEach((node) => {
if (node.textContent !== nextValue) node.textContent = nextValue;
});
};
const setDate = (key, value) => {
const date = new Date(value);
if (Number.isNaN(date.getTime())) return;
const nextText = date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
document.querySelectorAll(`[data-stat="${key}"]`).forEach((node) => {
if (node.textContent !== nextText) node.textContent = nextText;
// Keep the machine-readable date in step with the visible one. A <time>
// reading "Oct 3, 2026" while its `datetime` still carried the build
// timestamp is wrong for assistive tech and for anything reading the
// attribute — the live refresh was making the two disagree.
if (node.tagName === 'TIME') node.setAttribute('datetime', date.toISOString());
});
};
const refresh = async () => {
try {
const [crateResponse, releasesResponse] = await Promise.all([
fetch(endpoints.crates, { headers: { Accept: 'application/json' } }),
fetch(endpoints.releases, { headers: { Accept: 'application/vnd.github+json' } }),
]);
if (!crateResponse.ok || !releasesResponse.ok) return;
const [cratePayload, releasesPayload] = await Promise.all([crateResponse.json(), releasesResponse.json()]);
if (!cratePayload?.crate || !Array.isArray(releasesPayload)) return;
const crate = cratePayload.crate;
const total = numberText(crate.downloads);
const recent = numberText(crate.recent_downloads);
const githubTotal = releasesPayload.reduce((releaseTotal, release) => {
const assets = Array.isArray(release?.assets) ? release.assets : [];
return releaseTotal + assets.reduce((assetTotal, asset) => assetTotal + (Number(asset?.download_count) || 0), 0);
}, 0);
const latest = releasesPayload
.filter((release) => release && !release.draft)
.sort((left, right) => Date.parse(right.published_at ?? right.created_at ?? '') - Date.parse(left.published_at ?? left.created_at ?? ''))[0];
if (total !== null) setText('crateDownloads', total);
if (recent !== null) setText('crateDownloads30d', recent);
setText('githubDownloads', numberText(githubTotal) ?? '—');
if (latest?.tag_name) setText('latestRelease', latest.tag_name);
if (latest?.published_at || latest?.created_at) setDate('latestReleaseDate', latest.published_at ?? latest.created_at);
setDate('updatedAt', new Date().toISOString());
} catch {
return;
}
};
// The stats are a live nicety, not content: the section already renders
// build-time values, so the refresh is a pure enhancement. Running it
// during the load window put two cross-origin requests on the critical
// path, competing with the document, the stylesheet and the webfont for
// bandwidth on exactly the slow connections that need it most. So the
// refresh waits for `load` AND for the main thread to go idle, with a
// timeout so a busy page still gets fresh numbers eventually.
const whenIdle = (run) => {
if (document.readyState !== 'complete') {
window.addEventListener('load', () => { whenIdle(run); }, { once: true });
return;
}
if (typeof window.requestIdleCallback === 'function') {
window.requestIdleCallback(() => { run(); }, { timeout: 3000 });
return;
}
run();
};
whenIdle(refresh);
</script>