@shiinasaku/github-card 4.1.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,46 +1,102 @@
1
1
  <div align="center">
2
2
 
3
- <img src="assets/logo.svg" alt="GitHub Card" width="480" />
3
+ <img src="assets/logo.svg" alt="GitHub Card" width="520" />
4
4
 
5
- # GitHub Card
5
+ ### Beautiful, blazing-fast GitHub profile cards
6
6
 
7
- **Beautiful, blazing-fast GitHub profile cards as dynamic SVGs.**
8
- Drop one line in your README — get a live, auto-updating stats card.
7
+ Live SVG cards for your README — stars, commits, languages, all auto-updating. One line, zero config, edge-cached.
9
8
 
10
- [![Bun](https://img.shields.io/badge/Bun-1.x-f9f1e1?style=flat-square&logo=bun&logoColor=000)](assets/bun.svg)
11
- [![Elysia](https://img.shields.io/badge/ElysiaJS-1.x-7c3aed?style=flat-square)](assets/elysia.svg)
9
+ <br/>
10
+
11
+ [![npm](https://img.shields.io/npm/v/@shiinasaku/github-card?style=flat-square&label=npm&color=000)](https://www.npmjs.com/package/@shiinasaku/github-card)
12
+ [![Bun](https://img.shields.io/badge/Bun-1.x-f9f1e1?style=flat-square&logo=bun&logoColor=000)](https://bun.sh)
13
+ [![Elysia](https://img.shields.io/badge/Elysia-1.x-7c3aed?style=flat-square)](https://elysiajs.com)
12
14
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6?style=flat-square&logo=typescript&logoColor=fff)](https://www.typescriptlang.org)
13
15
  [![License: MIT](https://img.shields.io/badge/License-MIT-34d399?style=flat-square)](LICENSE)
14
16
  [![Deploy with Vercel](https://img.shields.io/badge/Deploy-Vercel-000?style=flat-square&logo=vercel)](https://vercel.com/new/clone?repository-url=https://github.com/ShiinaSaku/Github-Card)
15
17
 
16
- <img src="https://card.shiina.xyz/card/shiinasaku?theme=shiina" alt="Live demo card" width="500" />
18
+ <a href="https://card.shiina.xyz/card/shiinasaku?theme=shiina">
19
+ <img src="https://card.shiina.xyz/card/shiinasaku?theme=shiina" alt="Live demo — shiinasaku" width="520" />
20
+ </a>
21
+
22
+ <sub>Live instance · <code>shiinasaku</code> · theme <code>shiina</code> — updates itself as you code</sub>
17
23
 
18
24
  </div>
19
25
 
20
26
  ---
21
27
 
28
+ ### ✨ What's new in 4.2
29
+
30
+ > System-font only · no shipped `.woff2` · crisper text (`geometricPrecision`, tabular numbers) · new 24 px icons (MingCute / Huge / Tabler) · airy stat stack with 7 px gaps, no boxes · default `affiliations=owner` — org stars excluded unless `?affiliations=affiliated` · fully typed `github.ts` & `github-client`, cache v8.
31
+
32
+ ---
33
+
22
34
  ## Quickstart
23
35
 
24
- Paste this into your profile README (replace `shiinasaku` with your username):
36
+ Paste into your profile README — replace `shiinasaku` with your username:
25
37
 
26
38
  ```md
27
39
  [![GitHub Card](https://card.shiina.xyz/card/shiinasaku?theme=shiina)](https://github.com/shiinasaku)
28
40
  ```
29
41
 
30
- That's it. No sign-up, no build step — the card updates itself as you code.
42
+ That's it. No sign-up, no build — the card refreshes on every push.
43
+
44
+ <details>
45
+ <summary><b>Self-host / local dev</b></summary>
46
+
47
+ ```bash
48
+ bun install
49
+ cp .env.example .env # add GITHUB_TOKEN
50
+ bun dev # http://localhost:3000
51
+ ```
52
+
53
+ | Command | Action |
54
+ | ------------------- | --------------------- |
55
+ | `bun test` | Run 51 tests |
56
+ | `bun run typecheck` | Strict `tsc --noEmit` |
57
+ | `bun run lint` | oxlint |
58
+ | `bun run fmt` | oxfmt |
59
+
60
+ </details>
61
+
62
+ ---
31
63
 
32
64
  ## Why GitHub Card?
33
65
 
34
- - **One line, zero config** — an `<img>` tag is the entire integration.
35
- - **Edge-fast** — two-tier cache (in-memory + Redis) with stale-while-revalidate, ETag/304 support, and CDN cache headers. Warm requests render in microseconds.
36
- - **21 hand-tuned themes** — plus full per-slot color overrides with hex _or_ Tailwind palette tokens.
37
- - **Retina avatars** — profile images inlined as Base64 at 2x resolution.
38
- - **Adaptive layout** — width, text wrapping, and language legends are computed mathematically; nothing ever overlaps.
39
- - **Users _and_ orgs** — works for organization accounts out of the box.
40
- - **Glassmorphic depth** — layered ambient gradients track your accent color for volumetric light with zero runtime cost (pure SVG).
41
- - **OpenAPI documented** — explore the API interactively at [`/openapi`](https://card.shiina.xyz/openapi).
66
+ <table>
67
+ <tr>
68
+ <td width="50%">
69
+
70
+ **One line, zero config**<br/>
71
+ An `<img>` tag is the entire integration. No OAuth, no action.
72
+
73
+ **Edge-fast**<br/>
74
+ L1 memory + L2 Redis SWR, `s-maxage=1800`, `stale-while-revalidate`, `ETag`/`304`. Warm hits render in microseconds.
75
+
76
+ **Retina avatars**<br/>
77
+ Profile images inlined as Base64 at 2×, clipped + ringed in pure SVG.
78
+
79
+ </td>
80
+ <td width="50%">
42
81
 
43
- ## Themes
82
+ **Adaptive layout**<br/>
83
+ Width, wrapping, and legends measured with per-glyph metrics — nothing ever overlaps or clips.
84
+
85
+ **Users _and_ orgs**<br/>
86
+ `GET /card/:login` works for users and organizations.
87
+
88
+ **Glassmorphic depth**<br/>
89
+ Radial + linear ambient gradients track your accent for volumetric light at zero runtime cost.
90
+
91
+ </td>
92
+ </tr>
93
+ </table>
94
+
95
+ OpenAPI docs live at [`/openapi`](https://card.shiina.xyz/openapi). Pure ESM lib, zero server dep for `renderCard`.
96
+
97
+ ---
98
+
99
+ ## Themes — 21 hand-tuned
44
100
 
45
101
  Preview **every** theme with your own data:
46
102
 
@@ -54,31 +110,33 @@ Preview **every** theme with your own data:
54
110
  | `github_dark` · `dark` · `nord` · `dracula` | `forest` · `rose` · `cobalt` |
55
111
  | `tokyonight` · `synthwave` · `radical` · `monokai` | `gruvbox` · `merko` · `onedark` · `highcontrast` |
56
112
 
113
+ Add `?theme=tokyonight` or override any slot with hex or Tailwind tokens: `pink-400`, `#ff79c6`, `ff79c6`.
114
+
115
+ ---
116
+
57
117
  ## Customization
58
118
 
59
- Every visual slot is overridable. Colors accept hex (`ff79c6` or `#ff79c6`) and Tailwind tokens (`pink-400`).
60
-
61
- | Parameter | Type | Description |
62
- | -------------- | -------- | ------------------------------------------------------------------ |
63
- | `theme` | string | Built-in theme name (see table above) |
64
- | `bg_color` | string | Background fill |
65
- | `title_color` | string | Name / title text |
66
- | `text_color` | string | Stats, labels, and body text |
67
- | `icon_color` | string | Stat icons and ambient glow |
68
- | `border_color` | string | Card outline stroke |
69
- | `hide_border` | boolean | Remove the card outline |
70
- | `compact` | boolean | Slim layout: hides bio, pronouns, Twitter, and the language legend |
71
- | `animate` | boolean | Fade-in stats + animated language bar |
72
- | `hide` | string[] | Hide stats: `stars`, `commits`, `issues`, `repos`, `prs` |
73
- | `hide_langs` | string[] | Exclude languages by name (`hide_langs=html,css`) |
74
- | `show_langs` | string[] | Include _only_ these languages |
75
- | `lang_count` | 1–10 | Number of top languages (default `5`) |
76
- | `scope` | string | `personal` (default), `org`, or `all` contribution scope |
77
- | `orgs` | string[] | Restrict org-scope stats to these organizations |
78
- | `affiliations` | string | `affiliated` (default) or `owner` repositories |
79
- | `fields` | string[] | Fetch only what you need (e.g. `fields=stats`) |
80
-
81
- ### Examples
119
+ | Parameter | Type | Description |
120
+ | -------------- | :--------: | ----------------------------------------------------------------- |
121
+ | `theme` | `string` | Built-in theme (table above) |
122
+ | `bg_color` | `string` | Background fill |
123
+ | `title_color` | `string` | Name / title |
124
+ | `text_color` | `string` | Stats, labels, body |
125
+ | `icon_color` | `string` | Icons + ambient glow |
126
+ | `border_color` | `string` | Card outline |
127
+ | `hide_border` | `boolean` | Remove outline |
128
+ | `compact` | `boolean` | Slim — hides bio/pronouns/Twitter/legend |
129
+ | `animate` | `boolean` | Fade-in stats + animated language bar |
130
+ | `hide` | `string[]` | Hide stats: `stars`, `commits`, `issues`, `repos`, `prs` |
131
+ | `hide_langs` | `string[]` | Exclude `hide_langs=html,css` |
132
+ | `show_langs` | `string[]` | Only `show_langs=typescript,rust` |
133
+ | `lang_count` | `1–10` | Top languages (default `5`) |
134
+ | `scope` | `string` | `personal` (default), `org`, `all` |
135
+ | `orgs` | `string[]` | Restrict org stats to `orgs=vercel,elysiajs` |
136
+ | `affiliations` | `string` | `owner` (default) or `affiliated` — org stars excluded by default |
137
+ | `fields` | `string[]` | Fetch only `fields=stats` for speed |
138
+
139
+ #### Examples
82
140
 
83
141
  ```md
84
142
  <!-- Dracula, no border, animated -->
@@ -89,107 +147,106 @@ Every visual slot is overridable. Colors accept hex (`ff79c6` or `#ff79c6`) and
89
147
 
90
148
  ![card](https://card.shiina.xyz/card/shiinasaku?bg_color=0d1117&title_color=58a6ff&text_color=9da7b3&icon_color=58a6ff)
91
149
 
92
- <!-- Compact, stats only, no languages -->
150
+ <!-- Compact, no issues/prs -->
93
151
 
94
152
  ![card](https://card.shiina.xyz/card/shiinasaku?compact=true&hide=issues,prs&fields=stats)
95
153
 
96
- <!-- Organization card -->
154
+ <!-- Include org stars explicitly -->
155
+
156
+ ![card](https://card.shiina.xyz/card/shiinasaku?affiliations=affiliated)
157
+
158
+ <!-- Organization -->
97
159
 
98
160
  ![card](https://card.shiina.xyz/card/elysiajs)
99
161
  ```
100
162
 
163
+ ---
164
+
101
165
  ## Deploy your own
102
166
 
103
167
  [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/ShiinaSaku/Github-Card)
104
168
 
105
- 1. Click the button above (or fork + import into Vercel).
106
- 2. Add environment variables:
169
+ 1. Click the button (or fork + import).
170
+ 2. Add env vars:
171
+
172
+ | Variable | Required | Purpose |
173
+ | :------------: | :------: | ----------------------------------- |
174
+ | `GITHUB_TOKEN` | ✅ | GitHub PAT — read-only is enough |
175
+ | `REDIS_URL` | ➖ | Redis / Upstash for shared L2 cache |
107
176
 
108
- | Variable | Required | Purpose |
109
- | -------------- | -------- | ----------------------------------------- |
110
- | `GITHUB_TOKEN` | ✅ | GitHub PAT (read-only is enough) |
111
- | `REDIS_URL` | ➖ | Redis/Upstash URL for the shared L2 cache |
177
+ 3. Done — serves `/card/:username` on Vercel CDN `s-maxage=1800, stale-while-revalidate=1800`.
112
178
 
113
- 3. Done. Your instance serves `/card/:username` on Vercel's CDN with `s-maxage=1800, stale-while-revalidate=1800`.
179
+ > Without Redis, in-memory LRU (1000 entries, SWR 30 min) still keeps warm instances fast.
114
180
 
115
- > Redis is optional — without it, the in-memory cache still keeps each warm instance fast.
181
+ ---
116
182
 
117
183
  ## API
118
184
 
119
185
  | Endpoint | Description |
120
186
  | ----------------------- | ------------------------------------------- |
121
- | `GET /card/:username` | SVG card (all query params above) |
122
- | `GET /:username/themes` | One SVG showing **all themes** for a user |
187
+ | `GET /card/:username` | SVG card — all params above |
188
+ | `GET /:username/themes` | One SVG with **all themes** for a user |
123
189
  | `GET /meta` | Service metadata + theme list |
124
190
  | `GET /health` | Uptime, cache telemetry, Redis reachability |
125
191
  | `GET /openapi` | Interactive OpenAPI docs |
126
192
 
127
- Responses are `image/svg+xml` with `ETag`, CORS (`*`), and CDN cache headers. Conditional requests (`If-None-Match`) return `304`.
193
+ Responses: `image/svg+xml`, `ETag` + `CDN-Cache-Control` + CORS `*`. Conditional `If-None-Match` → `304`.
194
+
195
+ ---
128
196
 
129
197
  ## Use as a library
130
198
 
131
199
  ```bash
132
200
  bun add @shiinasaku/github-card # Bun
133
- npm install @shiinasaku/github-card # Node / Next.js / Vite
201
+ npm install @shiinasaku/github-card # Node / Next / Vite
134
202
  ```
135
203
 
136
204
  ```ts
137
205
  import { renderCard, themes } from "@shiinasaku/github-card";
138
206
 
139
207
  const svg = renderCard(user, stats, languages, { theme: "tokyonight" });
208
+ // → string of SVG, zero deps, any runtime
140
209
  ```
141
210
 
142
- Ships as a prebuilt ESM bundle with full `.d.ts` types (Bun resolves the raw TypeScript source automatically via the `bun` export condition). The renderer is pure — no server, no network, works in any JS runtime.
211
+ Prebuilt `dist/lib.js` + `.d.ts`; Bun resolves raw TS via `bun` export condition. Pure renderer — no network, no server.
143
212
 
144
- ## Releasing
213
+ ---
145
214
 
146
- Releases are fully automated:
215
+ ## Architecture
147
216
 
148
- 1. **Actions → Bump** → choose `patch` / `minor` / `major`.
149
- 2. The workflow bumps `package.json`, commits, and tags `vX.Y.Z`.
150
- 3. The tag triggers **Release**: format, lint, typecheck, tests, dist build, tag↔version guard, `npm pack` verification, then publish to npm with [provenance](https://docs.npmjs.com/generating-provenance-statements) and a GitHub Release with auto-generated notes.
217
+ ```mermaid
218
+ flowchart LR
219
+ A[GET /card/:username] --> B[Elysia<br/>validation · CORS · OpenAPI · timing]
220
+ B --> C{L1 memory<br/>SWR 30m}
221
+ C -- hit --> G[render SVG<br/>ETag/304 → CDN]
222
+ C -- miss --> D{L2 Redis<br/>SWR 30m}
223
+ D -- hit --> G
224
+ D -- miss --> E[GitHub GraphQL<br/>100/page, 5 pages, 6s timeout]
225
+ E --> F[typed fetch<br/>+ avatar 150px]
226
+ F --> G
227
+ G --> H[Pure SVG<br/>system fonts · measured layout · glass]
228
+ ```
151
229
 
152
- ## Local development
230
+ - **Bun + Elysia** — one of the fastest HTTP stacks.
231
+ - **Two-tier SWR** — stale served instantly + background refresh, request coalescing via `inFlight`.
232
+ - **Typed upstream** — `RepoNode`/`ContributionEntry` generics, `T=unknown`, `TimeoutError`/`RateLimitError` mapping.
153
233
 
154
- ```bash
155
- bun install
156
- cp .env.example .env # add your GITHUB_TOKEN
157
- bun dev # http://localhost:3000
158
- ```
234
+ ---
159
235
 
160
- | Command | Action |
161
- | ------------------- | --------------------- |
162
- | `bun test` | Run the test suite |
163
- | `bun run typecheck` | Strict `tsc --noEmit` |
164
- | `bun run lint` | oxlint |
165
- | `bun run fmt` | oxfmt |
236
+ ## Releasing
166
237
 
167
- ## Architecture
238
+ Fully automated:
168
239
 
169
- ```
170
- GET /card/:username
171
- │
172
- ▼
173
- Elysia (validation, CORS, OpenAPI, server-timing)
174
- │
175
- ▼
176
- L1 in-memory cache ──hit──► render SVG ──► ETag/304 ──► CDN
177
- │miss ▲
178
- ▼ │ stale-while-revalidate
179
- L2 Redis (SWR) ──hit──► serve stale + background refresh
180
- │miss
181
- ▼
182
- GitHub GraphQL (batched, paginated 100/page, 6s timeout)
183
- │
184
- ▼
185
- Pure SVG renderer (zero-dependency, dynamic layout engine)
186
- ```
240
+ 1. **Actions → Bump** → `patch` / `minor` / `major`.
241
+ 2. Workflow bumps `package.json`, commits, tags `vX.Y.Z`.
242
+ 3. Tag triggers **Release**: `oxfmt` · `oxlint` · `typecheck` · `tests` · `dist` build · tag↔version guard · `npm pack` verify → publish with [provenance](https://docs.npmjs.com/generating-provenance-statements) + GitHub Release.
243
+
244
+ ---
245
+
246
+ <div align="center">
187
247
 
188
- - **Bun + Elysia** — one of the fastest HTTP stacks available.
189
- - **Two-tier SWR cache** — users never wait on GitHub's API.
190
- - **Request coalescing** — concurrent misses share a single upstream fetch.
191
- - **Defensive upstream** — timeouts, size caps, and typed errors (`401/404/429/502`).
248
+ **[MIT](LICENSE) © [saku shiina](https://www.shiina.xyz)** — built with Bun, Elysia, and system fonts.
192
249
 
193
- ## License
250
+ <sub>Stars default to <code>owner</code> only in 4.2 — add <code>?affiliations=affiliated</code> to include orgs.</sub>
194
251
 
195
- [MIT](LICENSE) © [saku shiina](https://www.shiina.xyz)
252
+ </div>
package/dist/lib.d.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  export { renderCard, type CardOpts } from "./card";
8
8
  export type { UserProfile, UserStats, LanguageStat, ProfileData, CardOptions } from "./types";
9
9
  export { themes, resolveColors, type Theme } from "./utils/themes";
10
- export { kFormat, escapeXml, wrapText } from "./utils/format";
10
+ export { kFormat, escapeXml, wrapText, measureText } from "./utils/format";
11
11
  export { icons, icon } from "./utils/icons";
12
12
  export { getLangColor } from "./utils/languages";
13
13
  export { FONT_FACE, FONT_FAMILY } from "./utils/font";