@askalf/git-providers
v0.0.2
Published
Unified GitHub + GitLab + Bitbucket Cloud REST clients behind one GitProvider interface (user info, list repos, list branches, OAuth config). Plus a 40+ entry api-key-provider taxonomy for cloud / CI / PM / monitoring vendors. Zero runtime deps.
Maintainers
Readme
@askalf/git-providers
One interface for GitHub + GitLab + Bitbucket Cloud. User info, repos, branches, OAuth config — same shape across all three. Plus a 40+ entry taxonomy for non-OAuth API-key providers (cloud / CI/CD / PM / monitoring / e-commerce / marketing / ...).
npm install @askalf/git-providersWhy
Building a tool that integrates with "your git provider"? You don't actually want three implementations. You want one GitProvider interface and a registry that hands you the right adapter at runtime. That's all this package is.
Zero runtime dependencies. Native fetch. ~600 lines of TypeScript total.
Use it
import { getProvider, getOAuthConfig, isValidProvider } from '@askalf/git-providers';
const provider = getProvider('github');
const user = await provider.getUserInfo(accessToken);
const repos = await provider.listRepos(accessToken);
const branches = await provider.getBranches(accessToken, 'askalf/git-providers');
// OAuth config (reads $GITHUB_CLIENT_ID + $GITHUB_CLIENT_SECRET by default)
const oauth = getOAuthConfig('github');
// → { clientId, clientSecret, authorizeUrl, tokenUrl, scopes }
if (isValidProvider(req.body.provider)) {
const adapter = getProvider(req.body.provider);
// ...
}The GitProvider interface
interface GitProvider {
getUserInfo(accessToken: string): Promise<GitProviderUserInfo>;
listRepos(accessToken: string): Promise<GitRepo[]>;
getBranches(accessToken: string, repoFullName: string): Promise<GitBranch[]>;
}
interface GitRepo {
fullName: string; // 'owner/name'
url: string; // web URL
cloneUrl: string; // https clone URL
defaultBranch: string; // 'main' / 'master' / etc
isPrivate: boolean;
description: string | null;
language: string | null; // null on GitLab list-projects
}
interface GitBranch {
name: string;
isDefault: boolean;
}repoFullName uses the owner/name shape across all three providers; the GitLab adapter URL-encodes it to the v4 API's namespace%2Fproject form internally.
Self-hosted (GHE / self-hosted GitLab)
The default singletons (githubProvider, gitlabProvider, bitbucketProvider) talk to the public clouds. For GitHub Enterprise Server or self-hosted GitLab, build a custom one:
import { createGitHubProvider, createGitLabProvider } from '@askalf/git-providers';
const ghe = createGitHubProvider({
baseUrl: 'https://github.example.com/api/v3',
});
const gl = createGitLabProvider({
baseUrl: 'https://gitlab.example.com/api/v4',
});
await ghe.listRepos(token);
await gl.listRepos(token);Bitbucket Cloud has only one API origin. Bitbucket Server (the self-hosted product, formerly Stash) uses a totally different API and isn't covered here — open an issue if you need it.
OAuth config
Each provider exports a getXxxOAuthConfig({ clientId?, clientSecret? }) helper. With no args, it reads <PROVIDER>_CLIENT_ID / <PROVIDER>_CLIENT_SECRET from process.env and returns null if either is missing. Pass options to bypass env entirely:
import { getGitHubOAuthConfig, getGitLabOAuthConfig } from '@askalf/git-providers';
const cfg = getGitHubOAuthConfig({
clientId: process.env.MY_GH_CLIENT_ID,
clientSecret: process.env.MY_GH_CLIENT_SECRET,
});
// Self-hosted GitLab — also override the OAuth host:
const gl = getGitLabOAuthConfig({
clientId: '...',
clientSecret: '...',
oauthHost: 'https://gitlab.example.com',
});API key provider taxonomy
A separate sub-export ships a 40+ entry catalog of API-key (non-OAuth) providers — useful for any app that lets users bring their own credentials for cloud / CI / project-management / monitoring / commerce / marketing / etc. tools.
import {
API_KEY_PROVIDERS,
PROVIDER_CONFIGS,
testApiKeyIntegration,
} from '@askalf/git-providers/api-key-providers';
// What providers do we know about?
console.log(API_KEY_PROVIDERS);
// ['aws', 'gcp', 'azure', 'digitalocean', 'vercel', 'netlify', 'railway', 'flyio',
// 'jira', 'linear', 'notion', 'asana', 'datadog', 'sentry', 'pagerduty', ...]
// What does each one need?
PROVIDER_CONFIGS['stripe']
// → {
// name: 'Stripe',
// category: 'ecommerce',
// requiredFields: [{ key: 'secret_key', label: 'Secret Key', sensitive: true }],
// testEndpoint: 'https://api.stripe.com/v1/balance',
// testHeaders: (c) => ({ Authorization: `Bearer ${c.secret_key}` }),
// }
// Test a connection (10s timeout, SSRF-safe):
const result = await testApiKeyIntegration('stripe', { secret_key: 'sk_test_...' });
// → { success: true, message: 'Connected to Stripe' }
// or { success: false, message: 'Stripe returned 401: Unauthorized' }testApiKeyIntegration has SSRF-safe URL construction for the two providers (Jira, Grafana) where part of the URL is built from user input — Jira domains are constrained to *.atlassian.net, Grafana URLs are forced through a URL-parser + protocol allowlist.
What's NOT covered
- Bitbucket Server (self-hosted, formerly Stash) — different API, different shape.
- Pull-request / issue / commit / file-content endpoints — only user info + repos + branches + OAuth config. Open an issue if you need more; most are mechanical to add.
- Webhook signing / payload parsing — different concern, not bundled here.
- Token refresh — we accept access tokens, we don't manage them.
License
MIT — see LICENSE.
Also by askalf
| Project | What it does | |---------|-------------| | arnie | Portable IT troubleshooting companion. Networking, AD, Windows Update, package managers, log triage, hardware checks. | | brio | Capability layer for AI workloads — semantic cache, cost tiering, policy. Sits in front of any Anthropic-compat endpoint. | | browser-bridge | Stealth headless Chromium in a container. CDP on 9222 — Playwright/Puppeteer/MCP-compatible. | | claude-bridge | Bridge Claude Code sessions to Discord. | | dario | Local LLM router. Use your Claude Max/Pro subscription as an API. | | deepdive | Local research agent. Plan → search → fetch → extract → synthesize. Cited answers. | | hands | Cross-platform computer-use agent. Mouse, keyboard, screen. | | install-kit | curl-pipe-bash template for self-hosted Docker apps. | | pgflex | One Postgres API. Two modes (real PG ↔ PGlite WASM). | | redisflex | One Redis API. Two modes (ioredis ↔ in-process). |
