The unified TypeScript SDK for every git provider.
One normalized API over GitHub, GitLab, Bitbucket Cloud, Azure DevOps, and Gitea — plus any plain git remote.
import { createClient } from 'repo-sdk';
import { github } from 'repo-sdk/github';
const client = createClient({
// Swap in gitlab(), bitbucket(), azureDevOps(), gitea(), or gitHttp() —
// every call below keeps the same normalized shape.
provider: github({ auth: { token: process.env.GITHUB_TOKEN! } }),
});
const head = await client.commits.get({
repo: 'capawesome-team/repo-sdk',
ref: 'main',
});
for await (const tag of client.tags.listAll({ repo: 'capawesome-team/repo-sdk' })) {
console.log(tag.name, head.sha);
}Works with
Including self-hosted: GitHub Enterprise Server, GitLab self-managed, Azure DevOps Server, Gitea & Forgejo
Everything a git integration needs
Auth, pagination, rate limits, errors, and webhooks — repo-sdk normalizes the messy parts of every provider's REST API behind one typed interface.
One unified API
Discovery, commits, tags, branches, refs, downloads, and webhooks — one interface over every provider.
Zero dependencies
Just fetch and Web Crypto. Nothing to audit, nothing to bloat your bundle.
Edge-compatible
Runs on Node.js ≥ 20, Cloudflare Workers, and any Web-standard runtime — no node:* imports anywhere.
Normalized types
Namespace, Repository, Commit, Tag, Webhook — with a raw escape hatch on every object.
Typed errors
Every failure is a RepoError with a stable code union, retry hints, and redacted secrets.
Webhook verify & parse
Standalone helpers that take a Web-standard Request — no client needed.
Capability gating
Providers differ. Unsupported options throw instead of being silently dropped.
Pagination that walks itself
list returns a page and an opaque cursor; the listAll async iterators follow cursors for you.
Resilient by default
Bounded retry on rate limits honoring Retry-After, and an AbortSignal on every request.
GitHub App auth
Installation tokens minted in pure Web Crypto — RS256 JWTs, PKCS#1 or PKCS#8 keys.
Self-hosted friendly
GitHub Enterprise Server, self-managed GitLab, Azure DevOps Server, and Gitea or Forgejo via baseUrl.
In-memory testing provider
Exercise your integration end to end without hitting a real provider — repo-sdk/testing.
// Mirror every repository the token can reach.
for await (const repo of client.repos.listAll({ owned: true })) {
const archive = await client.repos.downloadArchive({
repo: repo.path,
ref: repo.defaultBranch ?? 'main',
format: 'tar.gz',
});
// archive.stream is a Web ReadableStream<Uint8Array>
await uploadToStorage(repo.path, archive.stream);
}Pagination that walks itself
list returns one page and an opaque cursor; thelistAll async iterators follow the cursors for you — and every cursor is a tamper-guarded envelope that can't redirect an authenticated request. Pair it with downloadArchive, which hands you a WebReadableStream instead of a buffer, and walking an entire account fits in a single for await loop.
Webhooks without the ceremony
verifyWebhook and parseWebhookEvent are standalone helpers that take a Web-standard Request — no client needed. They drop straight into Next.js route handlers, Hono, and workers, and they know each provider's signature scheme — HMAC-SHA256, shared token, or Basic auth — comparing in constant time so you don't have to.
import { verifyWebhook, parseWebhookEvent } from 'repo-sdk/github';
export async function POST(request: Request): Promise<Response> {
const valid = await verifyWebhook({ request, secret: process.env.WEBHOOK_SECRET! });
if (!valid) return new Response('invalid signature', { status: 401 });
const event = await parseWebhookEvent(request);
if (event.type === 'push') {
console.log(`push to ${event.repo} @ ${event.ref}`);
}
return new Response(null, { status: 204 });
}What you can build with repo-sdk
Anywhere your product meets a git repository — and your users get to choose where that repository lives.
CI/CD & build platforms
List a user’s repositories, resolve a ref to an exact SHA, then stream a tar.gz or mint an authenticated clone URL — the whole build-input pipeline, one code path for every provider.
Webhook ingestion at the edge
Terminate push, tag, and release deliveries from all providers in one handler: verify the signature, parse to one event shape, react.
“Connect a repository” flows
Power the repo picker in your SaaS: namespaces, repository search, and owned filters — with capability flags telling you what to render per provider.
Release & tag automation
Watch tags and branches, resolve refs to commits, and drive changelogs, deploy triggers, and version checks from normalized data.
Backup & mirroring
Walk every repository with listAll and stream archives to storage — cursors, rate limits, and retries handled for you.
Agents & internal tools
Give an AI agent or internal dashboard one typed surface over all the git hosting your org uses — stable error codes, secrets redacted.
Providers differ. repo-sdk tells you how.
Every provider ships a typed capability object, and the client throwsunsupported instead of silently dropping options.
| Capability | GitHub | GitLab | Bitbucket | Azure DevOps | Gitea |
|---|---|---|---|---|---|
| Repository search | — | ||||
| Tag dates | — | — | — | ||
| Release webhooks | — | — | |||
| tar.gz archives | — |
Frequently asked questions
Which git providers does repo-sdk support?
repo-sdk ships dedicated providers for GitHub, GitLab, Bitbucket Cloud, Azure DevOps, and Gitea, plus a gitHttp provider that talks to any plain git remote over the smart-HTTP protocol. Self-hosted deployments are covered too: GitHub Enterprise Server, self-managed GitLab, Azure DevOps Server, and Gitea or Forgejo instances via a baseUrl option.
Authentication per providerIs repo-sdk an alternative to Octokit?
For multi-provider integrations, yes: instead of stitching together Octokit plus one SDK per provider, you write against one normalized API. If you only ever talk to GitHub, a dedicated SDK exposes more endpoints — repo-sdk focuses on the surface integrations actually share.
Octokit alternatives comparedDoes repo-sdk run on Cloudflare Workers and other edge runtimes?
Yes. repo-sdk has zero runtime dependencies and no node:* imports — it is built on fetch, Web Crypto, and Web streams only, so it runs on Node.js 20+, Cloudflare Workers, and any Web-standard runtime.
How does repo-sdk handle feature differences between providers?
Every provider declares a typed RepoCapabilities object and the client gates on it: an option a provider cannot honor throws a RepoError with code unsupported instead of being silently dropped. You can also branch on client.capabilities at runtime to decide which features to offer.
How capability gating worksHow does webhook signature verification work across providers?
verifyWebhook is a standalone helper that takes a Web-standard Request and knows each provider’s scheme — HMAC-SHA256 signatures for GitHub, Bitbucket, and Gitea, a shared token for GitLab, and Basic auth for Azure DevOps. All comparisons run in constant time, and parseWebhookEvent then normalizes the delivery into one event shape.
Receiving webhooks guideDoes repo-sdk support GitHub App authentication?
Yes. Pass an appId and privateKey and the SDK mints installation tokens itself, signing RS256 JWTs with pure Web Crypto. Both PKCS#1 and PKCS#8 keys are accepted, and getInstallationToken() exposes the current token for use outside the SDK — in a git clone URL, for example.
GitHub authenticationHow do I test code that uses repo-sdk?
Import the in-memory provider from repo-sdk/testing: it implements the same contract as the real providers with seedable state, so integration tests run without a network. Every provider factory also accepts an injectable fetch for wire-level tests.
Testing guideStart here
Write it once. Run it everywhere your users host code.
MIT licensed, zero dependencies, TypeScript all the way down. Your first cross-provider integration is one install away.