@shiinasaku/github-card 2.0.0 → 4.1.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 +134 -293
- package/dist/card.d.ts +16 -0
- package/dist/lib.d.ts +13 -0
- package/dist/lib.js +1209 -0
- package/dist/types.d.ts +37 -0
- package/dist/utils/colors.d.ts +2 -0
- package/dist/utils/font.d.ts +2 -0
- package/dist/utils/format.d.ts +3 -0
- package/dist/utils/icons.d.ts +9 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/languages.d.ts +2 -0
- package/dist/utils/themes.d.ts +16 -0
- package/package.json +29 -18
- package/src/card.ts +634 -113
- package/src/env.d.ts +4 -0
- package/src/github.ts +351 -483
- package/src/index.ts +147 -134
- package/src/input.css +1 -0
- package/src/tailwind.css +3837 -0
- package/src/types.ts +1 -0
- package/src/utils/colors.ts +85 -0
- package/src/utils/font.ts +3 -19
- package/src/utils/format.ts +16 -16
- package/src/utils/github-client.ts +193 -0
- package/src/utils/icons.ts +2 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/themes.ts +154 -19
package/README.md
CHANGED
|
@@ -1,354 +1,195 @@
|
|
|
1
|
-
# GitHub Profile Card
|
|
2
|
-
|
|
3
1
|
<div align="center">
|
|
4
2
|
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
<picture>
|
|
8
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://card.shiina.xyz/card/ShiinaSaku?theme=github_dark" />
|
|
9
|
-
<img src="https://card.shiina.xyz/card/ShiinaSaku" alt="GitHub Profile Card" width="500" />
|
|
10
|
-
</picture>
|
|
3
|
+
<img src="assets/logo.svg" alt="GitHub Card" width="480" />
|
|
11
4
|
|
|
12
|
-
|
|
5
|
+
# GitHub Card
|
|
13
6
|
|
|
14
|
-
|
|
7
|
+
**Beautiful, blazing-fast GitHub profile cards as dynamic SVGs.**
|
|
8
|
+
Drop one line in your README — get a live, auto-updating stats card.
|
|
15
9
|
|
|
16
|
-
|
|
10
|
+
[](assets/bun.svg)
|
|
11
|
+
[](assets/elysia.svg)
|
|
12
|
+
[](https://www.typescriptlang.org)
|
|
13
|
+
[](LICENSE)
|
|
14
|
+
[](https://vercel.com/new/clone?repository-url=https://github.com/ShiinaSaku/Github-Card)
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
[](https://bun.sh)
|
|
20
|
-
[](LICENSE)
|
|
21
|
-
[](#testing)
|
|
22
|
-
|
|
23
|
-
[Live Demo](https://card.shiina.xyz/card/ShiinaSaku) ·
|
|
24
|
-
[All Themes](https://card.shiina.xyz/ShiinaSaku/themes) ·
|
|
25
|
-
[API Docs](https://card.shiina.xyz/openapi) ·
|
|
26
|
-
[npm Package](#programmatic-usage-npm)
|
|
16
|
+
<img src="https://card.shiina.xyz/card/shiinasaku?theme=shiina" alt="Live demo card" width="500" />
|
|
27
17
|
|
|
28
18
|
</div>
|
|
29
19
|
|
|
30
20
|
---
|
|
31
21
|
|
|
32
|
-
##
|
|
22
|
+
## Quickstart
|
|
33
23
|
|
|
34
|
-
|
|
35
|
-

|
|
36
|
-
```
|
|
24
|
+
Paste this into your profile README (replace `shiinasaku` with your username):
|
|
37
25
|
|
|
38
|
-
|
|
26
|
+
```md
|
|
27
|
+
[](https://github.com/shiinasaku)
|
|
28
|
+
```
|
|
39
29
|
|
|
40
|
-
|
|
30
|
+
That's it. No sign-up, no build step — the card updates itself as you code.
|
|
41
31
|
|
|
42
|
-
|
|
43
|
-
<picture>
|
|
44
|
-
<source
|
|
45
|
-
media="(prefers-color-scheme: dark)"
|
|
46
|
-
srcset="https://card.shiina.xyz/card/YOUR_USERNAME?theme=github_dark"
|
|
47
|
-
/>
|
|
48
|
-
<img src="https://card.shiina.xyz/card/YOUR_USERNAME" alt="GitHub Stats" />
|
|
49
|
-
</picture>
|
|
50
|
-
```
|
|
32
|
+
## Why GitHub Card?
|
|
51
33
|
|
|
52
|
-
|
|
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).
|
|
53
42
|
|
|
54
43
|
## Themes
|
|
55
44
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
45
|
+
Preview **every** theme with your own data:
|
|
46
|
+
|
|
47
|
+
```md
|
|
48
|
+

|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Dark favorites | Light & accent |
|
|
52
|
+
| -------------------------------------------------- | ------------------------------------------------ |
|
|
53
|
+
| `shiina` · `aurora` · `oled` · `slate` | `default` · `pearl` · `sand` |
|
|
54
|
+
| `github_dark` · `dark` · `nord` · `dracula` | `forest` · `rose` · `cobalt` |
|
|
55
|
+
| `tokyonight` · `synthwave` · `radical` · `monokai` | `gruvbox` · `merko` · `onedark` · `highcontrast` |
|
|
56
|
+
|
|
57
|
+
## Customization
|
|
58
|
+
|
|
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`) |
|
|
84
80
|
|
|
85
|
-
|
|
86
|
-
https://card.shiina.xyz/YOUR_USERNAME/themes
|
|
87
|
-
```
|
|
81
|
+
### Examples
|
|
88
82
|
|
|
89
|
-
|
|
83
|
+
```md
|
|
84
|
+
<!-- Dracula, no border, animated -->
|
|
90
85
|
|
|
91
|
-
|
|
86
|
+

|
|
92
87
|
|
|
93
|
-
|
|
88
|
+
<!-- Fully custom colors -->
|
|
94
89
|
|
|
95
|
-
|
|
90
|
+

|
|
96
91
|
|
|
97
|
-
|
|
92
|
+
<!-- Compact, stats only, no languages -->
|
|
98
93
|
|
|
99
|
-
|
|
100
|
-
| :------------ | :-------- | :----------------------------------- |
|
|
101
|
-
| `theme` | `default` | One of the 20 built-in themes |
|
|
102
|
-
| `compact` | `false` | Hides bio, pronouns, language labels |
|
|
103
|
-
| `hide_border` | `false` | Removes the card border |
|
|
94
|
+

|
|
104
95
|
|
|
105
|
-
|
|
96
|
+
<!-- Organization card -->
|
|
106
97
|
|
|
107
|
-
|
|
98
|
+

|
|
99
|
+
```
|
|
108
100
|
|
|
109
|
-
|
|
110
|
-
| :------------- | :----------------- |
|
|
111
|
-
| `bg_color` | Background |
|
|
112
|
-
| `title_color` | Name text |
|
|
113
|
-
| `text_color` | Body text & labels |
|
|
114
|
-
| `icon_color` | Stat icons |
|
|
115
|
-
| `border_color` | Card border |
|
|
101
|
+
## Deploy your own
|
|
116
102
|
|
|
117
|
-
|
|
103
|
+
[](https://vercel.com/new/clone?repository-url=https://github.com/ShiinaSaku/Github-Card)
|
|
118
104
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
| `lang_count` | `5` | Top languages shown (1--10) |
|
|
122
|
-
| `hide` | -- | Comma-separated: `stars,commits,issues,repos,prs` |
|
|
123
|
-
| `scope` | `personal` | `personal` / `org` / `all` -- see [scope details](#what-the-card-shows) |
|
|
124
|
-
| `orgs` | -- | Comma-separated org logins to include (filters contributed-to repos) |
|
|
105
|
+
1. Click the button above (or fork + import into Vercel).
|
|
106
|
+
2. Add environment variables:
|
|
125
107
|
|
|
126
|
-
|
|
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 |
|
|
127
112
|
|
|
128
|
-
|
|
129
|
-
# Compact with 3 languages
|
|
130
|
-
https://card.shiina.xyz/card/ShiinaSaku?compact=true&lang_count=3
|
|
113
|
+
3. Done. Your instance serves `/card/:username` on Vercel's CDN with `s-maxage=1800, stale-while-revalidate=1800`.
|
|
131
114
|
|
|
132
|
-
|
|
133
|
-
https://card.shiina.xyz/card/ShiinaSaku?bg_color=0d1117&text_color=c9d1d9&title_color=58a6ff
|
|
115
|
+
> Redis is optional — without it, the in-memory cache still keeps each warm instance fast.
|
|
134
116
|
|
|
135
|
-
|
|
136
|
-
https://card.shiina.xyz/card/ShiinaSaku?scope=all&orgs=oven-sh,elysiajs
|
|
117
|
+
## API
|
|
137
118
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
119
|
+
| Endpoint | Description |
|
|
120
|
+
| ----------------------- | ------------------------------------------- |
|
|
121
|
+
| `GET /card/:username` | SVG card (all query params above) |
|
|
122
|
+
| `GET /:username/themes` | One SVG showing **all themes** for a user |
|
|
123
|
+
| `GET /meta` | Service metadata + theme list |
|
|
124
|
+
| `GET /health` | Uptime, cache telemetry, Redis reachability |
|
|
125
|
+
| `GET /openapi` | Interactive OpenAPI docs |
|
|
141
126
|
|
|
142
|
-
|
|
127
|
+
Responses are `image/svg+xml` with `ETag`, CORS (`*`), and CDN cache headers. Conditional requests (`If-None-Match`) return `304`.
|
|
143
128
|
|
|
144
|
-
##
|
|
145
|
-
|
|
146
|
-
Install the package to render cards in your own server, CLI tool, or script:
|
|
129
|
+
## Use as a library
|
|
147
130
|
|
|
148
131
|
```bash
|
|
149
|
-
bun add github-card
|
|
132
|
+
bun add @shiinasaku/github-card # Bun
|
|
133
|
+
npm install @shiinasaku/github-card # Node / Next.js / Vite
|
|
150
134
|
```
|
|
151
135
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
```typescript
|
|
155
|
-
import { renderCard, themes } from "github-card";
|
|
156
|
-
|
|
157
|
-
const svg = renderCard(
|
|
158
|
-
{
|
|
159
|
-
login: "octocat",
|
|
160
|
-
name: "The Octocat",
|
|
161
|
-
avatarUrl: "https://github.com/octocat.png",
|
|
162
|
-
bio: "Open source enthusiast",
|
|
163
|
-
pronouns: "they/them",
|
|
164
|
-
twitter: "github",
|
|
165
|
-
},
|
|
166
|
-
{ stars: 3200, commits: 1450, issues: 89, repos: 42, prs: 210 },
|
|
167
|
-
[
|
|
168
|
-
{ name: "TypeScript", size: 120000, color: "#3178c6" },
|
|
169
|
-
{ name: "Go", size: 80000, color: "#00ADD8" },
|
|
170
|
-
{ name: "Rust", size: 40000, color: "#dea584" },
|
|
171
|
-
],
|
|
172
|
-
{ theme: "tokyonight", compact: false },
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
// svg is a self-contained SVG string with embedded font
|
|
176
|
-
```
|
|
136
|
+
```ts
|
|
137
|
+
import { renderCard, themes } from "@shiinasaku/github-card";
|
|
177
138
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
import {
|
|
182
|
-
// Core renderer
|
|
183
|
-
renderCard,
|
|
184
|
-
type CardOpts,
|
|
185
|
-
|
|
186
|
-
// Types
|
|
187
|
-
type UserProfile,
|
|
188
|
-
type UserStats,
|
|
189
|
-
type LanguageStat,
|
|
190
|
-
type ProfileData,
|
|
191
|
-
type CardOptions,
|
|
192
|
-
|
|
193
|
-
// Theming
|
|
194
|
-
themes,
|
|
195
|
-
resolveColors,
|
|
196
|
-
type Theme,
|
|
197
|
-
|
|
198
|
-
// Utilities
|
|
199
|
-
kFormat, // 1500 -> "1.5k"
|
|
200
|
-
escapeXml, // "<>" -> "<>"
|
|
201
|
-
wrapText, // text wrapping with ellipsis
|
|
202
|
-
icon, // SVG stat icons (star, commit, pr, issue, repo, x)
|
|
203
|
-
icons, // raw SVG path data
|
|
204
|
-
getLangColor, // language -> hex color (650+ languages)
|
|
205
|
-
FONT_FACE, // base64 @font-face CSS rule
|
|
206
|
-
FONT_FAMILY, // font-family declaration
|
|
207
|
-
} from "github-card";
|
|
139
|
+
const svg = renderCard(user, stats, languages, { theme: "tokyonight" });
|
|
208
140
|
```
|
|
209
141
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
The default export is an Elysia app. Mount it into your own server:
|
|
213
|
-
|
|
214
|
-
```typescript
|
|
215
|
-
import { Elysia } from "elysia";
|
|
216
|
-
import githubCard from "github-card/server";
|
|
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.
|
|
217
143
|
|
|
218
|
-
|
|
219
|
-
.use(githubCard) // adds /card/:username, /:username/themes, etc.
|
|
220
|
-
.get("/my-route", () => "hello")
|
|
221
|
-
.listen(3000);
|
|
222
|
-
```
|
|
144
|
+
## Releasing
|
|
223
145
|
|
|
224
|
-
|
|
146
|
+
Releases are fully automated:
|
|
225
147
|
|
|
226
|
-
|
|
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.
|
|
227
151
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
```bash
|
|
231
|
-
git clone https://github.com/ShiinaSaku/Github-Card.git
|
|
232
|
-
cd Github-Card
|
|
233
|
-
vercel deploy
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
Set environment variables:
|
|
237
|
-
|
|
238
|
-
```
|
|
239
|
-
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx # required
|
|
240
|
-
UPSTASH_REDIS_REST_URL=https://... # optional, L2 cache
|
|
241
|
-
UPSTASH_REDIS_REST_TOKEN=... # optional
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
### Local Development
|
|
152
|
+
## Local development
|
|
245
153
|
|
|
246
154
|
```bash
|
|
247
155
|
bun install
|
|
248
|
-
|
|
249
|
-
bun dev
|
|
250
|
-
# http://localhost:3000/card/ShiinaSaku
|
|
156
|
+
cp .env.example .env # add your GITHUB_TOKEN
|
|
157
|
+
bun dev # http://localhost:3000
|
|
251
158
|
```
|
|
252
159
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
|
258
|
-
|
|
|
259
|
-
| `GET /card/:username` | SVG stats card |
|
|
260
|
-
| `GET /:username/themes` | SVG grid of all themes |
|
|
261
|
-
| `GET /health` | JSON -- cache metrics, Redis status, uptime |
|
|
262
|
-
| `GET /openapi` | Interactive API documentation |
|
|
263
|
-
|
|
264
|
-
### Response Headers
|
|
265
|
-
|
|
266
|
-
| Header | Value |
|
|
267
|
-
| :---------------------------- | :-------------------------------------------------------------- |
|
|
268
|
-
| `Cache-Control` | `public, max-age=0, s-maxage=1800, stale-while-revalidate=1800` |
|
|
269
|
-
| `ETag` | Enables 304 Not Modified |
|
|
270
|
-
| `Server-Timing` | Per-request timing telemetry |
|
|
271
|
-
| `Access-Control-Allow-Origin` | `*` |
|
|
272
|
-
|
|
273
|
-
### Status Codes
|
|
274
|
-
|
|
275
|
-
| Code | Meaning |
|
|
276
|
-
| :--- | :------------------ |
|
|
277
|
-
| 200 | SVG card |
|
|
278
|
-
| 304 | Cached (ETag match) |
|
|
279
|
-
| 401 | Bad GitHub token |
|
|
280
|
-
| 404 | User not found |
|
|
281
|
-
| 422 | Invalid parameters |
|
|
282
|
-
| 429 | GitHub rate limited |
|
|
283
|
-
| 502 | GitHub API down |
|
|
284
|
-
|
|
285
|
-
---
|
|
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 |
|
|
286
166
|
|
|
287
167
|
## Architecture
|
|
288
168
|
|
|
289
169
|
```
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
## Testing
|
|
313
|
-
|
|
314
|
-
```bash
|
|
315
|
-
bun test # 21 tests
|
|
316
|
-
bun test --coverage # with coverage
|
|
317
|
-
bun run typecheck # tsc
|
|
318
|
-
bun run lint # oxlint
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
---
|
|
322
|
-
|
|
323
|
-
## What the card shows
|
|
324
|
-
|
|
325
|
-
| Stat | Source |
|
|
326
|
-
| :-------- | :------------------------------------- |
|
|
327
|
-
| Stars | Total across owned repos (excl. forks) |
|
|
328
|
-
| Commits | Current calendar year |
|
|
329
|
-
| Issues | Open + closed |
|
|
330
|
-
| Repos | Owned, non-fork |
|
|
331
|
-
| PRs | Open + closed + merged |
|
|
332
|
-
| Languages | Top N by code size |
|
|
333
|
-
|
|
334
|
-
### Scope
|
|
335
|
-
|
|
336
|
-
| Value | Stars / Repos / Languages from | Speed |
|
|
337
|
-
| :--------- | :--------------------------------------------------- | :--------------------------------- |
|
|
338
|
-
| `personal` | Your own repos only | Single query |
|
|
339
|
-
| `org` | Org repos you actually contributed to (commits, PRs) | Parallel: metadata + contributions |
|
|
340
|
-
| `all` | Your repos + org repos you contributed to | Parallel: personal + contributions |
|
|
341
|
-
|
|
342
|
-
Org stats use GitHub's `repositoriesContributedTo` API -- only repos you actually touched are counted, not every repo in the organization. Filter to specific orgs with `orgs=org1,org2`.
|
|
343
|
-
|
|
344
|
-
---
|
|
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
|
+
```
|
|
187
|
+
|
|
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`).
|
|
345
192
|
|
|
346
193
|
## License
|
|
347
194
|
|
|
348
|
-
[MIT](LICENSE)
|
|
349
|
-
|
|
350
|
-
---
|
|
351
|
-
|
|
352
|
-
<div align="center">
|
|
353
|
-
<sub>Built with <a href="https://bun.sh">Bun</a> and <a href="https://elysiajs.com">Elysia</a>. Hosted on <a href="https://vercel.com">Vercel</a>.</sub>
|
|
354
|
-
</div>
|
|
195
|
+
[MIT](LICENSE) © [saku shiina](https://www.shiina.xyz)
|
package/dist/card.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { UserProfile, UserStats, LanguageStat } from "./types";
|
|
2
|
+
export type CardOpts = {
|
|
3
|
+
theme?: string;
|
|
4
|
+
title_color?: string;
|
|
5
|
+
text_color?: string;
|
|
6
|
+
icon_color?: string;
|
|
7
|
+
bg_color?: string;
|
|
8
|
+
border_color?: string;
|
|
9
|
+
hide_border?: boolean;
|
|
10
|
+
compact?: boolean;
|
|
11
|
+
hide?: string[];
|
|
12
|
+
hide_langs?: string[];
|
|
13
|
+
show_langs?: string[];
|
|
14
|
+
animate?: boolean;
|
|
15
|
+
};
|
|
16
|
+
export declare function renderCard(user: UserProfile, stats: UserStats, langs: LanguageStat[], opts?: CardOpts): string;
|
package/dist/lib.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* github-card — npm entry point
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the pure SVG renderer, all themes, types, and utility functions.
|
|
5
|
+
* No server dependency — works in any JS/TS runtime.
|
|
6
|
+
*/
|
|
7
|
+
export { renderCard, type CardOpts } from "./card";
|
|
8
|
+
export type { UserProfile, UserStats, LanguageStat, ProfileData, CardOptions } from "./types";
|
|
9
|
+
export { themes, resolveColors, type Theme } from "./utils/themes";
|
|
10
|
+
export { kFormat, escapeXml, wrapText } from "./utils/format";
|
|
11
|
+
export { icons, icon } from "./utils/icons";
|
|
12
|
+
export { getLangColor } from "./utils/languages";
|
|
13
|
+
export { FONT_FACE, FONT_FAMILY } from "./utils/font";
|