diff --git a/packages/app/app/components/BadgeGenerator.vue b/packages/app/app/components/BadgeGenerator.vue index dc9784c5..ce513b3f 100644 --- a/packages/app/app/components/BadgeGenerator.vue +++ b/packages/app/app/components/BadgeGenerator.vue @@ -1,32 +1,18 @@ diff --git a/packages/app/server/api/repo/index.get.ts b/packages/app/server/api/repo/index.get.ts index 78dc034b..0eb88fc2 100644 --- a/packages/app/server/api/repo/index.get.ts +++ b/packages/app/server/api/repo/index.get.ts @@ -1,5 +1,6 @@ import type { H3Event } from "h3"; import { z } from "zod"; +import { getRepoReleaseCount } from "../../utils/bucket"; const querySchema = z.object({ owner: z.string(), @@ -16,6 +17,8 @@ const getRepoInfo = defineCachedFunction( repo, }); + const releaseCount = 0; + return { id: data.id.toString(), name: data.name, @@ -27,6 +30,7 @@ const getRepoInfo = defineCachedFunction( url: data.html_url, homepageUrl: data.homepage || "", description: data.description || "", + releaseCount, }; } catch (error) { console.error( @@ -65,6 +69,7 @@ export default defineEventHandler(async (event) => { url: "", homepageUrl: "", description: "Error fetching repository data", + releaseCount: 0, }; } }); diff --git a/packages/app/server/routes/badge/[owner]/[repo].get.ts b/packages/app/server/routes/badge/[owner]/[repo].get.ts index ac76a8e9..80da34a4 100644 --- a/packages/app/server/routes/badge/[owner]/[repo].get.ts +++ b/packages/app/server/routes/badge/[owner]/[repo].get.ts @@ -5,6 +5,8 @@ import { createError, getQuery, } from "h3"; +import { getRepoReleaseCount } from "../../../utils/bucket"; +import { LOGO_BASE64 } from "../../../../shared/constants"; export default defineEventHandler(async (event) => { const { owner, repo } = getRouterParams(event) as { @@ -18,56 +20,23 @@ export default defineEventHandler(async (event) => { }); } - const { style = "flat", color = "000" } = getQuery(event) as Record< - string, - string - >; - const logoBase64 = getPkgPrNewLogoBase64(); + const releaseCount = await getRepoReleaseCount(event, owner, repo); + + const style = "flat"; + const color = "000"; + const shieldsUrl = `https://img.shields.io/static/v1?` + - `label=&message=${encodeURIComponent("pkg.pr.new")}` + + `label=&message=${encodeURIComponent(`${releaseCount} | pkg.pr.new`)}` + `&color=${color}` + `&style=${style}` + - `&logo=data:image/svg+xml;base64,${logoBase64}` + + `&logo=data:image/svg+xml;base64,${LOGO_BASE64}` + `&logoSize=auto`; const res = await fetch(shieldsUrl); const svg = await res.text(); setHeader(event, "Content-Type", "image/svg+xml"); - setHeader(event, "Cache-Control", "public, max-age=86400"); + setHeader(event, "Cache-Control", "public, max-age=86400, immutable"); return svg; }); - -function getPkgPrNewLogoBase64(): string { - const logo = ` - - - - - - - - - - - - - - - - - - - - - - - - - - -`; - - return Buffer.from(logo).toString("base64"); -} diff --git a/packages/app/server/utils/bucket.ts b/packages/app/server/utils/bucket.ts index 1dd5c1b5..5b629131 100644 --- a/packages/app/server/utils/bucket.ts +++ b/packages/app/server/utils/bucket.ts @@ -120,3 +120,40 @@ export function useDebugBucket(event: Event) { useDebugBucket.key = "debug"; useDebugBucket.base = joinKeys(useBucket.base, useDebugBucket.key); + +export async function getRepoReleaseCount( + event: Event, + owner: string, + repo: string, +): Promise { + try { + const binding = useBinding(event); + const prefix = `${usePackagesBucket.base}:${owner}:${repo}:`; + + const uniqueCommitShas = new Set(); + let cursor: string | undefined; + + do { + const response = await binding.list({ + cursor, + limit: 1000, + prefix, + } as any); + + for (const { key } of response.objects) { + if (!key.startsWith(prefix)) continue; + + const trimmedKey = key.slice(prefix.length); + const [sha] = trimmedKey.split(":"); + if (sha) uniqueCommitShas.add(sha); + } + + cursor = response.truncated ? response.cursor : undefined; + } while (cursor); + + return uniqueCommitShas.size; + } catch (error) { + console.error(`Error counting releases for ${owner}/${repo}:`, error); + return 0; + } +} diff --git a/packages/app/shared/constants.ts b/packages/app/shared/constants.ts new file mode 100644 index 00000000..2e7ddfd5 --- /dev/null +++ b/packages/app/shared/constants.ts @@ -0,0 +1,36 @@ +const LOGO_SVG = ` + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +function svgToBase64(svgString: string): string { + if (typeof Buffer !== "undefined") { + return Buffer.from(svgString, "utf-8").toString("base64"); + } + return btoa(unescape(encodeURIComponent(svgString))); +} +export const LOGO_BASE64 = svgToBase64(LOGO_SVG);