---
title: "Provider kit"
description: "The building blocks of a provider, from `forges/kit`."
canonical_url: "https://forges.link/contributing/provider-kit"
---
# Provider kit

> The building blocks of a provider, from `forges/kit`.

Import from `forges/kit`. Code that only uses providers imports from `forges` instead. See [Write a provider](https://forges.link/contributing/write-a-provider) for how they fit together.

## Define a provider

### `CapabilityEnv`

What support can depend on once the provider exists.

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        version?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Instance version from <code>
        instanceVersion
      </code>
      
       or <code>
        refreshCapabilities()
      </code>
      
      , when known.
    </td>
  </tr>
</tbody>
</table>

### `SupportInput`

A fixed support level, or one computed from the instance version.

**one of:**

- [`Support`](https://forges.link/reference/provider#support-1)
- `((env: CapabilityEnv) => Support)`

### `VerbKind`

The thread kinds that verbs can differ by.

**type:** [`Exclude<ThreadKind, 'other'>`](https://forges.link/reference/data-model#threadkind)

### `ThreadFilter`

The `ThreadQuery` filters that a provider declares in `threads.listFilters` when its listing applies them.

**one of:**

- `'involves'`
- `'mentions'`
- `'milestone'`

### `AlertKind`

The security alert kinds that support can differ by.

**type:** [`Exclude<SecurityAlertKind, 'other'>`](https://forges.link/reference/data-model#securityalertkind)

### `Verb`

A verb whose support does not depend on the thread kind.

**type parameters:** `F`

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        support
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#supportinput">
        <code>
          SupportInput
        </code>
      </a>
    </td>
    
    <td>
      How well the verb is supported.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        run
      </code>
    </td>
    
    <td>
      <code>
        F
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
</tbody>
</table>

### `KindVerb`

A verb whose support depends on the thread kind it is called with. Kinds not listed are unsupported.

**type parameters:** `F`

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        kinds
      </code>
    </td>
    
    <td>
      <code>
        Partial<Record<VerbKind, SupportInput>>
      </code>
    </td>
    
    <td>
      How well each thread kind is supported.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        run
      </code>
    </td>
    
    <td>
      <code>
        F
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
</tbody>
</table>

### `verb()`

Declares a verb whose support does not depend on the thread kind.

```ts
function verb<F>(support: SupportInput, run: F): Verb<F>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        support
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#supportinput">
        <code>
          SupportInput
        </code>
      </a>
    </td>
    
    <td>
      How well the verb is supported.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        run
      </code>
    </td>
    
    <td>
      <code>
        F
      </code>
    </td>
    
    <td>
      The function that implements the verb.
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`Verb<F>`](https://forges.link/contributing/provider-kit#verb)

### `perKind()`

Declares a verb whose support depends on the thread kind.

**Example**

```ts
const threads = {
  get: perKind({ issue: true, pull_request: true }, getThread),
}
```

```ts
function perKind<F>(kinds: Partial<Record<VerbKind, SupportInput>>, run: F): KindVerb<F>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        kinds
      </code>
    </td>
    
    <td>
      <code>
        Partial<Record<VerbKind, SupportInput>>
      </code>
    </td>
    
    <td>
      How well each thread kind is supported. Kinds that are left out are unsupported.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        run
      </code>
    </td>
    
    <td>
      <code>
        F
      </code>
    </td>
    
    <td>
      The function that implements the verb.
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`KindVerb<F>`](https://forges.link/contributing/provider-kit#kindverb)

### `ProviderSpec`

Everything a provider declares. Methods and capabilities are both derived from it.

**type parameters:** `TExtensions extends object = Record<never, never>`

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        extensions?
      </code>
    </td>
    
    <td>
      <code>
        TExtensions
      </code>
    </td>
    
    <td>
      Members that only this forge's providers have, such as <code>
        graphql()
      </code>
      
       on GitHub. They are added to the provider unchanged.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        traits
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Capabilities that no single verb carries.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        traits.eventKinds
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/provider#forgecapabilities">
        <code>
          ForgeCapabilities['eventKinds']
        </code>
      </a>
    </td>
    
    <td>
      Whether event kinds come from the forge or are inferred from text. See <code>
        ForgeCapabilities.eventKinds
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        traits.authKinds
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/providers#authkind">
        <code>
          readonly AuthKind[]
        </code>
      </a>
    </td>
    
    <td>
      The auth types the provider accepts.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        traits.limits?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#textlimits">
        <code>
          TextLimits
        </code>
      </a>
    </td>
    
    <td>
      Limits on the text the forge accepts.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Listings are declared as pages; core derives the iterables.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.get
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['get']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.listPage
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['listPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.byOwnerPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['byOwnerPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.labelsPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['labelsPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.createLabel?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['createLabel']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.milestonesPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['milestonesPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.collaboratorsPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['collaboratorsPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.contributorsPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['contributorsPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.contributorStats?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['contributorStats']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.templates?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['templates']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.permissionFor?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['permissionFor']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.addCollaborator?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['addCollaborator']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.assignableUsersPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['assignableUsersPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.reviewerCandidatesPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ReposApi['reviewerCandidatesPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.eventsPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<(repo: RepoRef, options?: EventFeedOptions) => Promise<Page<ForgeEventInput>>>
      </code>
    </td>
    
    <td>
      The implementation of <code>
        provider.repos.events()
      </code>
      
       and <code>
        provider.repos.eventsPage()
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        users?
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      <code>
        get
      </code>
      
       is omitted when the forge cannot read an account by login.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        orgs?
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      An organisation's teams and their members. Listings are declared as pages; core derives the iterables.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.get
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'get'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.listPage
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'listPage'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.listFilters?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#threadfilter">
        <code>
          readonly ThreadFilter[]
        </code>
      </a>
    </td>
    
    <td>
      The <a href="https://forges.link/contributing/provider-kit#threadfilter">
        <code>
          ThreadFilter
        </code>
      </a>
      
      s that <code>
        listPage
      </code>
      
       applies, or reports with its own warning. Core leaves the others out of the query and adds a <code>
        filter_unsupported
      </code>
      
       warning to the first page.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.getMany
      </code>
    </td>
    
    <td>
      <code>
        Verb<ThreadsApi['getMany']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.eventsPage
      </code>
    </td>
    
    <td>
      <code>
        Verb<(ref: ThreadRef, options?: ListOptions) => Promise<Page<ForgeEventInput>>>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.commentsPage
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'commentsPage'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.getComment?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'getComment'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.comment?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'comment'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.editComment?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'editComment'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.deleteComment?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'deleteComment'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.close?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'close'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.reopen?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'reopen'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.create?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'create'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.update?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'update'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.setLabels?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'setLabels'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.addLabels?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'addLabels'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.removeLabels?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'removeLabels'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.setMilestone?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'setMilestone'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.reactions?
      </code>
    </td>
    
    <td>
      <code>
        KindVerb<{ [K in 'react' | 'unreact']: NonNullable<ThreadsApi[K]> }>
      </code>
    </td>
    
    <td>
      One capability covers reacting and removing a reaction.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.reactionsPage?
      </code>
    </td>
    
    <td>
      <code>
        KindVerb<ThreadsApi['reactionsPage']>
      </code>
    </td>
    
    <td>
      Listing the reactions on a thread or one of its comments.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.transfer?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ThreadsApi['transfer']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.markDuplicate?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ThreadsApi['markDuplicate']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.setAssignees?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'setAssignees'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.requestReview?
      </code>
    </td>
    
    <td>
      <code>
        ThreadVerb<'requestReview'>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.merge?
      </code>
    </td>
    
    <td>
      <code>
        Verb<(ref: ThreadRef, options?: MergeOptions, hooks?: MergeHooks) => Promise<MergeResult>>
      </code>
    </td>
    
    <td>
      <code>
        beforeMerge
      </code>
      
       runs once the merge is validated, just before it is sent.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.approveAndMerge?
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Optional support override; approval and merging must also be supported.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.subscriptions?
      </code>
    </td>
    
    <td>
      <code>
        KindVerb<{ [K in 'subscription' | 'subscribe' | 'unsubscribe']: NonNullable<ThreadsApi[K]> }>
      </code>
    </td>
    
    <td>
      One capability covers reading and changing the subscription.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.checks?
      </code>
    </td>
    
    <td>
      <code>
        KindVerb<(ref: ThreadRef, options?: BaseOptions) => Promise<Page<Check>>>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.reviewsPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ThreadsApi['reviewsPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.getReview?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ThreadsApi['getReview']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.createReview?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ThreadsApi['createReview']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.submitReview?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ThreadsApi['submitReview']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.replyToReviewComment?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ThreadsApi['replyToReviewComment']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.approve?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ThreadsApi['approve']>
      </code>
    </td>
    
    <td>
      Omit to derive approval from <code>
        createReview
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.filesPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ThreadsApi['filesPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.commitsPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<ThreadsApi['commitsPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.reviewThreads?
      </code>
    </td>
    
    <td>
      <code>
        Verb<Pick<ThreadsApi, 'resolveReviewThread' | 'unresolveReviewThread'>>
      </code>
    </td>
    
    <td>
      One capability covers resolving and unresolving.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        emulated?
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Support for the single-item reads core emulates from their listings where the spec declares no endpoint. Each defaults to <code>
        'emulated'
      </code>
      
      , capped by the listing's own support.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        checks?
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Commit-level checks, beside the pull-level <code>
        threads.checks
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ci?
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Read-only CI. Listings are declared as pages; core derives the iterables.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents?
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Repository contents. Listings are declared as pages; core derives the iterables.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        search?
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Cross-repository search. Listings are declared as pages; core derives the iterables.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        securityAlerts?
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Support per alert kind; <code>
        listPage
      </code>
      
       is called with <code>
        kind
      </code>
      
       unset to list every supported kind.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications?
      </code>
    </td>
    
    <td>
      <code>
        { listPage: Verb<(options?: NotificationListOptions) => Promise<Page<Notification>>> } & { [K in Exclude<keyof NotificationsApi, 'list' | 'listPage'>]?: Verb<NonNullable<NotificationsApi[K]>> }
      </code>
    </td>
    
    <td>
      Omit when the forge has no notifications. <code>
        list
      </code>
      
       is derived from <code>
        page
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        installations?
      </code>
    </td>
    
    <td>
      <code>
        Verb<Omit<InstallationsApi, 'list' | 'repos'>>
      </code>
    </td>
    
    <td>
      The implementation of <code>
        provider.installations
      </code>
      
      , except for <code>
        list()
      </code>
      
       and <code>
        repos()
      </code>
      
      , which core derives.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Managing registered hooks. Listings are declared as pages; core derives the iterables.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.listPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<WebhooksApi['listPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.create?
      </code>
    </td>
    
    <td>
      <code>
        Verb<WebhooksApi['create']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.update?
      </code>
    </td>
    
    <td>
      <code>
        Verb<WebhooksApi['update']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.delete?
      </code>
    </td>
    
    <td>
      <code>
        Verb<WebhooksApi['delete']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.rotateSecret?
      </code>
    </td>
    
    <td>
      <code>
        Verb<WebhooksApi['rotateSecret']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.deliveriesPage?
      </code>
    </td>
    
    <td>
      <code>
        Verb<WebhooksApi['deliveriesPage']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.redeliver?
      </code>
    </td>
    
    <td>
      <code>
        Verb<WebhooksApi['redeliver']>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scopes()?
      </code>
    </td>
    
    <td>
      <code>
        (verb: ForgeVerb) => VerbScopes
      </code>
    </td>
    
    <td>
      Token scopes or app permissions per verb, for <code>
        provider.scopesFor()
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        normaliseMarkdown()?
      </code>
    </td>
    
    <td>
      <code>
        (body: string) => string
      </code>
    </td>
    
    <td>
      The implementation of <code>
        provider.normaliseMarkdown()
      </code>
      
      . Without it, Markdown is returned unchanged.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        web?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#weblinks">
        <code>
          WebLinks
        </code>
      </a>
    </td>
    
    <td>
      How the forge's web pages are laid out; omit when they have no stable pattern.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        request?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#fetcher">
        <code>
          Fetcher
        </code>
      </a>
    </td>
    
    <td>
      Fetcher behind <code>
        request()
      </code>
      
      , when it differs from the context fetcher.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        probeVersion()?
      </code>
    </td>
    
    <td>
      <code>
        () => Promise<string | undefined>
      </code>
    </td>
    
    <td>
      Reads the instance version for <code>
        refreshCapabilities()
      </code>
      
      . Omit when capabilities never depend on it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        rateLimits()?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/requests#ratelimit">
        <code>
          () => RateLimit[]
        </code>
      </a>
    </td>
    
    <td>
      The implementation of <code>
        provider.rateLimits()
      </code>
      
      , for a provider whose requests bypass its fetchers.
    </td>
  </tr>
</tbody>
</table>

### `MergeHooks`

Hooks that a provider runs around a merge.

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        beforeMerge()?
      </code>
    </td>
    
    <td>
      <code>
        () => Promise<void>
      </code>
    </td>
    
    <td>
      Runs before the merge request is sent, for example to wait for a pending state.
    </td>
  </tr>
</tbody>
</table>

### `ProviderBase`

The options, the identity and the resolved URLs that provider hooks receive.

**type parameters:** `TOptions, TState`

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        options
      </code>
    </td>
    
    <td>
      <code>
        TOptions
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        forge
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#forgekind">
        <code>
          ForgeKind
        </code>
      </a>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        instance
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#forgeinstance">
        <code>
          ForgeInstance
        </code>
      </a>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        baseUrl
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      API base after defaults and the API path are applied.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        headers
      </code>
    </td>
    
    <td>
      <code>
        Record<string, string>
      </code>
    </td>
    
    <td>
      Default headers: the definition's, plus <code>
        user-agent
      </code>
      
       outside browsers or when the caller sets one.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        origin
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Error context for this provider.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        origin.forge
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#forgekind">
        <code>
          ForgeKind
        </code>
      </a>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        origin.instance
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#forgeinstance">
        <code>
          ForgeInstance
        </code>
      </a>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        state
      </code>
    </td>
    
    <td>
      <code>
        TState
      </code>
    </td>
    
    <td>
      State passed to <code>
        derive()
      </code>
      
      , or created by <code>
        prepare()
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

### `ProviderContext`

The argument of `setup()`: the base, the fetchers and `derive()`.

**type parameters:** `TOptions, TState`

**extends:** [`ProviderBase<TOptions, TState>`](https://forges.link/contributing/provider-kit#providerbase)

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        fetcher
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#fetcher">
        <code>
          Fetcher
        </code>
      </a>
    </td>
    
    <td>
      Authenticated with the definition's <code>
        authHeaders
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        createFetcher()
      </code>
    </td>
    
    <td>
      <code>
        (overrides: Partial<FetcherOptions> & { baseUrl: string }) => Fetcher
      </code>
    </td>
    
    <td>
      Another fetcher with the same timeout, <code>
        fetch
      </code>
      
       and error context. It sends no credentials unless it sets its own <code>
        authHeaders
      </code>
      
      . Its budgets count towards <code>
        provider.rateLimits()
      </code>
      
       only when neither it nor <code>
        fetcher
      </code>
      
       sends credentials.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        derive()
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/provider">
        <code>
          (options: TOptions, state?: TState) => ForgeProvider
        </code>
      </a>
    </td>
    
    <td>
      Another provider from the same definition, for example one per app installation.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        options
      </code>
    </td>
    
    <td>
      <code>
        TOptions
      </code>
    </td>
    
    <td>
      Inherited from <a href="https://forges.link/contributing/provider-kit#providerbase">
        <code>
          ProviderBase
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        forge
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#forgekind">
        <code>
          ForgeKind
        </code>
      </a>
    </td>
    
    <td>
      Inherited from <a href="https://forges.link/contributing/provider-kit#providerbase">
        <code>
          ProviderBase
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        instance
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#forgeinstance">
        <code>
          ForgeInstance
        </code>
      </a>
    </td>
    
    <td>
      Inherited from <a href="https://forges.link/contributing/provider-kit#providerbase">
        <code>
          ProviderBase
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        baseUrl
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      API base after defaults and the API path are applied. Inherited from <a href="https://forges.link/contributing/provider-kit#providerbase">
        <code>
          ProviderBase
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        headers
      </code>
    </td>
    
    <td>
      <code>
        Record<string, string>
      </code>
    </td>
    
    <td>
      Default headers: the definition's, plus <code>
        user-agent
      </code>
      
       outside browsers or when the caller sets one. Inherited from <a href="https://forges.link/contributing/provider-kit#providerbase">
        <code>
          ProviderBase
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        origin
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Error context for this provider. Inherited from <a href="https://forges.link/contributing/provider-kit#providerbase">
        <code>
          ProviderBase
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        origin.forge
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#forgekind">
        <code>
          ForgeKind
        </code>
      </a>
    </td>
    
    <td>
      Inherited from <a href="https://forges.link/contributing/provider-kit#providerbase">
        <code>
          ProviderBase
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        origin.instance
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#forgeinstance">
        <code>
          ForgeInstance
        </code>
      </a>
    </td>
    
    <td>
      Inherited from <a href="https://forges.link/contributing/provider-kit#providerbase">
        <code>
          ProviderBase
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        state
      </code>
    </td>
    
    <td>
      <code>
        TState
      </code>
    </td>
    
    <td>
      State passed to <code>
        derive()
      </code>
      
      , or created by <code>
        prepare()
      </code>
      
      . Inherited from <a href="https://forges.link/contributing/provider-kit#providerbase">
        <code>
          ProviderBase
        </code>
      </a>
      
      .
    </td>
  </tr>
</tbody>
</table>

### `ProviderDefinition`

The defaults, the authentication and the `setup()` of a forge.

**type parameters:** `TOptions extends ForgeOptionsBase, TState = undefined, HasWeb extends boolean = boolean, TExtensions extends object = Record<never, never>`

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        forge
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#forgekind">
        <code>
          ForgeKind
        </code>
      </a>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        experimental?
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      The forge's API as a whole is unstable, so the provider can change with it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        anonymous?
      </code>
    </td>
    
    <td>
      <code>
        true | 'webhooks'
      </code>
    </td>
    
    <td>
      Accepts a missing <code>
        auth
      </code>
      
       as <code>
        { type: 'anonymous' }
      </code>
      
      : core then sends no credentials and marks writes, notifications, subscriptions, installations and the account's repository list unsupported. <code>
        'webhooks'
      </code>
      
       marks every verb unsupported, for a forge whose API needs credentials but whose webhook deliveries can be verified without them.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        baseUrl
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Default <code>
        baseUrl
      </code>
      
       when the caller passes none.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        apiPath?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Appended to <code>
        baseUrl
      </code>
      
       unless already present, for example <code>
        /api/v4
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        instance()?
      </code>
    </td>
    
    <td>
      <code>
        (host: string) => string
      </code>
    </td>
    
    <td>
      Maps the API host to the instance host, for example <code>
        api.github.com
      </code>
      
       to <code>
        github.com
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        headers?
      </code>
    </td>
    
    <td>
      <code>
        Record<string, string>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        prepare()?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#providerbase">
        <code>
          (base: ProviderBase<TOptions, TState | undefined>) => TState
        </code>
      </a>
    </td>
    
    <td>
      Builds per-provider state once; receives the state given to <code>
        derive()
      </code>
      
      , if any.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        authHeaders()?
      </code>
    </td>
    
    <td>
      <code>
        (base: ProviderBase<TOptions, TState>) => FetcherOptions['authHeaders']
      </code>
    </td>
    
    <td>
      Resolves the credential headers of each request.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        query?
      </code>
    </td>
    
    <td>
      <code>
        Record<string, string>
      </code>
    </td>
    
    <td>
      Query parameters for every request, such as an API version; see <code>
        FetcherOptions.query
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        hasWeb?
      </code>
    </td>
    
    <td>
      <code>
        HasWeb
      </code>
    </td>
    
    <td>
      Whether the forge has a website: <code>
        setup()
      </code>
      
       must then return <code>
        web
      </code>
      
      , and the provider's <code>
        webOrigin
      </code>
      
       is typed <code>
        string
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setup()
      </code>
    </td>
    
    <td>
      <code>
        (ctx: ProviderContext<TOptions, TState>) => HasWeb extends true ? ProviderSpec<TExtensions> & { web: WebLinks } : ProviderSpec<TExtensions>
      </code>
    </td>
    
    <td>
      Declares the verbs and the web links of one provider.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#webhookhandlers">
        <code>
          WebhookHandlers<TOptions>
        </code>
      </a>
    </td>
    
    <td>
      Delivery verification and translation. Omit it and <code>
        webhooks.ingest()
      </code>
      
       is unsupported.
    </td>
  </tr>
</tbody>
</table>

### `WebhookHandlers`

Verifies and translates deliveries for one provider; built once per instance from its context.

**type parameters:** `TOptions`

**type:** `(ctx: Omit<ProviderContext<TOptions, unknown>, 'state' | 'derive'>) => { events: WebhookEventType[] verify: (delivery: WebhookDelivery) => Promise<boolean> translate: (delivery: WebhookDelivery) => ForgeEventInput[] | Promise<ForgeEventInput[]> }`

### `defineForgeProvider()`

Defines a forge provider. Returns the factory end users call, for example
`github({ auth })`. Nothing touches the network until `create()`.

```ts
function defineForgeProvider<TOptions extends ForgeOptionsBase, TState = undefined, HasWeb extends boolean = boolean, Forge extends ForgeKind = ForgeKind, Experimental extends boolean = boolean, TExtensions extends object = Record<never, never>>(definition: ProviderDefinition<TOptions, TState, HasWeb, TExtensions>): ProviderFactoryFunction<TOptions, HasWeb, Forge, Experimental, ForgeProvider<HasWeb> & TExtensions>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        definition
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#providerdefinition">
        <code>
          ProviderDefinition<TOptions, TState, HasWeb, TExtensions>
        </code>
      </a>
    </td>
    
    <td>
      The defaults, authentication and setup of the forge.
    </td>
  </tr>
</tbody>
</table>

**Returns:** `ProviderFactoryFunction<TOptions, HasWeb, Forge, Experimental, ForgeProvider<HasWeb> & TExtensions>`

## Capability table

### `CapabilityEntry`

One row of the capability table: where a capability is declared on `ProviderSpec`,
where it lands on `ForgeCapabilities`, and which `ForgeProvider` verbs it covers.
`capabilitiesOf()`, `supports()` and the capability matrix derive from the table.

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        capability
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Where the support lands on <code>
        ForgeCapabilities
      </code>
      
      , dot-separated.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        spec?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Where the verb is declared on <code>
        ProviderSpec
      </code>
      
      , dot-separated.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        verbs?
      </code>
    </td>
    
    <td>
      <code>
        readonly string[]
      </code>
    </td>
    
    <td>
      Verbs on <code>
        ForgeProvider
      </code>
      
       this capability covers.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        perKind?
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      Support is declared per thread kind.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        derived?
      </code>
    </td>
    
    <td>
      <code>
        'experimental' | 'poll' | 'webhook' | 'threadEvents' | 'upsertComment' | 'getComment' | 'getReview' | 'ciJob' | 'subscriptionSet' | 'approve' | 'approveAndMerge' | 'alertKinds' | 'eventKinds' | 'authKinds' | 'limits'
      </code>
    </td>
    
    <td>
      The capability is computed by core rather than read from a declared verb.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        write?
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      The verbs change state, so <code>
        readOnly
      </code>
      
       and anonymous providers reject them.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        account?
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      The verbs need an account, so anonymous providers reject them.
    </td>
  </tr>
</tbody>
</table>

### `CAPABILITY_TABLE`

Every capability with the verbs it covers and the flags that gate it, in the order the capability matrix lists them.

**type:** [`readonly CapabilityEntry[]`](https://forges.link/contributing/provider-kit#capabilityentry)

## Requests

### `FetcherOptions`

Options for `createFetcher()`.

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        baseUrl
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fetch?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/requests#fetchlike">
        <code>
          FetchLike
        </code>
      </a>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Injected for tests and for runtimes with a non-global fetch.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        timeout?
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        30000
      </code>
    </td>
    
    <td>
      Timeout in milliseconds (headers only for streams).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        headers?
      </code>
    </td>
    
    <td>
      <code>
        Record<string, string>
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Default headers, sent only to the API origin.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        authHeaders()?
      </code>
    </td>
    
    <td>
      <code>
        () => Promise<Record<string, string>> | Record<string, string>
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Credentials resolved before each API-origin request.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        authenticated?
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Requests carry credentials that <code>
        authHeaders
      </code>
      
       does not set, for example through a <code>
        fetch
      </code>
      
       that signs them.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        query?
      </code>
    </td>
    
    <td>
      <code>
        Record<string, string>
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      API-origin query defaults; request parameters take precedence.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        context?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/errors#forgeerrorcontext">
        <code>
          ForgeErrorContext
        </code>
      </a>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Attached to every error the fetcher throws.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        onRetry()?
      </code>
    </td>
    
    <td>
      <code>
        (retry: { url: string, method: string, wait: number }) => void
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Called before a request is retried. A rate limit with a <code>
        retry-after
      </code>
      
       of at most a minute is retried once, after that wait.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        onRateLimit()?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/requests#ratelimit">
        <code>
          (event: { url: string, method: string, rateLimit: RateLimit }) => void
        </code>
      </a>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Called with the rate limit that a response from the base URL's origin reports, including a response that fails or is <code>
        304 Not Modified
      </code>
      
      . Responses without rate limit headers don't call it.
    </td>
  </tr>
</tbody>
</table>

### `RequestOptions`

Options for one request of a fetcher.

**extends:** `Omit<RequestInit, 'signal'>`

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        query?
      </code>
    </td>
    
    <td>
      <code>
        Record<string, string | number | boolean | undefined>
      </code>
    </td>
    
    <td>
      Query parameters. Parameters that are <code>
        undefined
      </code>
      
       are left out.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        signal?
      </code>
    </td>
    
    <td>
      <code>
        AbortSignal
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        etag?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Send <code>
        If-None-Match
      </code>
      
      , and resolve with <code>
        notModified
      </code>
      
       instead of throwing.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        json?
      </code>
    </td>
    
    <td>
      <code>
        unknown
      </code>
    </td>
    
    <td>
      Serialised as the JSON request body, with a matching <code>
        content-type
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        mapError()?
      </code>
    </td>
    
    <td>
      <code>
        (error: unknown) => unknown
      </code>
    </td>
    
    <td>
      Rewrites a failure from this request, for endpoints whose statuses mean something specific.
    </td>
  </tr>
</tbody>
</table>

### `PaginateOptions`

Options for reading one page of a paginated endpoint.

**extends:** [`RequestOptions`](https://forges.link/contributing/provider-kit#requestoptions)

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        select()?
      </code>
    </td>
    
    <td>
      <code>
        (body: unknown, linkNext?: string) => { items: unknown[], next?: string, total?: number }
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Reads items and the next page URL from a response body, for APIs that paginate in the body (Bitbucket's <code>
        values
      </code>
      
       / <code>
        next
      </code>
      
      ). Without it, the body is the item array and the next page comes from the <code>
        Link
      </code>
      
       header. <code>
        linkNext
      </code>
      
       is the <code>
        Link
      </code>
      
       header's next URL, for APIs that wrap items in the body but still paginate with <code>
        Link
      </code>
      
      . <code>
        total
      </code>
      
       is the item total the body reports, such as a search's <code>
        total_count
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        conditional?
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Whether the first page sends <code>
        cursor.etag
      </code>
      
       as <code>
        If-None-Match
      </code>
      
       and reports its validator in <code>
        etag
      </code>
      
      . Turn it off for a page that is built from more than this one response.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        query?
      </code>
    </td>
    
    <td>
      <code>
        Record<string, string | number | boolean | undefined>
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Query parameters. Parameters that are <code>
        undefined
      </code>
      
       are left out. Inherited from <a href="https://forges.link/contributing/provider-kit#requestoptions">
        <code>
          RequestOptions
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        signal?
      </code>
    </td>
    
    <td>
      <code>
        AbortSignal
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Inherited from <a href="https://forges.link/contributing/provider-kit#requestoptions">
        <code>
          RequestOptions
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        etag?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Send <code>
        If-None-Match
      </code>
      
      , and resolve with <code>
        notModified
      </code>
      
       instead of throwing. Inherited from <a href="https://forges.link/contributing/provider-kit#requestoptions">
        <code>
          RequestOptions
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        json?
      </code>
    </td>
    
    <td>
      <code>
        unknown
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Serialised as the JSON request body, with a matching <code>
        content-type
      </code>
      
      . Inherited from <a href="https://forges.link/contributing/provider-kit#requestoptions">
        <code>
          RequestOptions
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        mapError()?
      </code>
    </td>
    
    <td>
      <code>
        (error: unknown) => unknown
      </code>
    </td>
    
    <td>
      
    </td>
    
    <td>
      Rewrites a failure from this request, for endpoints whose statuses mean something specific. Inherited from <a href="https://forges.link/contributing/provider-kit#requestoptions">
        <code>
          RequestOptions
        </code>
      </a>
      
      .
    </td>
  </tr>
</tbody>
</table>

### `FetchResult`

A parsed response.

**type parameters:** `T`

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        data
      </code>
    </td>
    
    <td>
      <code>
        T
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        response
      </code>
    </td>
    
    <td>
      <code>
        Response
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notModified
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      The server answered <code>
        304 Not Modified
      </code>
      
       to the <code>
        etag
      </code>
      
       that the request sent.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cursor?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/requests#cursor">
        <code>
          Cursor
        </code>
      </a>
    </td>
    
    <td>
      Where the next page starts, when there is one.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        total?
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      The total number of items the listing reports, where the response carries one.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        etag?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The validator of a listing's first page, from <code>
        Fetcher.page
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

### `Fetcher`

A client for one forge API. It adds credentials, applies the timeout and retries, and maps failures to errors.

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        raw()
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#requestoptions">
        <code>
          (path: string, options?: RequestOptions) => Promise<Response>
        </code>
      </a>
    </td>
    
    <td>
      Sends a request and returns the response unparsed.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        stream()
      </code>
    </td>
    
    <td>
      <code>
        (path: string, options?: RequestOptions) => Promise<RawResponse>
      </code>
    </td>
    
    <td>
      Bytes as they arrive, through the same timeout and error mapping as <code>
        Fetcher.json
      </code>
      
      . HTTP(S) download redirects to another origin omit all headers and credentials. HTTPS downloads cannot redirect to HTTP. Where <code>
        fetch
      </code>
      
       hides redirects (browsers), the runtime follows GET and HEAD under its own header rules.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        json()
      </code>
    </td>
    
    <td>
      <code>
        (path: string, options?: RequestOptions) => Promise<FetchResult<T>>
      </code>
    </td>
    
    <td>
      Sends a request and parses the JSON body.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        page()
      </code>
    </td>
    
    <td>
      <code>
        (path: string, options?: PaginateOptions & { cursor?: Cursor }) => Promise<FetchResult<T[]>>
      </code>
    </td>
    
    <td>
      One page: <code>
        path
      </code>
      
       with its query, or <code>
        cursor.nextUrl
      </code>
      
       when given. A first page, whose cursor has neither <code>
        nextUrl
      </code>
      
       nor <code>
        token
      </code>
      
      , sends <code>
        cursor.etag
      </code>
      
       as <code>
        If-None-Match
      </code>
      
       and reports the response's validator in <code>
        etag
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        items()
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#paginateoptions">
        <code>
          (path: string, options?: PaginateOptions) => AsyncGenerator<T>
        </code>
      </a>
    </td>
    
    <td>
      Every item across every page, in order.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        resolve()
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#requestoptions">
        <code>
          (path: string, query?: RequestOptions['query']) => string
        </code>
      </a>
    </td>
    
    <td>
      The absolute URL of a path and query, without sending a request.
    </td>
  </tr>
</tbody>
</table>

### `parseLinkHeader()`

Parses an RFC 5988 `Link` header into a map of rel to URL.

```ts
function parseLinkHeader(header: string | null | undefined): Record<string, string>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        header
      </code>
    </td>
    
    <td>
      <code>
        string | null | undefined
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Record<string, string>`

### `createFetcher()`

Creates a fetcher for one forge API.

```ts
function createFetcher(options: FetcherOptions): Fetcher
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        options
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#fetcheroptions">
        <code>
          FetcherOptions
        </code>
      </a>
    </td>
    
    <td>
      The base URL and the credentials, timeout and error context of every request.
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`Fetcher`](https://forges.link/contributing/provider-kit#fetcher)

### `CreateRequestOptions`

Options for `createRequest()`.

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        readOnly()?
      </code>
    </td>
    
    <td>
      <code>
        (method: string, path: string) => Error
      </code>
    </td>
    
    <td>
      Error for mutating requests.
    </td>
  </tr>
</tbody>
</table>

### `createRequest()`

Builds a provider's `request()` escape hatch on top of its fetcher.

```ts
function createRequest(fetcher: Fetcher, createOptions: CreateRequestOptions = {}): ForgeRequest
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        fetcher
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#fetcher">
        <code>
          Fetcher
        </code>
      </a>
    </td>
    
    <td>
      The fetcher to send requests with.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        createOptions?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#createrequestoptions">
        <code>
          CreateRequestOptions
        </code>
      </a>
    </td>
    
    <td>
      Where to reject writes, for a read-only provider. Defaults to <code>
        {}
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`ForgeRequest`](https://forges.link/reference/requests#forgerequest)

## Webhooks and events

### `eventAction()`

Normalises a forge-native verb (`closed`, `close`, `synchronize`, ...) into an [`EventAction`](https://forges.link/reference/data-model#eventaction).

```ts
function eventAction(raw: string | undefined): EventAction | undefined
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        raw
      </code>
    </td>
    
    <td>
      <code>
        string | undefined
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`EventAction | undefined`](https://forges.link/reference/data-model#eventaction)

### `completeEvent()`

Fills `action` from `actionRaw`, or from the last `.`/`:` segment of
`kindRaw`, falling back to the kind's default verb, then `other`.

```ts
function completeEvent(event: ForgeEventInput): ForgeEvent
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        event
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#forgeeventinput">
        <code>
          ForgeEventInput
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`ForgeEvent`](https://forges.link/reference/data-model#forgeevent)

### `reviewState()`

Normalises a forge-native review verdict (`APPROVED`, `changes_requested`, ...) into a [`ReviewState`](https://forges.link/reference/data-model#reviewstate).

```ts
function reviewState(raw: string | undefined): ReviewState
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        raw
      </code>
    </td>
    
    <td>
      <code>
        string | undefined
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`ReviewState`](https://forges.link/reference/data-model#reviewstate)

### `verifyHmacSignature()`

Checks a hex HMAC-SHA256 of the raw body, sent in the first of `header`
present, after an optional `prefix` such as `sha256=`. The delivery's own
`secret` takes precedence over the provider's.

```ts
function verifyHmacSignature(delivery: WebhookDelivery, secret: string | undefined, { header, prefix = '' }: { header: string | readonly string[], prefix?: string }): Promise<boolean>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        delivery
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#webhookdelivery">
        <code>
          WebhookDelivery
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        secret
      </code>
    </td>
    
    <td>
      <code>
        string | undefined
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        { header, prefix = '' }
      </code>
    </td>
    
    <td>
      <code>
        { header: string | readonly string[], prefix?: string }
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Promise<boolean>`

### `verifySharedToken()`

Checks a secret sent verbatim in `header`.

```ts
function verifySharedToken(delivery: WebhookDelivery, secret: string | undefined, header: string): boolean
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        delivery
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#webhookdelivery">
        <code>
          WebhookDelivery
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        secret
      </code>
    </td>
    
    <td>
      <code>
        string | undefined
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        header
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `boolean`

### `RefChange`

One ref update in a push delivery.

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        ref
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      A full ref such as <code>
        refs/heads/main
      </code>
      
      , or a bare name when <code>
        refType
      </code>
      
       is given.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        refType?
      </code>
    </td>
    
    <td>
      <code>
        'branch' | 'tag'
      </code>
    </td>
    
    <td>
      Whether the ref is a branch or a tag.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        before?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        after?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        created?
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        deleted?
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        forced?
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        commits?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#pushcommit">
        <code>
          PushCommit[]
        </code>
      </a>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        commitCount?
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      Commits pushed, when the forge reports more than it sends.
    </td>
  </tr>
</tbody>
</table>

### `refEvent()`

The kind, detail and summary of one ref update in a push: a deletion, a creation, or new commits. Without
`commits` or `commitCount`, the detail has no `commitCount`.

```ts
function refEvent(who: string, change: RefChange): Pick<ForgeEventInput, 'kind' | 'action' | 'detail' | 'summary'>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        who
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        change
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#refchange">
        <code>
          RefChange
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`Pick<ForgeEventInput, 'kind' | 'action' | 'detail' | 'summary'>`](https://forges.link/contributing/provider-kit#forgeeventinput)

### `NativeEventMap`

Native event names per normalised kind, as a forge names them in a hook subscription.

**type:** [`Partial<Record<EventKind, readonly string[]>>`](https://forges.link/reference/data-model#eventkind)

### `nativeEventsFor()`

The forge's own event names for `events`, plus any `nativeEvents` passed through unchanged.

```ts
function nativeEventsFor(map: NativeEventMap, events: EventKind[] | undefined, nativeEvents: string[] | undefined): string[]
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        map
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#nativeeventmap">
        <code>
          NativeEventMap
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        events
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#eventkind">
        <code>
          EventKind[] | undefined
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        nativeEvents
      </code>
    </td>
    
    <td>
      <code>
        string[] | undefined
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `string[]`

## Cryptography

### `toBase64()`

Base64 for arbitrary bytes, a byte at a time so a large buffer cannot overflow the call stack.

```ts
function toBase64(bytes: Uint8Array): string
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        bytes
      </code>
    </td>
    
    <td>
      <code>
        Uint8Array
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `string`

### `hmacSha256Hex()`

Lowercase hex HMAC-SHA256 of `body` under `secret`.

```ts
function hmacSha256Hex(secret: string, body: string | Uint8Array): Promise<string>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        secret
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        body
      </code>
    </td>
    
    <td>
      <code>
        string | Uint8Array
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Promise<string>`

### `timingSafeEqual()`

Constant-time comparison of two strings. The time taken depends only on the
length of `a`, so pass the untrusted value as `a`.

```ts
function timingSafeEqual(a: string, b: string): boolean
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        a
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        b
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `boolean`

### `JwtClaims`

The claims of a signed JWT. Other claims are passed through.

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        iss
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The issuer, such as the app ID.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        iat
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      When the token was issued, in seconds since the epoch.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        exp
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      When the token expires, in seconds since the epoch.
    </td>
  </tr>
</tbody>
</table>

### `signRs256Jwt()`

Signs an RS256 JWT with a PEM-encoded RSA private key.

```ts
function signRs256Jwt(privateKeyPem: string, claims: JwtClaims): Promise<string>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        privateKeyPem
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        claims
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#jwtclaims">
        <code>
          JwtClaims
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Promise<string>`

### `headerValue()`

The value of a header, whatever the casing of `name`, from a `Headers` object or a plain record.

```ts
function headerValue(headers: Headers | Record<string, string>, name: string): string | undefined
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        headers
      </code>
    </td>
    
    <td>
      <code>
        Headers | Record<string, string>
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        name
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `string | undefined`

### `bodyText()`

A request body as text.

```ts
function bodyText(body: string | Uint8Array): string
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        body
      </code>
    </td>
    
    <td>
      <code>
        string | Uint8Array
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `string`

### `sha256Hex()`

Lowercase hex SHA-256 of `body`.

```ts
function sha256Hex(body: string | Uint8Array): Promise<string>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        body
      </code>
    </td>
    
    <td>
      <code>
        string | Uint8Array
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Promise<string>`

### `signEdDsaJwt()`

Signs an EdDSA (Ed25519) JWT with a PKCS#8 PEM private key. `kid` goes in the JOSE header.

```ts
function signEdDsaJwt(privateKeyPem: string, claims: JwtClaims, kid?: string): Promise<string>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        privateKeyPem
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        claims
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#jwtclaims">
        <code>
          JwtClaims
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        kid?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Promise<string>`

### `Ed25519Jwk`

An Ed25519 public key in JWK form, as served from a JWKS endpoint.

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        kty
      </code>
    </td>
    
    <td>
      <code>
        'OKP'
      </code>
    </td>
    
    <td>
      The key type, always <code>
        OKP
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        crv
      </code>
    </td>
    
    <td>
      <code>
        'Ed25519'
      </code>
    </td>
    
    <td>
      The curve, always <code>
        Ed25519
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        x
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The public key, base64url encoded.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        kid?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
</tbody>
</table>

### `verifyEd25519()`

Verifies an Ed25519 signature (base64) over `data` with a JWK public key.

```ts
function verifyEd25519(jwk: Ed25519Jwk, data: string | Uint8Array, signatureBase64: string): Promise<boolean>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        jwk
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#ed25519jwk">
        <code>
          Ed25519Jwk
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        data
      </code>
    </td>
    
    <td>
      <code>
        string | Uint8Array
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        signatureBase64
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Promise<boolean>`

### `hmacSha256Base64()`

Base64 HMAC-SHA256 of `body` under `secret`.

```ts
function hmacSha256Base64(secret: string, body: string | Uint8Array): Promise<string>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        secret
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        body
      </code>
    </td>
    
    <td>
      <code>
        string | Uint8Array
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Promise<string>`

## Helpers

### `supportOnly()`

Marks every declared verb unsupported except the capabilities in `keep` and
anything under them, for a credential that reaches only part of the API.

**Example**

```ts
return appItself ? supportOnly(spec, ['installations']) : spec
```

```ts
function supportOnly<T extends ProviderSpec>(spec: T, keep: readonly string[]): T
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        spec
      </code>
    </td>
    
    <td>
      <code>
        T
      </code>
    </td>
    
    <td>
      The spec that <code>
        setup()
      </code>
      
       declares.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        keep
      </code>
    </td>
    
    <td>
      <code>
        readonly string[]
      </code>
    </td>
    
    <td>
      Capability paths, such as <code>
        installations
      </code>
      
      , that stay as declared.
    </td>
  </tr>
</tbody>
</table>

**Returns:** `T`

### `fromBase64()`

Decodes base64, tolerating the newlines GitHub and Gitea wrap it in.

```ts
function fromBase64(value: string): Uint8Array
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        value
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Uint8Array`

### `toFileContent()`

Shapes bytes as the caller asked: UTF-8 text for `as: 'text'`, bytes
otherwise. Rejects with [`ContentNotTextError`](https://forges.link/reference/errors#contentnottexterror) when text was asked for
and the bytes are not valid UTF-8.

```ts
function toFileContent(bytes: Uint8Array, file: FileMetadata, options: FileOptions | undefined, context?: { forge?: string, instance?: string }): FileContent
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        bytes
      </code>
    </td>
    
    <td>
      <code>
        Uint8Array
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        file
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#filemetadata">
        <code>
          FileMetadata
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        options
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#fileoptions">
        <code>
          FileOptions | undefined
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        context?
      </code>
    </td>
    
    <td>
      <code>
        { forge?: string, instance?: string }
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`FileContent`](https://forges.link/reference/data-model#filecontent)

### `toMergeError()`

Maps a generic merge-endpoint failure onto [`MergeBlockedError`](https://forges.link/reference/data-model#mergeblockederror) or [`MergeConflictError`](https://forges.link/reference/data-model#mergeconflicterror).

```ts
function toMergeError(error: unknown): unknown
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        error
      </code>
    </td>
    
    <td>
      <code>
        unknown
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `unknown`

### `soleMergeMethod()`

Picks the only allowed merge method, or throws [`MergeMethodRequiredError`](https://forges.link/reference/data-model#mergemethodrequirederror).

```ts
function soleMergeMethod(allowed: Partial<Record<MergeMethod, boolean | undefined>>, context?: ForgeErrorContext): MergeMethod
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        allowed
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#mergemethod">
        <code>
          Partial<Record<MergeMethod, boolean | undefined>>
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        context?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/errors#forgeerrorcontext">
        <code>
          ForgeErrorContext
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`MergeMethod`](https://forges.link/reference/data-model#mergemethod)

### `reactionContent()`

The normalised name for a forge-native reaction name, or `'other'` where there is none.

```ts
function reactionContent(raw: string): ReactionContent | 'other'
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        raw
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`ReactionContent | 'other'`](https://forges.link/reference/data-model#reactioncontent)

### `ForgeEventInput`

A [`ForgeEvent`](https://forges.link/reference/data-model#forgeevent) as a provider builds it; core derives `action` when it is absent.

**type:** `Omit<ForgeEvent, 'action'> & { action?: EventAction }`

### `forgeIterable()`

Wraps a generator so warnings it reports are collected on the returned
iterable rather than interrupting iteration.

```ts
function forgeIterable<T>(run: (warn: (warning: ForgeWarning) => void) => AsyncIterable<T>): ForgeIterable<T>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        run
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/requests#forgewarning">
        <code>
          (warn: (warning: ForgeWarning) => void) => AsyncIterable<T>
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `ForgeIterable<T>`

### `iteratePages()`

Drives a `page()` function until it reports no further cursor, collecting page warnings.

```ts
function iteratePages<T, O extends { cursor?: Cursor } = ListOptions>(page: (options: O) => Promise<Page<T>>, options: O = {} as O): ForgeIterable<T>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        page
      </code>
    </td>
    
    <td>
      <code>
        (options: O) => Promise<Page<T>>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        options?
      </code>
    </td>
    
    <td>
      <code>
        O
      </code>
    </td>
    
    <td>
      Defaults to <code>
        {} as O
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

**Returns:** `ForgeIterable<T>`

### `toWarning()`

Turns a caught error into a serialisable warning.

```ts
function toWarning(code: string, error: unknown, subject?: string): ForgeWarning
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        code
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        error
      </code>
    </td>
    
    <td>
      <code>
        unknown
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        subject?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`ForgeWarning`](https://forges.link/reference/requests#forgewarning)

### `mapConcurrent()`

Maps with at most `limit` calls in flight, preserving order. Once a call rejects, no further calls start.

```ts
function mapConcurrent<T, R>(items: readonly T[], limit: number, fn: (item: T) => Promise<R>): Promise<R[]>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        items
      </code>
    </td>
    
    <td>
      <code>
        readonly T[]
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        limit
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fn
      </code>
    </td>
    
    <td>
      <code>
        (item: T) => Promise<R>
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Promise<R[]>`

### `getManyConcurrently()`

`threads.getMany` for forges without a batch endpoint. A rate limit or a rejected credential rejects the call; other failures become per-item warnings.

```ts
function getManyConcurrently(refs: ThreadRef[], get: (ref: ThreadRef, options?: BaseOptions) => Promise<Thread>, options: BaseOptions = {}): Promise<GetManyResult[]>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        refs
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#threadref">
        <code>
          ThreadRef[]
        </code>
      </a>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        get
      </code>
    </td>
    
    <td>
      <code>
        (ref: ThreadRef, options?: BaseOptions) => Promise<Thread>
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        options?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/requests#baseoptions">
        <code>
          BaseOptions
        </code>
      </a>
    </td>
    
    <td>
      Defaults to <code>
        {}
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`Promise<GetManyResult[]>`](https://forges.link/reference/data-model#getmanyresult)

### `versionAtLeast()`

Compares dotted numeric versions, ignoring any suffix after the numbers.

```ts
function versionAtLeast(version: string | undefined, minimum: string): boolean
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        version
      </code>
    </td>
    
    <td>
      <code>
        string | undefined
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        minimum
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `boolean`

### `toDate()`

Reads a timestamp from a forge response, or `undefined` when it is empty or not a date.

```ts
function toDate(value: string | number | null | undefined): Date | undefined
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        value
      </code>
    </td>
    
    <td>
      <code>
        string | number | null | undefined
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Date | undefined`

### `hostOf()`

The host of `baseUrl`, including the port when there is one.

```ts
function hostOf(baseUrl: string): string
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        baseUrl
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `string`

### `requireThread()`

Narrows a ref to one a provider can address, or throws [`UnresolvedThreadError`](https://forges.link/reference/errors#unresolvedthreaderror).

```ts
function requireThread(ref: ThreadRef, context?: ForgeErrorContext): ResolvedThreadRef
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        ref
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#threadref">
        <code>
          ThreadRef
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        context?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/errors#forgeerrorcontext">
        <code>
          ForgeErrorContext
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`ResolvedThreadRef`](https://forges.link/reference/data-model#resolvedthreadref)

### `requireIssueOrPull()`

Narrows a ref to an issue or pull request, or throws
[`UnsupportedOperationError`](https://forges.link/reference/errors#unsupportedoperationerror) naming the verb that needs one.

```ts
function requireIssueOrPull(ref: ThreadRef, context: ForgeErrorContext, verb: string): ResolvedThreadRef & { kind: 'issue' | 'pull_request' }
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        ref
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#threadref">
        <code>
          ThreadRef
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        context
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/errors#forgeerrorcontext">
        <code>
          ForgeErrorContext
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        verb
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`ResolvedThreadRef & { kind: 'issue' | 'pull_request' }`](https://forges.link/reference/data-model#resolvedthreadref)

### `resolveToken()`

The token in `auth`, read again on every call when it is a function.

```ts
function resolveToken(auth: TokenAuth): Promise<string>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        auth
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/providers#tokenauth">
        <code>
          TokenAuth
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Promise<string>`

### `actorLogin()`

A login from either a login string or an actor.

```ts
function actorLogin(actor: string | Actor): string
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        actor
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#actor">
        <code>
          string | Actor
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `string`

### `toPage()`

Maps one fetched page into a [`Page`](https://forges.link/reference/requests#page). The cursor is kept only when there is a next page.

```ts
function toPage<R, T>(result: FetchResult<R[]>, map: (raw: R) => T | undefined, warnings?: ForgeWarning[]): Page<T>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        result
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#fetchresult">
        <code>
          FetchResult<R[]>
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        map
      </code>
    </td>
    
    <td>
      <code>
        (raw: R) => T | undefined
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        warnings?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/requests#forgewarning">
        <code>
          ForgeWarning[]
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Page<T>`

### `ListingExtras`

Extra options for a listing: the query, how to select the items and map errors, and where to collect warnings.

**extends:** [`Pick<PaginateOptions, 'query' | 'select' | 'mapError'>`](https://forges.link/contributing/provider-kit#paginateoptions)

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        warnings?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/requests#forgewarning">
        <code>
          ForgeWarning[]
        </code>
      </a>
    </td>
    
    <td>
      Collects the non-fatal warnings of the listing.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        query?
      </code>
    </td>
    
    <td>
      <code>
        Record<string, string | number | boolean | undefined>
      </code>
    </td>
    
    <td>
      Query parameters. Parameters that are <code>
        undefined
      </code>
      
       are left out. Inherited from <a href="https://forges.link/contributing/provider-kit#requestoptions">
        <code>
          RequestOptions
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        select()?
      </code>
    </td>
    
    <td>
      <code>
        (body: unknown, linkNext?: string) => { items: unknown[], next?: string, total?: number }
      </code>
    </td>
    
    <td>
      Reads items and the next page URL from a response body, for APIs that paginate in the body (Bitbucket's <code>
        values
      </code>
      
       / <code>
        next
      </code>
      
      ). Without it, the body is the item array and the next page comes from the <code>
        Link
      </code>
      
       header. <code>
        linkNext
      </code>
      
       is the <code>
        Link
      </code>
      
       header's next URL, for APIs that wrap items in the body but still paginate with <code>
        Link
      </code>
      
      . <code>
        total
      </code>
      
       is the item total the body reports, such as a search's <code>
        total_count
      </code>
      
      . Inherited from <a href="https://forges.link/contributing/provider-kit#paginateoptions">
        <code>
          PaginateOptions
        </code>
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        mapError()?
      </code>
    </td>
    
    <td>
      <code>
        (error: unknown) => unknown
      </code>
    </td>
    
    <td>
      Rewrites a failure from this request, for endpoints whose statuses mean something specific. Inherited from <a href="https://forges.link/contributing/provider-kit#requestoptions">
        <code>
          RequestOptions
        </code>
      </a>
      
      .
    </td>
  </tr>
</tbody>
</table>

### `Listing`

One page of `path` as the model, with `options` mapped onto the forge's page-size parameter.

**type:** `<R, T>(path: string, options: PageOptions, map: (raw: R) => T | undefined, extras?: ListingExtras) => Promise<Page<T>>`

### `createListing()`

Builds a [`Listing`](https://forges.link/contributing/provider-kit#listing) for a forge that names its page-size parameter `pageParam`.

```ts
function createListing(fetcher: Fetcher, pageParam: string, defaultPerPage?: number): Listing
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        fetcher
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#fetcher">
        <code>
          Fetcher
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pageParam
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        defaultPerPage?
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`Listing`](https://forges.link/contributing/provider-kit#listing)

### `phased()`

Chains listings that a forge serves from separate endpoints. The cursor
`token` records which phase is next, ahead of the phase's own token. With
one phase, the first page is conditional as that phase's is; with more,
one validator cannot cover every endpoint, so no page has an `etag`.

```ts
function phased<T>(phases: Array<(cursor?: Cursor) => Promise<Page<T>>>, cursor?: Cursor): Promise<Page<T>>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        phases
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/requests#cursor">
        <code>
          Array<(cursor?: Cursor) => Promise<Page<T>>>
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cursor?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/requests#cursor">
        <code>
          Cursor
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `Promise<Page<T>>`

### `hasEveryLabel()`

Whether `labels` include every name in `wanted`; true when nothing is wanted.

```ts
function hasEveryLabel(labels: ReadonlyArray<{ name: string }> | undefined, wanted: readonly string[] | undefined): boolean
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        labels
      </code>
    </td>
    
    <td>
      <code>
        ReadonlyArray<{ name: string }> | undefined
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        wanted
      </code>
    </td>
    
    <td>
      <code>
        readonly string[] | undefined
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `boolean`

### `summariseChecks()`

Any failure fails, else any pending is pending, else any unknown (or none at all) is unknown, else success.

```ts
function summariseChecks(states: CheckState[], url?: string): ChecksSummary
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        states
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#checkstate">
        <code>
          CheckState[]
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        url?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`ChecksSummary`](https://forges.link/reference/data-model#checkssummary)

### `memo()`

Caches the result of `load` after its first call. A rejected load is
forgotten so the next call retries; with `ttl` (milliseconds) a resolved
value is reloaded once it is older than that.

```ts
function memo<T>(load: () => Promise<T>, ttl?: number): () => Promise<T>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        load
      </code>
    </td>
    
    <td>
      <code>
        () => Promise<T>
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ttl?
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `() => Promise<T>`

### `memoBy()`

[`memo`](https://forges.link/contributing/provider-kit#memo) per key.

```ts
function memoBy<K, T>(load: (key: K) => Promise<T>): (key: K) => Promise<T>
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        load
      </code>
    </td>
    
    <td>
      <code>
        (key: K) => Promise<T>
      </code>
    </td>
  </tr>
</tbody>
</table>

**Returns:** `(key: K) => Promise<T>`

### `syntheticReview()`

A review standing in for an approval, vote or participant state on a forge
that has no review objects. `comments` is `false` because there is nothing
to hang inline comments on.

```ts
function syntheticReview(thread: ResolvedThreadRef, id: string, state: ReviewState, extras: { author?: Actor, stateRaw?: string, submittedAt?: Date, raw: unknown }): Review
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        thread
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#resolvedthreadref">
        <code>
          ResolvedThreadRef
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        id
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        state
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#reviewstate">
        <code>
          ReviewState
        </code>
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        extras
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#actor">
        <code>
          { author?: Actor, stateRaw?: string, submittedAt?: Date, raw: unknown }
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`Review`](https://forges.link/reference/data-model#review)

### `hexColour()`

A label colour as six hex digits, with the `#` prefix the forge expects. `ededed` when none is given.

```ts
function hexColour(colour: string | undefined, prefix: '#' | '' = ''): string
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        colour
      </code>
    </td>
    
    <td>
      <code>
        string | undefined
      </code>
    </td>
    
    <td>
      
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        prefix?
      </code>
    </td>
    
    <td>
      <code>
        '#' | ''
      </code>
    </td>
    
    <td>
      Defaults to <code>
        ''
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

**Returns:** `string`

### `WebLinks`

How a provider builds and reads its web URLs. Builders return a path relative
to `baseUrl` or an absolute URL, and may return `undefined` when the forge has no such page.

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        baseUrl
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The base URL of the forge website, such as <code>
        https://github.com
      </code>
      
       or <code>
        https://example.com/gitlab
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repo()
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#reporef">
        <code>
          (repo: RepoRef) => string
        </code>
      </a>
    </td>
    
    <td>
      The page of a repository.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        section()?
      </code>
    </td>
    
    <td>
      <code>
        (repo: RepoRef, section: RepoSection) => string | undefined
      </code>
    </td>
    
    <td>
      The page of one of a repository's sections, such as its issues, pull requests, stargazers or forks.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        thread()
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#resolvedthreadref">
        <code>
          (ref: ResolvedThreadRef) => string | undefined
        </code>
      </a>
    </td>
    
    <td>
      The page of an issue or pull request.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        comment()?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#resolvedcommentref">
        <code>
          (ref: ResolvedCommentRef) => string | undefined
        </code>
      </a>
    </td>
    
    <td>
      The page of a comment, anchored on its thread.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        release()?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#releaseref">
        <code>
          (ref: ReleaseRef) => string | undefined
        </code>
      </a>
    </td>
    
    <td>
      The page of a release.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        file()?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#reporef">
        <code>
          (repo: RepoRef, path: string, at: string, line?: number) => string | undefined
        </code>
      </a>
    </td>
    
    <td>
      The page of a file at a revision, optionally at a line.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        raw()?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#reporef">
        <code>
          (repo: RepoRef, path: string, at: string) => string | undefined
        </code>
      </a>
    </td>
    
    <td>
      The raw bytes of a file at a revision.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        compare()?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#reporef">
        <code>
          (repo: RepoRef, base: string, head: string) => string | undefined
        </code>
      </a>
    </td>
    
    <td>
      The page that compares two revisions.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parse()
      </code>
    </td>
    
    <td>
      <code>
        (segments: string[], url: URL, origin: ForgeOrigin) => ParsedForgeUrl | undefined
      </code>
    </td>
    
    <td>
      Reads a URL already known to be under <code>
        baseUrl
      </code>
      
      , split into the path segments after it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reference()?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#resolvedthreadref">
        <code>
          (ref: ResolvedThreadRef, sameRepo: boolean, expand: boolean) => string | undefined
        </code>
      </a>
    </td>
    
    <td>
      The forge's cross-reference syntax; <code>
        undefined
      </code>
      
       falls back to the thread URL.
    </td>
  </tr>
</tbody>
</table>

### `GitHubShape`

How a forge that lays out its website like GitHub differs from GitHub.

<table>
<thead>
  <tr>
    <th>
      Member
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        pull
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The path segment of pull requests, such as <code>
        pull
      </code>
      
       or <code>
        pulls
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        discussions?
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      The forge has discussions, which are addressed like issues.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        commentFragment
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Fragment for a comment id, for example <code>
        issuecomment-
      </code>
      
       or <code>
        note_
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        file()
      </code>
    </td>
    
    <td>
      <code>
        (at: string) => string
      </code>
    </td>
    
    <td>
      The path segment that leads to a file at a revision.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parseFile()?
      </code>
    </td>
    
    <td>
      <code>
        (segments: string[]) => { at: string, path: string } | undefined
      </code>
    </td>
    
    <td>
      Reads a file page back from the segments after the repository name; defaults to <code>
        blob/{at}/{path}
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        commit?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The path segment of commits; defaults to <code>
        commit
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        raw?
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      Whether the forge serves raw files at <code>
        /raw/{at}/{path}
      </code>
      
      ; defaults to <code>
        true
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        rawOrigin?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The origin that serves raw files at <code>
        /{owner}/{name}/{at}/{path}
      </code>
      
      ; when unset, raw files are linked at <code>
        /raw/{at}/{path}
      </code>
      
       on the forge.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        lineFragment()
      </code>
    </td>
    
    <td>
      <code>
        (line: number) => string
      </code>
    </td>
    
    <td>
      The URL fragment that selects a line of a file.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pullPrefix?
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Reference prefix for pulls when it differs from issues.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sections?
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/reference/data-model#reposection">
        <code>
          Partial<Record<RepoSection, string | null>>
        </code>
      </a>
    </td>
    
    <td>
      Path segments for sections whose path is not the section's own name, such as a forge that lists stargazers at <code>
        stars
      </code>
      
      ; <code>
        null
      </code>
      
       marks a section the forge has no page for, so <code>
        section()
      </code>
      
       returns <code>
        undefined
      </code>
      
       for it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reserved?
      </code>
    </td>
    
    <td>
      <code>
        readonly string[]
      </code>
    </td>
    
    <td>
      Reserved owner segments.
    </td>
  </tr>
</tbody>
</table>

### `githubShapedWeb()`

Web links for forges laid out like GitHub: `/{owner}/{name}/issues/{n}` and friends.

```ts
function githubShapedWeb(baseUrl: string, shape: GitHubShape): WebLinks
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        baseUrl
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        shape
      </code>
    </td>
    
    <td>
      <a href="https://forges.link/contributing/provider-kit#githubshape">
        <code>
          GitHubShape
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

**Returns:** [`WebLinks`](https://forges.link/contributing/provider-kit#weblinks)

These exports are documented elsewhere: [`ProviderFactoryFunction`](https://forges.link/reference/providers#providerfactoryfunction).


## Sitemap

See the full [sitemap](https://forges.link/sitemap.md) for all pages.
