Skip to content

Latest commit

Β 

History

65 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

repo-sdk

npm version npm downloads license

A unified, normalized, zero-dependency, edge-compatible TypeScript SDK over GitHub, GitLab, Bitbucket Cloud, Azure DevOps, and Gitea β€” plus generic git smart-HTTP remotes. Write your repository, commit, branch, tag, ref-resolution, download and webhook logic once against one normalized API β€” built on raw fetch and Web Crypto, so it runs on Node, Cloudflare Workers, and other Web-standard runtimes.

Features

  • One API, eight namespaces β€” users, namespaces, repos, commits, branches, tags, refs, and webhooks behind a single interface.
  • Capability gating β€” providers differ. The client reports what the active provider supports and throws unsupported instead of silently dropping an option.
  • Ref resolution that follows git β€” refs.resolve accepts a branch, a tag, a fully-qualified refs/…, HEAD, or an abbreviated SHA and returns one normalized match, with tags shadowing branches exactly like git rev-parse.
  • Webhook verify & parse β€” standalone per-provider helpers that take a Web-standard Request. No client, no credentials. detectWebhookProvider routes a shared endpoint to the right pair.
  • Zero dependencies β€” fetch and Web Crypto only. No node:* imports, so it runs on Cloudflare Workers without nodejs_compat β€” including RS256 JWT signing for GitHub App auth.
  • Tree-shakable and typed β€” each provider ships on its own subpath, so unused providers never reach your bundle. Every model is normalized (IDs as strings, dates as Date, refs fully qualified) and keeps the untouched provider payload on raw.

Installation

npm install repo-sdk

Quickstart

Create a client from the package root and a provider factory from its subpath.

import { createClient } from 'repo-sdk';
import { github } from 'repo-sdk/github';

const client = createClient({
  provider: github({ auth: { token: process.env.GITHUB_TOKEN! } }),
});

Resolve a ref β€” a branch, tag, SHA, or HEAD β€” to a single commit, and page through history.

const head = await client.commits.get({ repo: 'capawesome-team/repo-sdk', ref: 'main' });
console.log(head.sha, head.message);

const { data: commits, cursor } = await client.commits.list({
  repo: 'capawesome-team/repo-sdk',
  ref: 'main',
  limit: 20,
});

Find out what a user-supplied ref actually is before you act on it.

const match = await client.refs.resolve({ repo: 'capawesome-team/repo-sdk', ref: 'v1.0.0' });
match.type; // 'branch' | 'tag' | 'commit'
match.ref; // 'refs/tags/v1.0.0'
match.sha; // peeled to the commit SHA for annotated tags

Download the code at that ref, as a stream or as a credential-bearing clone URL for the git CLI.

const archive = await client.repos.downloadArchive({
  repo: 'capawesome-team/repo-sdk',
  ref: match.sha,
  format: 'tar.gz',
});
await new Response(archive.stream).arrayBuffer();

const { url } = await client.repos.getCloneUrl({ repo: 'capawesome-team/repo-sdk' });

Verify and handle the webhook. The helpers take the Request itself β€” no client, no credentials.

import { parseWebhookEvent, verifyWebhook } from 'repo-sdk/github';

export async function POST(request: Request): Promise<Response> {
  if (!(await verifyWebhook({ request, secret: process.env.WEBHOOK_SECRET! }))) {
    return new Response('invalid signature', { status: 401 });
  }

  const event = await parseWebhookEvent(request);

  switch (event.type) {
    case 'push':
      // event.headCommitSha is undefined when the push deleted the ref.
      break;
    case 'tag_push':
      // event.ref is always fully qualified β€” refs/tags/v1.0.0.
      break;
    case 'release':
      break;
  }

  return new Response(null, { status: 204 });
}

API at a glance

Namespace Methods
users me
namespaces list Β· listAll
repos list Β· listAll Β· get Β· downloadArchive Β· getCloneCredentials Β· getCloneUrl
commits list Β· listAll Β· get
branches list Β· listAll Β· get
tags list Β· listAll Β· get
refs resolve Β· search
webhooks create Β· list Β· get Β· update Β· delete

Every list returns an opaque cursor and has a listAll async generator that walks the pages for you. Cursors are provider-tagged and origin-checked, so a forged one cannot redirect an authenticated request. Every method accepts a signal for cancellation. Rate-limited requests are retried once when the provider's Retry-After fits the budget (10 seconds by default, configurable via retry).

Webhook payload helpers β€” verifyWebhook and parseWebhookEvent β€” are exported from the provider subpaths and take no credential beyond the shared secret, so they run in a handler with no client at all. detectWebhookProvider from the core entry identifies the sender when one endpoint serves several providers.

Providers

Provider Import Notes
GitHub repo-sdk/github Personal access token or GitHub App installation auth.
GitLab repo-sdk/gitlab Personal, group, project, or OAuth token.
Bitbucket repo-sdk/bitbucket Bitbucket Cloud. Atlassian API token or access token.
Azure DevOps repo-sdk/azure-devops Organization-scoped. PAT or Entra ID token.
Gitea repo-sdk/gitea Gitea β‰₯ 1.20 and Forgejo.
Generic git repo-sdk/git-http Any git smart-HTTP remote. Ref discovery and clone URLs only.
Testing repo-sdk/testing Seedable in-memory provider for your test suite. No credentials.

Every factory accepts an injectable fetch, and every token can be a static string or a tokenProvider that mints one per request and is re-invoked once on a 401. Self-hosted deployments β€” GitHub Enterprise Server, GitLab self-managed, Azure DevOps Server, and Gitea/Forgejo β€” are supported via baseUrl. Providers do not support the same feature set β€” client.capabilities tells you what the active one can do, and the full breakdown lives in the capability matrix.

Testing

repo-sdk/testing ships a seedable in-memory provider you hand to createClient like any other β€” no account, no tokens, no fetch stubs, no throwaway repositories.

import { createClient } from 'repo-sdk';
import { createInMemoryProvider } from 'repo-sdk/testing';

const client = createClient({
  provider: createInMemoryProvider({
    repositories: { 'acme/app': { name: 'app', namespace: 'acme', defaultBranch: 'main' } },
    branches: { 'acme/app': [{ name: 'main', sha: 'c1' }] },
    commits: { 'acme/app': [{ sha: 'c1', message: 'Initial commit' }] },
  }),
});

It reports every capability enabled by default, and a second options argument simulates a specific provider's identity and capability gaps β€” so code that branches on client.capabilities is testable. Its page size is deliberately small, so your cursor pagination gets exercised, and provider.state exposes the data as plain maps for assertions.

Errors

Every failure is a RepoError with a closed code union: unauthorized, forbidden, not_found, rate_limited, validation, unsupported, provider_error, network_error.

import { RepoError } from 'repo-sdk';

try {
  await client.repos.downloadArchive({ repo: 'acme/app', ref: 'main', format: 'tar.gz' });
} catch (error) {
  if (error instanceof RepoError && error.code === 'unsupported') {
    // Azure DevOps serves zip only β€” fall back instead of failing the job.
  }
}

Errors also carry provider, status, retryAfter and retryable; cause is the underlying JS Error. Token values are redacted from every message, so a leaked stack trace cannot leak a credential. The deliberate exceptions are repos.getCloneUrl, which returns a URL with the credential embedded because that is what git clone needs, and repos.getCloneCredentials, which returns that credential next to a credential-free URL for a git credential helper β€” treat both as secrets.

Runtime support

Node.js β‰₯ 20, Cloudflare Workers (without nodejs_compat), Deno, Bun, Vercel Edge, and any other runtime with fetch, Web Crypto and TextEncoder. ESM only.

Documentation

Full documentation lives at repo-sdk.dev (docs):

Development

Prerequisites: Node >= 20.

npm install
Script Description
npm run build Build with tsdown
npm test Run the unit + provider contract test suite
npm run test:watch Run tests in watch mode
npm run test:live Gated live provider tests (env vars documented in CONTRIBUTING)
npm run typecheck Type-check without emitting
npm run lint Lint the codebase
npm run fmt Format with prettier

Docs site:

  • npm run docs:dev β€” run the docs dev server
  • npm run docs:build β€” build the static site to .blume-dist/

Releases are automated with release-please, driven by Conventional Commits. While pre-1.0.0, breaking changes bump the minor version and features bump the patch version. Merging the release pull request publishes to npm. See CONTRIBUTING.md for details.

About

repo-sdk is developed and maintained by Genz IT Solutions GmbH. It powers Capawesome, a cloud platform for mobile apps.

License

MIT

About

πŸ”Œ A unified, normalized, zero-dependency, edge-compatible TypeScript SDK over GitHub, GitLab, Gitea, Bitbucket Cloud, and Azure DevOps.

Topics

Resources

Contributing

Stars

1 star

Watchers

1 watching

Forks

Releases

Sponsor this project

Contributors

Languages