@rsalianto/git-heatmap-core
v0.1.7
Published
Core data fetching, normalization, and calendar utilities for git-heatmap — framework-agnostic
Maintainers
Readme
@rsalianto/git-heatmap-core
Core logic for the git-heatmap family — data fetching, normalization, and calendar utilities shared by all framework packages. No DOM or framework dependency; runs in any Node.js or edge environment.

Part of the
@rsalianto/git-heatmapfamily — available for React, Vue, Angular, Vanilla JS, and Next.js.
Installation
npm install @rsalianto/git-heatmap-coreFetchers (server-side only)
These make authenticated HTTP calls and must run on the server — never in the browser.
import { fetchGitHubContributions } from "@rsalianto/git-heatmap-core/fetchers/github";
import { fetchGitLabContributions } from "@rsalianto/git-heatmap-core/fetchers/gitlab";
// GitHub (requires a personal access token with read:user scope)
const data = await fetchGitHubContributions({
username: "your-username",
token: process.env.GITHUB_TOKEN, // required
from: "2024-01-01", // optional — ISO date
to: "2024-12-31", // optional — ISO date
});
// GitLab (token optional for public profiles)
const data = await fetchGitLabContributions({
username: "your-username",
token: process.env.GITLAB_TOKEN, // optional
baseUrl: "https://gitlab.your-company.com", // optional, default: https://gitlab.com
});Normalizers
Convert raw API responses or manual entries into HeatmapData.
import {
normalizeGitHub,
normalizeGitLab,
normalizeManual,
buildHeatmapData,
buildHeatmapDataForYear,
} from "@rsalianto/git-heatmap-core";buildHeatmapData(entries, levels?) — recommended for most use cases
Builds a full 52-week grid ending at today from sparse {date, count} pairs. Missing dates default to count: 0.
const data = buildHeatmapData([
{ date: "2025-06-01", count: 5 },
{ date: "2025-06-15", count: 12 },
]);buildHeatmapDataForYear(entries, year, levels?) — display a specific year
Builds a full grid from Jan 1 to Dec 31 of the given year (or today if it is the current year).
const data2024 = buildHeatmapDataForYear(allEntries, 2024);
const dataCurrent = buildHeatmapDataForYear(allEntries, new Date().getFullYear());normalizeManual(entries, levels?) — sparse data, no grid padding
Converts {date, count} pairs to HeatmapData without generating empty weeks. Useful when your data already covers the exact range you want.
const data = normalizeManual([
{ date: "2025-01-01", count: 3 },
{ date: "2025-01-02", count: 0 },
]);normalizeGitHub(raw, levels?) / normalizeGitLab(raw, levels?)
Convert raw API responses to HeatmapData. Used internally by the fetchers.
import { normalizeGitHub } from "@rsalianto/git-heatmap-core";
const data = normalizeGitHub(rawGraphQLResponse);HeatmapData shape
This is the JSON format returned by all normalizers and fetchers, and expected by all component data props / api-url endpoints.
interface HeatmapData {
totalContributions: number; // sum of all counts
weeks: Array<{
days: Array<{
date: string; // "YYYY-MM-DD", empty string for padding cells
count: number; // raw contribution count
level: 0 | 1 | 2 | 3 | 4; // bucketed intensity
}>;
}>;
source: "github" | "gitlab" | "manual";
}Example JSON (as returned by an api-url endpoint):
{
"totalContributions": 312,
"source": "github",
"weeks": [
{
"days": [
{ "date": "2025-01-05", "count": 0, "level": 0 },
{ "date": "2025-01-06", "count": 3, "level": 1 },
{ "date": "2025-01-07", "count": 8, "level": 2 },
{ "date": "2025-01-08", "count": 0, "level": 0 },
{ "date": "2025-01-09", "count": 14, "level": 3 },
{ "date": "2025-01-10", "count": 22, "level": 4 },
{ "date": "2025-01-11", "count": 1, "level": 1 }
]
}
]
}Note: If you build your own API endpoint for
api-url, it must return this exact structure — not a raw[{date, count}]array.
Default levels
import { DEFAULT_LEVELS } from "@rsalianto/git-heatmap-core";
// [
// { threshold: 0, color: "var(--ghm-color-l0)", label: "No contributions" },
// { threshold: 1, color: "var(--ghm-color-l1)", label: "1–2 contributions" },
// { threshold: 3, color: "var(--ghm-color-l2)", label: "3–5 contributions" },
// { threshold: 6, color: "var(--ghm-color-l3)", label: "6–10 contributions" },
// { threshold: 11, color: "var(--ghm-color-l4)", label: "11+ contributions" },
// ]Custom levels:
import { buildHeatmapData } from "@rsalianto/git-heatmap-core";
const data = buildHeatmapData(entries, [
{ threshold: 0, color: "var(--ghm-color-l0)", label: "None" },
{ threshold: 1, color: "var(--ghm-color-l1)", label: "Low" },
{ threshold: 5, color: "var(--ghm-color-l2)", label: "Medium" },
{ threshold: 15, color: "var(--ghm-color-l3)", label: "High" },
{ threshold: 30, color: "var(--ghm-color-l4)", label: "Peak" },
]);Types
import type {
HeatmapData,
HeatmapDay,
HeatmapWeek,
LevelConfig,
HeatmapTheme,
GitHubFetchOptions,
GitLabFetchOptions,
GitHubRawCalendar,
GitLabRawCalendar,
} from "@rsalianto/git-heatmap-core";Related packages
@rsalianto/git-heatmap-react— React component@rsalianto/git-heatmap-vue— Vue 3 component@rsalianto/git-heatmap-angular— Angular component@rsalianto/git-heatmap-vanilla— Web Component (no framework)@rsalianto/git-heatmap-next— Next.js App Router route handlers
