Skip to content

The library

Terminal window
npm install @stats-forge/github-stats-forge-core
import { CardConfig, stats } from '@stats-forge/github-stats-forge-core/api';
const config = new CardConfig({
pats: [{ name: 'PAT_1', value: process.env.PAT_1 }],
});
const result = await stats({ username: 'octocat', show_icons: 'true' }, config);

A handler takes the query params its card accepts — as strings, the way a query string carries them — and the configuration for the deployment. The handlers are stats, topLangs, pin, contributedTo, gist and wakatime.

Nothing in the library reads process.env. The host builds the configuration and passes it in, which is what lets the same code run in an action, on a server and in a browser.

This is the layer underneath the rest: the GitHub Stats Forge action, the recommended way to put a card in a repository, is these handlers and a step that writes the file. Reach for the library when you want a card somewhere the action cannot go.

if (result.status === 'success') {
// result.content is the card, as SVG
} else {
// result.content is the failure, drawn as a card
// result.error.code is why it failed
// result.error.param is the parameter at fault, when it names one
// result.retryable is whether trying again could help
}

Both branches carry a content you can serve: a failure is still an image, so a README shows the reason rather than a broken picture.

CodeWhat happenedRetryable
invalid_paramA parameter is malformed or not renderableno
missing_paramA parameter the card cannot render withoutno
not_allowedThe deployment does not serve that account or gistno
not_foundThe user, repository or gist does not existno
no_tokensThe deployment has no usable GitHub tokenyes
rate_limitedEvery token is rate limitedyes
upstreamGitHub or WakaTime answered with something unusableyes

A host branches on the code rather than on the message, and uses retryable to decide between caching the failure and trying again.

const config = new CardConfig({
pats: [{ name: 'PAT_1', value: process.env.PAT_1 }],
usernameAllowlist: ['octocat'],
excludeRepositories: ['octocat/scratch'],
fetchMultiPageStars: 1,
fetch: myFetch,
});
FieldWhat it is
patsThe tokens to spend, each with the name of the variable it came from
usernameAllowlistThe GitHub logins this deployment draws, case-insensitively; omit for any
gistAllowlistThe same, for gist ids
excludeRepositoriesRepositories left out of every card
fetchMultiPageStarsHow many pages of starred repositories to read; Infinity for all
fetchThe transport every request goes through — swap it to cache, mock or proxy

CardConfig.fromEnv(process.env) builds the same thing from PAT_1…, ALLOWLIST, GIST_ALLOWLIST, EXCLUDE_REPO and FETCH_MULTI_PAGE_STARS, for a host that would rather configure through the environment. A PAT_ variable set to nothing is skipped.

An allowlist is enforced by the api handlers, before anything is fetched, so an identity the deployment does not serve fails as not_allowed and spends no rate limit. It covers every GitHub login — username and the organization card’s org — and the gist card’s id. It does not cover the wakatime card, whose username is a WakaTime profile rather than a GitHub login. Calling a render function directly bypasses the check: it lives at the api layer, which is where a query stops being untrusted.

A token is never logged. The name it came from is, so a failing token can be found without its value ending up in a log.

ImportWhat it holds
@stats-forge/github-stats-forge-core/apiThe card handlers, CardConfig, ApiResult
@stats-forge/github-stats-forge-core/fetchersThe GitHub and WakaTime fetchers on their own
@stats-forge/github-stats-forge-core/themesThe theme table