diff --git a/packages/aws-lambda/README.md b/packages/aws-lambda/README.md
index 839a090..d8c96ba 100644
--- a/packages/aws-lambda/README.md
+++ b/packages/aws-lambda/README.md
@@ -114,27 +114,20 @@ For the project overview and the shared contract, see the [core documentation](h
Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh). Every bit helps! π
-### π Platinum Sponsor
-
-
-### π₯ Silver Sponsor
-
-
-### Generous Sponsors
+### Organization Sponsors
@@ -142,26 +135,26 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
@@ -169,31 +162,31 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
-With thanks to 37 past sponsors who helped get us here.
+With thanks to [37 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get us here.
## License
diff --git a/packages/core/README.md b/packages/core/README.md
index f148201..3ee9cff 100644
--- a/packages/core/README.md
+++ b/packages/core/README.md
@@ -468,27 +468,20 @@ For transport-specific quick-starts and options, see the adapter documentation:
Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh). Every bit helps! π
-### π Platinum Sponsor
-
-
-### π₯ Silver Sponsor
-
-
-### Generous Sponsors
+### Organization Sponsors
@@ -496,26 +489,26 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
@@ -523,31 +516,31 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
-With thanks to 37 past sponsors who helped get us here.
+With thanks to [37 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get us here.
## License
diff --git a/packages/fastify/README.md b/packages/fastify/README.md
index 12cf37e..877e60c 100644
--- a/packages/fastify/README.md
+++ b/packages/fastify/README.md
@@ -141,27 +141,20 @@ For the project overview and the shared contract, see the [core documentation](h
Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh). Every bit helps! π
-### π Platinum Sponsor
-
-
-### π₯ Silver Sponsor
-
-
-### Generous Sponsors
+### Organization Sponsors
@@ -169,26 +162,26 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
@@ -196,31 +189,31 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
-With thanks to 37 past sponsors who helped get us here.
+With thanks to [37 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get us here.
## License
diff --git a/packages/fetch/README.md b/packages/fetch/README.md
index b5936b5..6c46ca6 100644
--- a/packages/fetch/README.md
+++ b/packages/fetch/README.md
@@ -126,27 +126,20 @@ For the project overview and the shared contract this adapter implements, see th
Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh). Every bit helps! π
-### π Platinum Sponsor
-
-
-### π₯ Silver Sponsor
-
-
-### Generous Sponsors
+### Organization Sponsors
@@ -154,26 +147,26 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
@@ -181,31 +174,31 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
-With thanks to 37 past sponsors who helped get us here.
+With thanks to [37 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get us here.
## License
diff --git a/packages/node/README.md b/packages/node/README.md
index d54e2a7..9e48364 100644
--- a/packages/node/README.md
+++ b/packages/node/README.md
@@ -102,27 +102,20 @@ For the project overview and the shared contract this adapter implements, see th
Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh). Every bit helps! π
-### π Platinum Sponsor
-
-
-### π₯ Silver Sponsor
-
-
-### Generous Sponsors
+### Organization Sponsors
@@ -130,26 +123,26 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
@@ -157,31 +150,31 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
-With thanks to 37 past sponsors who helped get us here.
+With thanks to [37 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get us here.
## License
diff --git a/packages/peer/README.md b/packages/peer/README.md
index b15e82b..e1adaed 100644
--- a/packages/peer/README.md
+++ b/packages/peer/README.md
@@ -165,27 +165,20 @@ For the project overview and the shared contract this adapter implements, see th
Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh). Every bit helps! π
-### π Platinum Sponsor
-
-
-### π₯ Silver Sponsor
-
-
-### Generous Sponsors
+### Organization Sponsors
@@ -193,26 +186,26 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
@@ -220,31 +213,31 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
-With thanks to 37 past sponsors who helped get us here.
+With thanks to [37 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get us here.
## License
diff --git a/packages/shared/README.md b/packages/shared/README.md
index 6843db9..bae3abe 100644
--- a/packages/shared/README.md
+++ b/packages/shared/README.md
@@ -45,27 +45,20 @@ For the project overview and the public contract of the ecosystem, see the [core
Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh). Every bit helps! π
-### π Platinum Sponsor
-
-
-### π₯ Silver Sponsor
-
-
-### Generous Sponsors
+### Organization Sponsors
@@ -73,26 +66,26 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
@@ -100,31 +93,31 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
-With thanks to 37 past sponsors who helped get us here.
+With thanks to [37 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get us here.
## License
diff --git a/scripts/sync-sponsors.ts b/scripts/sync-sponsors.ts
index 4abb20d..17260f5 100644
--- a/scripts/sync-sponsors.ts
+++ b/scripts/sync-sponsors.ts
@@ -9,15 +9,22 @@ interface Sponsor {
amount: number
createdAt: string
tierTitle: string
+ tierTitlePlural: string
tierLevel: number
+ /** Extra rel tokens for the sponsor's link (e.g. `sponsored`); may be empty. */
+ rel: string
link: string
- org: boolean
- sidebarSize?: string
- sidebarLogo?: string
+ /** Tagline, present on sponsors that bought an ad slot. */
+ description?: string
+ /** Brand tint behind the ad card, both themes required together. */
+ background?: { light: string, dark: string }
+ /** 1-based ad-grid position the sponsor bought. */
+ slot?: number
[key: string]: unknown
}
const SPONSORS_SOURCE_URL = 'https://raw.githubusercontent.com/middleapi/static/refs/heads/main/sponsors.json'
+const PAST_SPONSORS_URL = 'https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg'
const ROOT_DIR = process.cwd()
const README_FILE_NAME = 'README.md'
@@ -47,17 +54,9 @@ async function findReadmes(dir: string): Promise {
return result.concat(...subResults)
}
-function withTracking(url: string): string {
- try {
- const tracked = new URL(url)
-
- tracked.searchParams.set('ref', 'orpc')
-
- return tracked.toString()
- }
- catch {
- return url
- }
+/** `noopener` always, plus whatever extra tokens the data carries. */
+function relAttribute(sponsor: Sponsor): string {
+ return ['noopener', sponsor.rel].filter(Boolean).join(' ')
}
function escapeHtml(value: string): string {
@@ -77,13 +76,48 @@ function getTierImageSizeAndColumns(tierLevel: number, tierLevels: number[]): [c
return [column, Math.floor(838 / column)]
}
+/**
+ * The slot sponsors' cards, mirroring the docs ad cards β logo on the left,
+ * name over tagline on the right β but without the brand backgrounds (GitHub
+ * strips inline styles anyway). One card per row. The oversized cell width is
+ * a preferred width, not a minimum: GitHub caps tables at the container, so
+ * the card spans the full row on any screen and the text wraps on phones
+ * instead of scrolling. One cell per card, the logo floated with the
+ * deprecated-but-sanitizer-safe `align`/`hspace` attributes, so no table
+ * border cuts through the card.
+ */
+function buildSlotCards(slotSponsors: Sponsor[]): string[] {
+ const lines = ['']
+
+ for (const sponsor of slotSponsors) {
+ const name = escapeHtml(sponsor.name ?? sponsor.login)
+ const description = escapeHtml(sponsor.description ?? '')
+
+ lines.push(' ')
+ lines.push(` ${name} ${description} | `)
+ lines.push('
')
+ }
+
+ lines.push('
')
+ lines.push('')
+
+ return lines
+}
+
function buildSponsorsSection(sponsors: Sponsor[]): string {
const activeSponsors = sponsors.filter(sponsor => sponsor.tierLevel > 0 && sponsor.amount > 0)
const pastSponsors = sponsors.filter(sponsor => sponsor.tierLevel <= 0 || sponsor.amount <= 0)
+ // Slot sponsors are featured as cards up top; the tier tables below carry
+ // everyone else so nobody appears twice.
+ const slotSponsors = activeSponsors
+ .filter(sponsor => sponsor.slot !== undefined)
+ .sort((a, b) => a.slot! - b.slot!)
+ const tieredSponsors = activeSponsors.filter(sponsor => sponsor.slot === undefined)
+
const groupedSponsors = new Map()
- for (const sponsor of activeSponsors) {
+ for (const sponsor of tieredSponsors) {
const group = groupedSponsors.get(sponsor.tierLevel)
if (group) {
@@ -101,6 +135,13 @@ function buildSponsorsSection(sponsors: Sponsor[]): string {
'',
]
+ if (slotSponsors.length > 0) {
+ lines.push(...buildSlotCards(slotSponsors))
+ }
+
+ // Sizes rank against every active tier, slot sponsors' tiers included, so
+ // featuring the top tiers as cards does not inflate the tables below them.
+ const sizeTierLevels = [...new Set(activeSponsors.map(sponsor => sponsor.tierLevel))].sort((a, b) => b - a)
const tierLevels = [...groupedSponsors.keys()].sort((a, b) => b - a)
for (const tierLevel of tierLevels) {
@@ -110,8 +151,8 @@ function buildSponsorsSection(sponsors: Sponsor[]): string {
continue
}
- const tierTitle = tierSponsors[0]?.tierTitle ?? `Tier ${tierLevel}`
- const [columns, imageSize] = getTierImageSizeAndColumns(tierLevel, tierLevels)
+ const tierTitle = tierSponsors[0]?.tierTitlePlural ?? `Tier ${tierLevel}`
+ const [columns, imageSize] = getTierImageSizeAndColumns(tierLevel, sizeTierLevels)
lines.push(`### ${tierTitle}`)
lines.push('')
@@ -123,7 +164,7 @@ function buildSponsorsSection(sponsors: Sponsor[]): string {
const displayName = sponsor.name ?? sponsor.login
const escapedName = escapeHtml(displayName)
- lines.push(` }) ${escapedName} | `)
+ lines.push(` }) ${escapedName} | `)
const isRowEnd = (index + 1) % columns === 0
const isLast = index === tierSponsors.length - 1
@@ -142,7 +183,7 @@ function buildSponsorsSection(sponsors: Sponsor[]): string {
if (pastSponsors.length > 0) {
const noun = pastSponsors.length === 1 ? 'past sponsor' : 'past sponsors'
- lines.push(`With thanks to ${pastSponsors.length} ${noun} who helped get us here.`)
+ lines.push(`With thanks to [${pastSponsors.length} ${noun}](${PAST_SPONSORS_URL}) who helped get us here.`)
lines.push('')
}
@@ -160,7 +201,10 @@ function replaceSponsorsSection(content: string, replacement: string): string {
const nextHeadingIndex = content.indexOf('\n## ', startIndex + heading.length)
const endIndex = nextHeadingIndex === -1 ? content.length : nextHeadingIndex + 1
- return `${content.slice(0, startIndex)}${replacement}${content.slice(endIndex)}`
+ // Trimmed to a single trailing newline, or a section replaced at the end of
+ // the file leaves a blank last line that eslint's markdown fixer removes β
+ // and the next sync would put back, forever.
+ return `${`${content.slice(0, startIndex)}${replacement}${content.slice(endIndex)}`.trimEnd()}\n`
}
async function main(): Promise {
@@ -170,7 +214,8 @@ async function main(): Promise {
throw new Error(`Failed to fetch sponsors data: ${response.status} ${response.statusText}`)
}
- const sponsors = (await response.json() as Sponsor[]).map(sponsor => ({ ...sponsor, link: withTracking(sponsor.link) }))
+ // Links arrive with their tracking params already baked in upstream.
+ const sponsors = await response.json() as Sponsor[]
const readmeFiles = await findReadmes(ROOT_DIR)
const replacement = buildSponsorsSection(sponsors)
diff --git a/tests/bun/README.md b/tests/bun/README.md
index 9c4732f..f614b0e 100644
--- a/tests/bun/README.md
+++ b/tests/bun/README.md
@@ -4,27 +4,20 @@
Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh). Every bit helps! π
-### π Platinum Sponsor
-
-
-### π₯ Silver Sponsor
-
-
-### Generous Sponsors
+### Organization Sponsors
@@ -32,26 +25,26 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
@@ -59,28 +52,28 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
-With thanks to 37 past sponsors who helped get us here.
+With thanks to [37 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get us here.
diff --git a/tests/deno/README.md b/tests/deno/README.md
index 4aaa554..139688a 100644
--- a/tests/deno/README.md
+++ b/tests/deno/README.md
@@ -4,27 +4,20 @@
Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh). Every bit helps! π
-### π Platinum Sponsor
-
-
-### π₯ Silver Sponsor
-
-
-### Generous Sponsors
+### Organization Sponsors
@@ -32,26 +25,26 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
@@ -59,28 +52,28 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
-With thanks to 37 past sponsors who helped get us here.
+With thanks to [37 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get us here.