@@ -70,37 +70,70 @@ go: github.com/kagal-dev/example
7070Self-hosted SVG version badges rendered by ` badge-maker ` with
7171pre-computed logo data URIs (extracted from ` simple-icons ` at
7272development time, inlined as base64 constants to avoid bundling the
73- full icon library into the Nitro server). The shared rendering logic
74- lives in ` server/utils/badge.ts ` (Nitro auto-imports it).
73+ full icon library into the Nitro server). The ` BadgeHandler ` class
74+ in ` server/utils/badge.ts ` handles method dispatch, input
75+ validation, cache headers, SVG rendering, and cache management —
76+ each endpoint provides only its identity and fetch callback.
7577
7678### Endpoints
7779
78- - ` /api/badge/go/{module} ` — fetches version from
80+ - ` GET /api/badge/go/{module}` — fetches version from
7981 ` proxy.golang.org/{module}/@latest ` . Validates the path
8082 matches a Go module pattern (domain with dot in first segment).
81- - ` /api/badge/npm/{package} ` — fetches version from
83+ - ` GET /api/badge/npm/{package}` — fetches version from
8284 ` registry.npmjs.org/{package}/latest ` . Validates the name
8385 matches npm naming rules (` @scope/name ` or ` name ` ).
84-
85- Both endpoints return ` image/svg+xml ` with cache headers (1 hour
86- for successful responses, 60 seconds for errors). Unknown packages
87- render a grey "unknown" badge instead of erroring.
86+ - ` DELETE ` on either endpoint busts the version cache
87+ and purges the CF edge cache (current PoP), so a freshly
88+ published version is picked up on the next GET.
89+ - Other methods return ` 405 ` with an ` Allow ` header.
90+
91+ Successful responses carry split ` Cache-Control ` (` max-age=3600 `
92+ for browsers, ` s-maxage=300 ` for the CF edge), a weak ` ETag `
93+ from the version string (conditional requests return ` 304 ` ),
94+ and ` Last-Modified ` from the upstream timestamp. Unknown packages render a
95+ grey "unknown" badge with a 60-second TTL.
96+
97+ ### Caching
98+
99+ Version lookups are cached in Cloudflare KV via Nitro's
100+ ` useStorage('versions') ` (` server/utils/version-cache.ts ` ).
101+ Each entry has a per-key TTL: 1 hour for successful lookups,
102+ 60 seconds for errors — failed entries auto-expire, preventing
103+ unbounded growth from bogus package names. The KV namespace
104+ binding (` VERSIONS_KV ` ) is configured in ` wrangler.toml ` and
105+ mounted in ` nuxt.config.ts ` ; local dev uses a memory driver.
106+
107+ Concurrent requests for the same key at the TTL boundary are
108+ coalesced via an in-flight promise map — only one upstream
109+ fetch runs, and only the originating caller writes to KV.
110+
111+ KV operations degrade gracefully: read failures fall through
112+ to an upstream fetch, write failures are logged but the badge
113+ is still returned.
114+
115+ Logging uses ` consola ` with tagged instances (` badge:go ` ,
116+ ` badge:npm ` , ` version-cache ` ).
88117
89118### Components
90119
91120- ` BadgeVersion ` — generic badge ` <img> ` wrapper with loading
92121 skeleton, error fallback (shows alt text), and SSR hydration
93122 handling (` onMounted ` checks ` complete ` + ` naturalWidth ` ).
123+ - ` BadgeVersionGo ` — MDC wrapper (` :badge-version-go{mod="..."} ` ).
124+ Optional ` dir ` prop for subpackages sharing a parent ` go.mod ` —
125+ badge fetches the parent module version, link points to the
126+ subpackage on pkg.go.dev.
127+ - ` BadgeVersionNpm ` — MDC wrapper (` :badge-version-npm{pkg="..."} ` ).
94128- Icons use ` @nuxt/icon ` with ` <Icon name="simple-icons:github" /> `
95129 instead of hand-rolled SVG components.
96130
97131## Content DB in development
98132
99- After adding or removing content files, run ` pnpm generate `
100- before ` pnpm dev ` . The cloudflare preset serves the client-side
101- SQL dump from Nitro build storage, which only ` generate ` (or
102- ` build ` ) populates. Without this step, SSR works but client-side
103- navigation will 404.
133+ ` pnpm dev ` runs ` nuxt cleanup ` before starting the dev server,
134+ removing stale client-side SQL dumps that would otherwise cause
135+ SPA 404s. The dev server regenerates the content database on
136+ startup, so no separate ` pnpm generate ` step is needed.
104137
105138## Dev server management
106139
0 commit comments