Capabilities
RepoCapabilities, capability gating, and how providers differ.
Providers are not identical. GitLab can date tags, GitHub can’t; Azure DevOps doesn’t support free-text
repository search; only GitHub, GitLab, and Gitea emit release webhooks. Rather than hide these
differences and silently drop options, repo-sdk advertises each provider’s capabilities and
gates on them.
RepoCapabilities
Every provider exposes a capabilities object, also surfaced on client.capabilities:
userProfile?boolean
Whether users.me can resolve the authenticated user profile. False e.g. for GitHub App installation tokens.
booleantagDates?boolean
Whether listed tags carry a date.
booleanrepoSearch?boolean
Whether repos.list accepts a free-text query.
booleanownedRepoFilter?boolean
Whether repos.list accepts owned: true.
booleancommitUserRef?boolean
Whether commit actors can carry a resolved account (GitActor.user).
booleanrefSearch?boolean
Whether refs.search can prefix-match branch and tag names server-side.
booleanwebhookEvents?WebhookEventType[]
The webhook events the provider can register.
WebhookEventType[]webhookVerification?'hmac-sha256' | 'shared-token' | 'basic-auth'
How incoming webhooks are verified.
'hmac-sha256' | 'shared-token' | 'basic-auth'archiveFormats?ArchiveFormat[]
The archive formats downloadArchive can return.
ArchiveFormat[]const client = createClient({ provider: github({ auth: { token } }) });
client.capabilities.tagDates; // false for GitHub
client.capabilities.archiveFormats; // ['zip', 'tar.gz']
client.capabilities.webhookEvents; // ['push', 'tag_push', 'release']
Capability gating
When you pass an option a provider can’t honor, the client throws a RepoError with code unsupported
before making a request — it never silently ignores it:
// Azure DevOps has no free-text repo search.
await client.repos.list({ query: 'checkout' });
// → RepoError { code: 'unsupported', provider: 'azure-devops' }
The same gating applies to:
users.me()— requiresuserProfilerepos.list({ query })— requiresrepoSearchrepos.list({ owned: true })— requiresownedRepoFilterrepos.downloadArchive({ format })— theformatmust be inarchiveFormatsrefs.search— requiresrefSearchwebhooks.create/webhooks.update— every event must be inwebhookEvents
Gate at runtime
Because capabilities are plain data, you can check them before offering a feature — for example, to hide a “search repositories” box when the active provider can’t search:
if (client.capabilities.repoSearch) {
const { data } = await client.repos.list({ query: userInput });
}
if (client.capabilities.webhookEvents.includes('release')) {
// offer release webhooks in the UI
}
Per-provider differences
| Capability | GitHub | GitLab | Bitbucket | Azure DevOps | Gitea |
|---|---|---|---|---|---|
User profile (users.me) |
✓ (✗ under App auth) | ✓ | ✓ | ✓ | ✓ |
| Tag dates | ✗ | ✓ | ✓ | ✗ | ✗ |
Repo search (query) |
✓ | ✓ | ✓ | ✗ | ✓ |
Owned filter (owned) |
✓ | ✓ | ✓ | ✗ | ✓ |
Commit author identity (author.user) |
✓ | ✗ | ✓ | ✗ | ✓ |
| Ref search | ✓ | ✓ | ✓ | ✓ | ✓ |
| Webhook events | push, tag_push, release | push, tag_push, release | push, tag_push | push, tag_push | push, tag_push, release |
| Webhook verification | HMAC-SHA256 | shared token | HMAC-SHA256 | basic auth | HMAC-SHA256 |
| Archive formats | zip, tar.gz | zip, tar.gz | zip, tar.gz | zip | zip, tar.gz |
See the full matrix
The complete per-provider capability reference.