Repository: octokit/octokit.js Branch: main Commit: fd769731bee3 Files: 31 Total size: 76.8 KB Directory structure: gitextract_d81oa9rl/ ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug.yml │ │ ├── documentation.yml │ │ ├── feature.yml │ │ └── maintenance.yml │ ├── pull_request_template.md │ ├── renovate.json │ └── workflows/ │ ├── add_to_octokit_project.yml │ ├── codeql.yml │ ├── immediate-response.yml │ ├── release.yml │ ├── test.yml │ └── update-prettier.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── MAINTAINING.md ├── README.md ├── SECURITY.md ├── package.json ├── scripts/ │ └── build.mjs ├── src/ │ ├── app.ts │ ├── index.ts │ ├── octokit.ts │ └── version.ts ├── test/ │ ├── app.test.ts │ ├── smoke.test.ts │ ├── tsconfig.test.json │ └── typescript-validate.ts ├── tsconfig.json └── vite.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE/bug.yml ================================================ name: Bug description: File a bug report title: "[BUG]: " labels: ["Type: Bug", "Status: Triage"] body: - type: markdown attributes: value: | Thanks for taking the time to fill out this bug report! - type: textarea id: what-happened attributes: label: What happened? description: What did you do? What happened? What did you expect to happen? placeholder: Put your description of the bug here. validations: required: true - type: textarea id: versions attributes: label: Versions description: What versions of the relevant software are you running? placeholder: Octokit.js v2.0.10, Node v16.18.0 validations: required: true - type: textarea id: logs attributes: label: Relevant log output description: | Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. Please check your logs before submission to ensure sensitive information is redacted. render: shell - type: checkboxes id: terms attributes: label: Code of Conduct description: By submitting this issue, you agree to follow our [Code of Conduct](CODE_OF_CONDUCT.md) options: - label: I agree to follow this project's Code of Conduct required: true ================================================ FILE: .github/ISSUE_TEMPLATE/documentation.yml ================================================ name: Documentation description: Update or add documentation title: "[DOCS]: " labels: ["Type: Documentation", "Status: Triage"] body: - type: markdown attributes: value: | Thanks for taking the time to fill this out! - type: textarea id: describe-need attributes: label: Describe the need description: What do you wish was different about our docs? placeholder: Describe the need for documentation updates here. validations: required: true - type: input id: sdk_version attributes: label: SDK Version description: Do these docs apply to a specific SDK version? placeholder: Octokit.NET v4.0.1 validations: required: false - type: input id: api_version attributes: label: API Version description: Do these docs apply to a specific version of the GitHub REST API or GraphQL API? placeholder: ex. v1.1.1 validations: required: false - type: textarea id: logs attributes: label: Relevant log output description: | Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. Please check your logs before submission to ensure sensitive information is redacted. render: shell - type: checkboxes id: terms attributes: label: Code of Conduct description: By submitting this issue, you agree to follow our [Code of Conduct](CODE_OF_CONDUCT.md) options: - label: I agree to follow this project's Code of Conduct required: true ================================================ FILE: .github/ISSUE_TEMPLATE/feature.yml ================================================ name: Feature description: Suggest an idea for a new feature or enhancement title: "[FEAT]: " labels: ["Type: Feature", "Status: Triage"] body: - type: markdown attributes: value: | Thanks for taking the time to fill this out! - type: textarea id: describe-need attributes: label: Describe the need description: What do you want to happen? What problem are you trying to solve? placeholder: Describe the need for the feature. validations: required: true - type: input id: sdk_version attributes: label: SDK Version description: Does this feature suggestion apply to a specific SDK version? placeholder: Octokit.rb v6.0.0 validations: required: false - type: input id: api_version attributes: label: API Version description: Does this feature suggestion apply to a specific version of the GitHub REST API or GraphQL API? placeholder: ex. v1.1.1 validations: required: false - type: textarea id: logs attributes: label: Relevant log output description: | Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. Please check your logs before submission to ensure sensitive information is redacted. render: shell - type: checkboxes id: terms attributes: label: Code of Conduct description: By submitting this issue, you agree to follow our [Code of Conduct](CODE_OF_CONDUCT.md) options: - label: I agree to follow this project's Code of Conduct required: true ================================================ FILE: .github/ISSUE_TEMPLATE/maintenance.yml ================================================ name: Maintenance description: Dependencies, cleanup, refactoring, reworking of code title: "[MAINT]: " labels: ["Type: Maintenance", "Status: Triage"] body: - type: markdown attributes: value: | Thanks for taking the time to fill this out! - type: textarea id: describe-need attributes: label: Describe the need description: What do you want to happen? placeholder: Describe the maintenance need here. validations: required: true - type: input id: sdk_version attributes: label: SDK Version description: Does this maintenance apply to a specific SDK version? placeholder: terraform-provider-github v5.7.0 validations: required: false - type: input id: api_version attributes: label: API Version description: Does this maintenance apply to a specific version of the GitHub REST API or GraphQL API? placeholder: ex. v1.1.1 validations: required: false - type: textarea id: logs attributes: label: Relevant log output description: | Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. Please check your logs before submission to ensure sensitive information is redacted. render: shell - type: checkboxes id: terms attributes: label: Code of Conduct description: By submitting this issue, you agree to follow our [Code of Conduct](CODE_OF_CONDUCT.md) options: - label: I agree to follow this project's Code of Conduct required: true ================================================ FILE: .github/pull_request_template.md ================================================ Resolves #ISSUE_NUMBER ---- ### Before the change? * ### After the change? * ### Pull request checklist - [ ] Tests for the changes have been added (for bug fixes / features) - [ ] Docs have been reviewed and added / updated if needed (for bug fixes / features) ### Does this introduce a breaking change? Please see our docs on [breaking changes](https://github.com/octokit/.github/blob/master/community/breaking_changes.md) to help! - [ ] Yes - [ ] No ---- ================================================ FILE: .github/renovate.json ================================================ { "extends": [ "github>octokit/.github" ] } ================================================ FILE: .github/workflows/add_to_octokit_project.yml ================================================ name: Add PRs and issues to Octokit org project on: issues: types: [reopened, opened] pull_request_target: types: [reopened, opened] jobs: add-to-project: name: Add issue to project runs-on: ubuntu-latest continue-on-error: true steps: - uses: actions/add-to-project@v1.0.2 with: project-url: https://github.com/orgs/octokit/projects/10 github-token: ${{ secrets.OCTOKITBOT_PROJECT_ACTION_TOKEN }} labeled: "Status: Stale" label-operator: NOT ================================================ FILE: .github/workflows/codeql.yml ================================================ name: "CodeQL" on: push: branches: [ "main", beta ] pull_request: # The branches below must be a subset of the branches above branches: [ "main" ] schedule: - cron: '19 5 * * 1' jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'javascript' ] steps: - name: Checkout repository uses: actions/checkout@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} - name: Autobuild uses: github/codeql-action/autobuild@v4 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 with: category: "/language:${{matrix.language}}" ================================================ FILE: .github/workflows/immediate-response.yml ================================================ name: Issue/PR response permissions: issues: write pull-requests: write on: issues: types: - opened pull_request_target: types: - opened jobs: respond-to-issue: if: ${{ github.actor != 'dependabot[bot]' && github.actor != 'renovate[bot]' && github.actor != 'githubactions[bot]' && github.actor != 'octokitbot' }} runs-on: ubuntu-latest steps: - name: Determine issue or PR number id: extract run: echo "NUMBER=${{ github.event.issue.number || github.event.pull_request.number }}" >> "$GITHUB_OUTPUT" - name: Respond to issue or PR uses: peter-evans/create-or-update-comment@v5 with: issue-number: ${{ steps.extract.outputs.NUMBER }} body: > 👋 Hi! Thank you for this contribution! Just to let you know, our GitHub SDK team does a round of issue and PR reviews twice a week, every Monday and Friday! We have a [process in place](https://github.com/octokit/.github/blob/main/community/prioritization_response.md#overview) for prioritizing and responding to your input. Because you are a part of this community please feel free to comment, add to, or pick up any issues/PRs that are labeled with `Status: Up for grabs`. You & others like you are the reason all of this works! So thank you & happy coding! 🚀 ================================================ FILE: .github/workflows/release.yml ================================================ name: Release "on": push: branches: - main - next - beta - "*.x" - debug # These are recommended by the semantic-release docs: https://github.com/semantic-release/npm#npm-provenance permissions: contents: write # to be able to publish a GitHub release issues: write # to be able to comment on released issues pull-requests: write # to be able to comment on released pull requests id-token: write # to enable use of OIDC for npm provenance jobs: release: name: release runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: node-version: lts/* cache: npm - run: npm ci - run: npm run build - run: npx semantic-release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.OCTOKITBOT_NPM_TOKEN }} ================================================ FILE: .github/workflows/test.yml ================================================ name: Test "on": push: branches: - main pull_request: types: - opened - synchronize jobs: test_matrix: runs-on: ubuntu-latest strategy: matrix: node_version: - 20 - 22 - 24 steps: - uses: actions/checkout@v6 - name: Use Node.js ${{ matrix.node_version }} uses: actions/setup-node@v6 with: node-version: ${{ matrix.node_version }} cache: npm - run: npm ci - run: npm test test: runs-on: ubuntu-latest needs: test_matrix steps: - run: exit 1 if: ${{ needs.test_matrix.result != 'success' }} - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: node-version: "lts/*" cache: npm - run: npm ci - run: npm run test:typescript - run: npm run lint - run: npm run build if: ${{ always() }} ================================================ FILE: .github/workflows/update-prettier.yml ================================================ name: Update Prettier "on": push: branches: - renovate/prettier-* workflow_dispatch: {} jobs: update_prettier: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: cache: npm node-version: lts/* - run: npm ci - run: npm run lint:fix - uses: gr2m/create-or-update-pull-request-action@v1.x env: GITHUB_TOKEN: ${{ secrets.OCTOKITBOT_PAT }} with: title: Prettier updated body: An update to prettier required updates to your code. branch: ${{ github.ref }} commit-message: "style: prettier" ================================================ FILE: .gitignore ================================================ coverage/ node_modules/ pkg/ .idea/ ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at opensource+octokit@github.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version] [homepage]: https://contributor-covenant.org [version]: https://contributor-covenant.org/version/1/4/ ================================================ FILE: CONTRIBUTING.md ================================================ # How to contribute Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. We appreciate you taking the time to contribute to `octokit` or any of the projects in Octokit's ecosystem. Especially as a new contributor, you have a valuable perspective that we lost a long time ago: you will find things confusing and run into problems that no longer occur to us. Please share them with us, so we can make the experience for future contributors the best it could be. Thank you 💖 ## Creating an Issue Before you create a new Issue: 1. Please make sure there is no open issue in the **Issues Section** of the repository you are working on yet. i.e. 2. If it is a bug report, include the steps to reproduce the issue, and please create a reproducible test case on [runkit.com](https://runkit.com/). Example: 3. If it is a feature request, please share the motivation for the new feature, what alternatives you tried, and how you would implement it. 4. Please include links to the corresponding GitHub documentation. ## Set up the repository locally First, fork the repository. Set up the repository locally. Replace `` with the name of the account you forked to and `` with the repository name you forked. ```shell git clone https://github.com//.git cd npm install ``` Run the tests before making changes to make sure the local setup is working as expected ```shell npm test ``` ## Submitting the Pull Request - Create a new branch locally. - Make your changes in that branch and push them to your fork - Submit a pull request from your topic branch to the main branch on the `octokit/` repository. - Be sure to tag any issues your pull request is taking care of / contributing to. Adding "Closes #123" to a pull request description will automatically close the issue once the pull request is merged in. ## Testing a pull request from GitHub repo locally You can install `@octokit/` from each pull request. Replace `[PULL REQUEST NUMBER]`: ``` npm install https://github.pika.dev/octokit//pr/[PULL REQUEST NUMBER] ``` Once you are done testing, you can revert to the default module `@octokit/` from npm with `npm install @octokit/` ## Maintainers See [MAINTAINING.md](MAINTAINING.md) ================================================ FILE: LICENSE ================================================ The MIT License Copyright (c) 2023 Octokit contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: MAINTAINING.md ================================================ # Maintenance releases ## Merging the Pull Request & releasing a new version Releases are automated using [semantic-release](https://github.com/semantic-release/semantic-release). The following commit message conventions determine which version is released: 1. `fix: ...` or `fix(scope name): ...` prefix in subject: bumps fix version, e.g. `1.2.3` → `1.2.4` 2. `feat: ...` or `feat(scope name): ...` prefix in subject: bumps feature version, e.g. `1.2.3` → `1.3.0` 3. `BREAKING CHANGE:` in body: bumps breaking version, e.g. `1.2.3` → `2.0.0` Only one version number is bumped at a time, the highest version change trumps the others. Besides, publishing a new version to npm, semantic-release also creates a git tag and release on GitHub, generates changelogs from the commit messages and puts them into the release notes. Before the publish it runs the `npm run build` script which creates a `pkg/` folder with distributions for browsers, node and Typescript definitions. The contents of the `pkg/` folder are published to the npm registry. If the pull request looks good but does not follow the commit conventions, use the Squash & merge button. > ⚠️ making sure the message is semantic-release compliant before clicking Confirm squash and merge: ![Screenshot of GitHub's Squash and Merge confirm dialog](assets/squash-and-merge-dialog.png)] ## Breaking changes When merging a breaking change using the PR body as specified above, extra care must be taken. Breaking changes must first be merged into the `beta` branch, where further testing may be conducted and additional breaking changes may be combined before cutting a release. The `beta` branch should be created for this purpose and based on `main`. Once the first commit to the branch is landed, a draft PR should be created from `beta` to `main` with the title vX, where X is the next major version. After changes are combined and tested, mark the PR as ready for review, get it reviewed, and merge the `beta` branch into `main` as documented above. `beta` branches are intended to be short-lived. Note the repository for the change: if it's dependent on other repos where the same change must be made, merge the leaf nodes first before the nodes higher up the tree. Your merge order should look something like: 1. octokit/types (when type changes are required) 1. endpoint 1. request 1. plugins 1. auth strategies 1. core 1. \*-methods 1. oauth-app 1. webhooks 1. app 1. octokit/octokit.js 1. octokit/rest.js ## Maintenance releases ### 0. Requirements `semantic-release` is configured in the `package.json` of each repository. If `release.branches` is set, make sure that it includes the line for maintenance releases, for example ```js "release": { "branches": [ "+([0-9]).x", "main", "beta" ], ``` `semantic-release` is run in the`.github/workflows/release.yml` GitHub Action workflow. Make sure it's triggered on push in the `*.x` release branches. ```yml name: Release "on": push: branches: - main - next - beta - "*.x" ``` ### 1. Create a branch for the maintenance version Find the latest version that was released on the maintenance version. For example, if the current version is 3.1, and you want to release maintenance versions for 2.x, then find the latest 2.x version. Say that's 2.10.9. In that example, create a branch based on this tag ``` git checkout -b 2.x v2.10.9 ``` Then push the new `2.x` branch to GitHub ``` git push -u origin HEAD ``` ### 2. Create a pull request with the changes for the new maintenance release Checkout a branch based on the latest maintenance branch, for example ``` git checkout -b 2.x-my-fix 2.x ``` Commit your changes, then push the branch to GitHub and create a pull request with the maintenance branch as base. ### 3. Merge the pull request with the correct commit message Note that maintenance versions only support `fix: ...` and `feat: ...` commits, no breaking versions can be released from a maintenance release. The `.github/workflows/release.yml` action should pick up the commit and release the correct version to both GitHub and npm. The npm release will use a `@release-*.x` tag so that the new release is not picked up as `@latest`. ## Troubleshooting
What can I do if I squashed and merged with a commit message which is not semantic-release compliant? 1. After merging, do a follow up on `https://github.com/octokit//actions/workflows/release.yml` to assure your commit is not triggering any release. You can find an example of a commit squashed and merged with a non semantic-release commit message [here](https://github.com/octokit/plugin-throttling.js/runs/5390685684?check_suite_focus=true) 2. Mention (`@username`) the maintainers of the project in your merged _Pull Request_ to let them know there was an issue with your merged _Pull Request_. We need to make sure no _Pull Request_ is merged until this issue is addressed. 3. Open a new _Pull Request_ with an [empty commit](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---allow-empty). In the description, link to the previous merged _Pull Request_ to give context to the reviewers and request a Review from the maintainers. This time make sure the message is [semantic-release](https://github.com/semantic-release/semantic-release) compliant.
================================================ FILE: README.md ================================================ # octokit.js > The all-batteries-included GitHub SDK for Browsers, Node.js, and Deno. The `octokit` package integrates the three main Octokit libraries 1. **API client** (REST API requests, GraphQL API queries, Authentication) 2. **App client** (GitHub App & installations, Webhooks, OAuth) 3. **Action client** (Pre-authenticated API client for single repository) ## Table of contents - [octokit.js](#octokitjs) - [Features](#features) - [Usage](#usage) - [`Octokit` API Client](#octokit-api-client) - [Constructor options](#constructor-options) - [Authentication](#authentication) - [Proxy Servers (Node.js only)](#proxy-servers-nodejs-only) - [Fetch missing](#fetch-missing) - [REST API](#rest-api) - [`octokit.rest` endpoint methods](#octokitrest-endpoint-methods) - [`octokit.request()`](#octokitrequest) - [Pagination](#pagination) - [Media Type formats](#media-type-formats) - [Request error handling](#request-error-handling) - [GraphQL API queries](#graphql-api-queries) - [Pagination](#pagination-1) - [Schema previews](#schema-previews) - [App client](#app-client) - [GitHub App](#github-app) - [Webhooks](#webhooks) - [OAuth](#oauth) - [App Server](#app-server) - [OAuth for browser apps](#oauth-for-browser-apps) - [Action client](#action-client) - [LICENSE](#license) ## Features - **Complete**. All features of GitHub's platform APIs are covered. - **Prescriptive**. All recommended best practices are implemented. - **Universal**. Works in all modern browsers, [Node.js](https://nodejs.org/), and [Deno](https://deno.land/). - **Tested**. All libraries have a 100% test coverage. - **Typed**. All libraries have extensive TypeScript declarations. - **Decomposable**. Use only the code you need. You can build your own Octokit in only a few lines of code or use the underlying static methods. Make your own tradeoff between functionality and bundle size. - **Extendable**. A feature missing? Add functionalities with plugins, hook into the request or webhook lifecycle or implement your own authentication strategy. ## Usage
Browsers Load octokit directly from esm.sh ```html ```
Deno Load octokit directly from esm.sh ```ts import { Octokit, App } from "https://esm.sh/octokit?dts"; ```
Node Install with npm/pnpm install octokit, or yarn add octokit ```js import { Octokit, App } from "octokit"; ```
> [!IMPORTANT] > As we use [conditional exports](https://nodejs.org/api/packages.html#conditional-exports), you will need to adapt your `tsconfig.json` by setting `"moduleResolution": "node16", "module": "node16"`. > > See the TypeScript docs on [package.json "exports"](https://www.typescriptlang.org/docs/handbook/modules/reference.html#packagejson-exports).
> See this [helpful guide on transitioning to ESM](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) from [@sindresorhus](https://github.com/sindresorhus) ## `Octokit` API Client **standalone minimal Octokit**: [`@octokit/core`](https://github.com/octokit/core.js/#readme). The `Octokit` client can be used to send requests to [GitHub's REST API](https://docs.github.com/rest/) and queries to [GitHub's GraphQL API](https://docs.github.com/graphql). **Example**: Get the username for the authenticated user. ```js // Create a personal access token at https://github.com/settings/tokens/new?scopes=repo const octokit = new Octokit({ auth: `personal-access-token123` }); // Compare: https://docs.github.com/en/rest/reference/users#get-the-authenticated-user const { data: { login }, } = await octokit.rest.users.getAuthenticated(); console.log("Hello, %s", login); ``` ### Constructor options The most commonly used options are
name type description
userAgent String Setting a user agent is required for all requests sent to GitHub's Platform APIs. The user agent defaults to something like this: `octokit.js/v1.2.3 Node.js/v8.9.4 (macOS High Sierra; x64)`. It is recommend to set your own user agent, which will prepend the default one. ```js const octokit = new Octokit({ userAgent: "my-app/v1.2.3", }); ```
authStrategy Function Defaults to [`@octokit/auth-token`](https://github.com/octokit/auth-token.js#readme). See [Authentication](#authentication) below.
auth String or Object Set to a [personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) unless you changed the `authStrategy` option. See [Authentication](#authentication) below.
baseUrl String When using with GitHub Enterprise Server, set `options.baseUrl` to the root URL of the API. For example, if your GitHub Enterprise Server's hostname is `github.acme-inc.com`, then set `options.baseUrl` to `https://github.acme-inc.com/api/v3`. Example ```js const octokit = new Octokit({ baseUrl: "https://github.acme-inc.com/api/v3", }); ```
Advanced options
name type description
request Object - `request.signal`: Use an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) instance to cancel a request. [`abort-controller`](https://www.npmjs.com/package/abort-controller) is an implementation for Node. - `request.fetch`: Replacement for [built-in fetch method](). Node only - `request.timeout` sets a request timeout, defaults to 0 The `request` option can also be set on a per-request basis.
timeZone String Sets the `Time-Zone` header which defines a timezone according to the [list of names from the Olson database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). ```js const octokit = new Octokit({ timeZone: "America/Los_Angeles", }); ``` The time zone header will determine the timezone used for generating the timestamp when creating commits. See [GitHub's Timezones documentation](https://developer.github.com/v3/#timezones).
throttle Object `Octokit` implements request throttling using [`@octokit/plugin-throttling`](https://github.com/octokit/plugin-throttling.js/#readme) By default, requests are retried once and warnings are logged in case of hitting a rate or secondary rate limit. ```js { onRateLimit: (retryAfter, options, octokit) => { octokit.log.warn( `Request quota exhausted for request ${options.method} ${options.url}` ); if (options.request.retryCount === 0) { // only retries once octokit.log.info(`Retrying after ${retryAfter} seconds!`); return true; } }, onSecondaryRateLimit: (retryAfter, options, octokit) => { octokit.log.warn( `SecondaryRateLimit detected for request ${options.method} ${options.url}` ); if (options.request.retryCount === 0) { // only retries once octokit.log.info(`Retrying after ${retryAfter} seconds!`); return true; } }, }; ``` To opt-out of this feature: ```js new Octokit({ throttle: { enabled: false } }); ``` Throttling in a cluster is supported using a Redis backend. See [`@octokit/plugin-throttling` Clustering](https://github.com/octokit/plugin-throttling.js/#clustering)
retry Object `Octokit` implements request retries using [`@octokit/plugin-retry`](https://github.com/octokit/plugin-retry.js/#readme) To opt-out of this feature: ```js new Octokit({ retry: { enabled: false } }); ```
### Authentication By default, the `Octokit` API client supports authentication using a static token. There are different means of authentication that are supported by GitHub, that are described in detail at [octokit/authentication-strategies.js](https://github.com/octokit/authentication-strategies.js/#readme). You can set each of them as the `authStrategy` constructor option, and pass the strategy options as the `auth` constructor option. For example, in order to authenticate as a GitHub App Installation: ```js import { createAppAuth } from "@octokit/auth-app"; const octokit = new Octokit({ authStrategy: createAppAuth, auth: { appId: 1, privateKey: "-----BEGIN PRIVATE KEY-----\n...", installationId: 123, }, }); // authenticates as app based on request URLs const { data: { slug }, } = await octokit.rest.apps.getAuthenticated(); // creates an installation access token as needed // assumes that installationId 123 belongs to @octocat, otherwise the request will fail await octokit.rest.issues.create({ owner: "octocat", repo: "hello-world", title: "Hello world from " + slug, }); ``` You can use the [`App`](#github-app) or [`OAuthApp`](#oauth-app) SDKs which provide APIs and internal wiring to cover most use cases. For example, to implement the above using `App` ```js const app = new App({ appId, privateKey }); const { data: slug } = await app.octokit.rest.apps.getAuthenticated(); const octokit = await app.getInstallationOctokit(123); await octokit.rest.issues.create({ owner: "octocat", repo: "hello-world", title: "Hello world from " + slug, }); ``` Learn more about [how authentication strategies work](https://github.com/octokit/authentication-strategies.js/#how-authentication-strategies-work) or how to [create your own](https://github.com/octokit/authentication-strategies.js/#create-your-own-octokit-authentication-strategy-module). ### Proxy Servers (Node.js only) By default, the `Octokit` API client does not make use of the standard proxy server environment variables. To add support for proxy servers you will need to provide an https client that supports them such as [`undici.ProxyAgent()`](https://undici.nodejs.org/#/docs/api/ProxyAgent). For example, this would use a `ProxyAgent` to make requests through a proxy server: ```js import { fetch as undiciFetch, ProxyAgent } from 'undici'; const myFetch = (url, options) => { return undiciFetch(url, { ...options, dispatcher: new ProxyAgent() }) } const octokit = new Octokit({ request: { fetch: myFetch }, }); ``` If you are writing a module that uses `Octokit` and is designed to be used by other people, you should ensure that consumers can provide an alternative agent for your `Octokit` or as a parameter to specific calls such as: ```js import { fetch as undiciFetch, ProxyAgent } from 'undici'; const myFetch = (url, options) => { return undiciFetch(url, { ...options, dispatcher: new ProxyAgent() }) } octokit.rest.repos.get({ owner, repo, request: { fetch: myFetch }, }); ``` #### Fetch missing If you get the following error: > fetch is not set. Please pass a fetch implementation as new Octokit({ request: { fetch }}). It probably means you are trying to run Octokit with an unsupported version of NodeJS. Octokit requires Node 18 or higher, [which includes a native fetch API](). To bypass this problem you can provide your own `fetch` implementation (or a built-in version like `node-fetch`) like this: ```js import fetch from "node-fetch"; const octokit = new Octokit({ request: { fetch: fetch, }, }); ``` ### REST API There are two ways of using the GitHub REST API, the [`octokit.rest.*` endpoint methods](#octokitrest-endpoint-methods) and [`octokit.request`](#octokitrequest). Both act the same way, the `octokit.rest.*` methods are just added for convenience, they use `octokit.request` internally. For example ```js await octokit.rest.issues.create({ owner: "octocat", repo: "hello-world", title: "Hello, world!", body: "I created this issue using Octokit!", }); ``` Is the same as ```js await octokit.request("POST /repos/{owner}/{repo}/issues", { owner: "octocat", repo: "hello-world", title: "Hello, world!", body: "I created this issue using Octokit!", }); ``` In both cases a given request is authenticated, retried, and throttled transparently by the `octokit` instance which also manages the `accept` and `user-agent` headers as needed. `octokit.request` can be used to send requests to other domains by passing a full URL and to send requests to endpoints that are not (yet) documented in [GitHub's REST API documentation](https://docs.github.com/rest). #### `octokit.rest` endpoint methods Every GitHub REST API endpoint has an associated `octokit.rest` endpoint method for better code readability and developer convenience. See [`@octokit/plugin-rest-endpoint-methods`](https://github.com/octokit/plugin-rest-endpoint-methods.js/#readme) for full details. Example: [Create an issue](https://docs.github.com/en/rest/reference/issues#create-an-issue) ```js await octokit.rest.issues.create({ owner: "octocat", repo: "hello-world", title: "Hello, world!", body: "I created this issue using Octokit!", }); ``` The `octokit.rest` endpoint methods are generated automatically from [GitHub's OpenAPI specification](https://github.com/github/rest-api-description/). We track operation ID and parameter name changes in order to implement deprecation warnings and reduce the frequency of breaking changes. Under the covers, every endpoint method is just `octokit.request` with defaults set, so it supports the same parameters as well as the `.endpoint()` API. #### `octokit.request()` You can call the GitHub REST API directly using `octokit.request`. The `request` API matches GitHub's REST API documentation 1:1 so anything you see there, you can call using `request`. See [`@octokit/request`](https://github.com/octokit/request.js#readme) for all the details. Example: [Create an issue](https://docs.github.com/en/rest/reference/issues#create-an-issue) [![Screenshot of REST API reference documentation for Create an issue](assets/create-an-issue-reference.png)](https://docs.github.com/en/rest/reference/issues#create-an-issue) The `octokit.request` API call corresponding to that issue creation documentation looks like this: ```js // https://docs.github.com/en/rest/reference/issues#create-an-issue await octokit.request("POST /repos/{owner}/{repo}/issues", { owner: "octocat", repo: "hello-world", title: "Hello, world!", body: "I created this issue using Octokit!", }); ``` The 1st argument is the REST API route as listed in GitHub's API documentation. The 2nd argument is an object with all parameters, independent of whether they are used in the path, query, or body. #### Pagination All REST API endpoints that paginate return the first 30 items by default. If you want to retrieve all items, you can use the pagination API. The pagination API expects the REST API route as first argument, but you can also pass any of the `octokit.rest.*.list*` methods for convenience and better code readability. Example: iterate through all issues in a repository ```js const iterator = octokit.paginate.iterator(octokit.rest.issues.listForRepo, { owner: "octocat", repo: "hello-world", per_page: 100, }); // iterate through each response for await (const { data: issues } of iterator) { for (const issue of issues) { console.log("Issue #%d: %s", issue.number, issue.title); } } ``` Using the [async iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of) is the most memory efficient way to iterate through all items. But you can also retrieve all items in a single call ```js const issues = await octokit.paginate(octokit.rest.issues.listForRepo, { owner: "octocat", repo: "hello-world", per_page: 100, }); ``` #### Media Type formats Media type formats can be set using `mediaType: { format }` on every request. Example: retrieve the raw content of a `package.json` file ```js const { data } = await octokit.rest.repos.getContent({ mediaType: { format: "raw", }, owner: "octocat", repo: "hello-world", path: "package.json", }); console.log("package name: %s", JSON.parse(data).name); ``` Learn more about [Media type formats](https://docs.github.com/en/rest/overview/media-types). #### Request error handling **Standalone module:** [`@octokit/request-error`](https://github.com/octokit/request-error.js/#readme) For request error handling, import `RequestError` and use `try...catch` statement. ```typescript import { RequestError } from "octokit"; ``` ```typescript try { // your code here that sends at least one Octokit request await octokit.request("GET /"); } catch (error) { // Octokit errors are instances of RequestError, so they always have an `error.status` property containing the HTTP response code. if (error instanceof RequestError) { // handle Octokit error // error.message; // Oops // error.status; // 500 // error.request; // { method, url, headers, body } // error.response; // { url, status, headers, data } } else { // handle all other errors throw error; } } ``` ### GraphQL API queries Octokit also supports GitHub's GraphQL API directly -- you can use the same queries shown in the documentation and available in the GraphQL explorer in your calls with `octokit.graphql`. Example: get the login of the authenticated user ```js const { viewer: { login }, } = await octokit.graphql(`{ viewer { login } }`); ``` Variables can be passed as 2nd argument ```js const { lastIssues } = await octokit.graphql( ` query lastIssues($owner: String!, $repo: String!, $num: Int = 3) { repository(owner: $owner, name: $repo) { issues(last: $num) { edges { node { title } } } } } `, { owner: "octokit", repo: "graphql.js", }, ); ``` #### Pagination GitHub's GraphQL API returns a maximum of 100 items. If you want to retrieve all items, you can use the pagination API. Example: get all issues ```js const { allIssues } = await octokit.graphql.paginate( ` query allIssues($owner: String!, $repo: String!, $num: Int = 10, $cursor: String) { repository(owner: $owner, name: $repo) { issues(first: $num, after: $cursor) { edges { node { title } } pageInfo { hasNextPage endCursor } } } } `, { owner: "octokit", repo: "graphql.js", }, ); ``` Learn more about [GitHub's GraphQL Pagination](https://github.com/octokit/plugin-paginate-graphql.js#readme) usage. #### Schema previews Previews can be enabled using the `{mediaType: previews: [] }` option. Example: create a label ```js await octokit.graphql( `mutation createLabel($repositoryId:ID!,name:String!,color:String!) { createLabel(input:{repositoryId:$repositoryId,name:$name}) { label: { id } } }`, { repositoryId: 1, name: "important", color: "cc0000", mediaType: { previews: ["bane"], }, }, ); ``` Learn more about [GitHub's GraphQL schema previews](https://docs.github.com/en/graphql/overview/schema-previews) ## App client The `App` client combines features for GitHub Apps, Webhooks, and OAuth ### GitHub App **Standalone module**: [`@octokit/app`](https://github.com/octokit/app.js/#readme) For integrators, GitHub Apps are a means of authentication and authorization. A GitHub app can be registered on a GitHub user or organization account. A GitHub App registration defines a set of permissions and webhooks events it wants to receive and provides a set of credentials in return. Users can grant access to repositories by installing them. Some API endpoints require the GitHub app to authenticate as itself using a JSON Web Token (JWT). For requests affecting an installation, an installation access token has to be created using the app's credentials and the installation ID. The `App` client takes care of all that for you. Example: Dispatch a repository event in every repository the app is installed on ```js import { App } from "octokit"; const app = new App({ appId, privateKey }); for await (const { octokit, repository } of app.eachRepository.iterator()) { // https://docs.github.com/en/rest/reference/repos#create-a-repository-dispatch-event await octokit.rest.repos.createDispatchEvent({ owner: repository.owner.login, repo: repository.name, event_type: "my_event", client_payload: { foo: "bar", }, }); console.log("Event dispatched for %s", repository.full_name); } ``` Example: Get an `octokit` instance authenticated as an installation ```js const octokit = await app.getInstallationOctokit(123); ``` Learn more about [apps](https://docs.github.com/apps). ### Webhooks **Standalone module**: [`@octokit/webhooks`](https://github.com/octokit/webhooks.js/#readme) When installing an app, events that the app registration requests will be sent as requests to the webhook URL set in the app's registration. Webhook event requests are signed using the webhook secret, which is also part of the app's registration. You must verify that secret before handling the request payload. The `app.webhooks.*` APIs provide methods to receiving, verifying, and handling webhook events. Example: create a comment on new issues ```js import { createServer } from "node:http"; import { App, createNodeMiddleware } from "octokit"; const app = new App({ appId, privateKey, webhooks: { secret }, }); app.webhooks.on("issues.opened", ({ octokit, payload }) => { return octokit.rest.issues.createComment({ owner: payload.repository.owner.login, repo: payload.repository.name, issue_number: payload.issue.number, body: "Hello, World!", }); }); // Your app can now receive webhook events at `/api/github/webhooks` createServer(createNodeMiddleware(app)).listen(3000); ``` For serverless environments, you can explicitly verify and receive an event ```js await app.webhooks.verifyAndReceive({ id: request.headers["x-github-delivery"], name: request.headers["x-github-event"], signature: request.headers["x-hub-signature-256"], payload: request.body, }); ``` Learn more about [GitHub webhooks](https://docs.github.com/webhooks). ### OAuth **Standalone module:** [`@octokit/oauth-app`](https://github.com/octokit/oauth-app.js/#readme) Both OAuth Apps and GitHub Apps support authenticating GitHub users using OAuth, see [Authorizing OAuth Apps](https://docs.github.com/en/developers/apps/authorizing-oauth-apps) and [Identifying and authorizing users for GitHub Apps](https://docs.github.com/en/developers/apps/identifying-and-authorizing-users-for-github-apps). There are some differences: - Only OAuth Apps support scopes. GitHub apps have permissions, and access is granted via installations of the app on repositories. - Only GitHub Apps support expiring user tokens - Only GitHub Apps support creating a scoped token to reduce the permissions and repository access `App` is for GitHub Apps. If you need OAuth App-specific functionality, use [`OAuthApp` instead](https://github.com/octokit/oauth-app.js/). Example: Watch a repository when a user logs in using the OAuth web flow ```js import { createServer } from "node:http"; import { App, createNodeMiddleware } from "octokit"; const app = new App({ oauth: { clientId, clientSecret }, }); app.oauth.on("token.created", async ({ token, octokit }) => { await octokit.rest.activity.setRepoSubscription({ owner: "octocat", repo: "hello-world", subscribed: true, }); }); // Your app can receive the OAuth redirect at /api/github/oauth/callback // Users can initiate the OAuth web flow by opening /api/github/oauth/login createServer(createNodeMiddleware(app)).listen(3000); ``` For serverless environments, you can explicitly exchange the `code` from the OAuth web flow redirect for an access token. `app.oauth.createToken()` returns an authentication object and emits the "token.created" event. ```js const { token } = await app.oauth.createToken({ code: request.query.code, }); ``` Example: create a token using the device flow. ```js const { token } = await app.oauth.createToken({ async onVerification(verification) { await sendMessageToUser( request.body.phoneNumber, `Your code is ${verification.user_code}. Enter it at ${verification.verification_uri}`, ); }, }); ``` Example: Create an OAuth App Server with default scopes ```js import { createServer } from "node:http"; import { OAuthApp, createNodeMiddleware } from "octokit"; const app = new OAuthApp({ clientId, clientSecret, defaultScopes: ["repo", "gist"], }); app.oauth.on("token", async ({ token, octokit }) => { await octokit.rest.gists.create({ description: "I created this gist using Octokit!", public: true, files: { "example.js": `/* some code here */`, }, }); }); // Your app can receive the OAuth redirect at /api/github/oauth/callback // Users can initiate the OAuth web flow by opening /api/oauth/login createServer(createNodeMiddleware(app)).listen(3000); ``` ### App Server After registering your GitHub app, you need to create and deploy a server which can retrieve the webhook event requests from GitHub as well as accept redirects from the OAuth user web flow. The simplest way to create such a server is to use `createNodeMiddleware()`, it works with both, Node's [`http.createServer()`](https://nodejs.org/api/http.html#http_http_createserver_options_requestlistener) method as well as an [Express middleware](https://expressjs.com/en/guide/using-middleware.html). The default routes that the middleware exposes are | Route | Route Description | | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `POST /api/github/webhooks` | Endpoint to receive GitHub Webhook Event requests | | `GET /api/github/oauth/login` | Redirects to GitHub's authorization endpoint. Accepts optional `?state` and `?scopes` query parameters. `?scopes` is a comma-separated list of [supported OAuth scope names](https://docs.github.com/en/developers/apps/scopes-for-oauth-apps#available-scopes) | | `GET /api/github/oauth/callback` | The client's redirect endpoint. This is where the `token` event gets triggered | | `POST /api/github/oauth/token` | Exchange an authorization code for an OAuth Access token. If successful, the `token` event gets triggered. | | `GET /api/github/oauth/token` | Check if token is valid. Must authenticate using token in `Authorization` header. Uses GitHub's [`POST /applications/{client_id}/token`](https://docs.github.com/en/rest/reference/apps#check-a-token) endpoint | | `PATCH /api/github/oauth/token` | Resets a token (invalidates current one, returns new token). Must authenticate using token in `Authorization` header. Uses GitHub's [`PATCH /applications/{client_id}/token`](https://docs.github.com/en/rest/reference/apps#reset-a-token) endpoint. | | `PATCH /api/github/oauth/refresh-token` | Refreshes an expiring token (invalidates current one, returns new access token and refresh token). Must authenticate using token in `Authorization` header. Uses GitHub's [`POST https://github.com/login/oauth/access_token`](https://docs.github.com/en/developers/apps/refreshing-user-to-server-access-tokens#renewing-a-user-token-with-a-refresh-token) OAuth endpoint. | | `POST /api/github/oauth/token/scoped` | Creates a scoped token (does not invalidate the current one). Must authenticate using token in `Authorization` header. Uses GitHub's [`POST /applications/{client_id}/token/scoped`](https://docs.github.com/en/rest/reference/apps#create-a-scoped-access-token) endpoint. | | `DELETE /api/github/oauth/token` | Invalidates current token, basically the equivalent of a logout. Must authenticate using token in `Authorization` header. | | `DELETE /api/github/oauth/grant` | Revokes the user's grant, basically the equivalent of an uninstall. must authenticate using token in `Authorization` header. | Example: create a GitHub server with express ```js import express from "express"; import { App, createNodeMiddleware } from "octokit"; const expressApp = express(); const octokitApp = new App({ appId, privateKey, webhooks: { secret }, oauth: { clientId, clientSecret }, }); expressApp.use(createNodeMiddleware(app)); expressApp.listen(3000, () => { console.log(`Example app listening at http://localhost:3000`); }); ``` ### OAuth for browser apps You must not expose your app's client secret to the user, so you cannot use the `App` constructor. Instead, you have to create a server using the `App` constructor which exposes the `/api/github/oauth/*` routes, through which you can safely implement an OAuth login for apps running in a web browser. If you set `(User) Authorization callback URL` to your own app, than you need to read out the `?code=...&state=...` query parameters, compare the `state` parameter to the value returned by `app.oauthLoginUrl()` earlier to protect against forgery attacks, then exchange the `code` for an OAuth Authorization token. If you run an [app server](#app-server) as described above, the default route to do that is `POST /api/github/oauth/token`. Once you successfully retrieved the token, it is also recommended to remove the `?code=...&state=...` query parameters from the browser's URL ```js const code = new URL(location.href).searchParams.get("code"); if (code) { // remove ?code=... from URL const path = location.pathname + location.search.replace(/\b(code|state)=\w+/g, "").replace(/[?&]+$/, ""); history.replaceState({}, "", path); // exchange the code for a token with your backend. // If you use https://github.com/octokit/oauth-app.js // the exchange would look something like this const response = await fetch("/api/github/oauth/token", { method: "POST", headers: { "content-type": "application/json", }, body: JSON.stringify({ code }), }); const { token } = await response.json(); // `token` is the OAuth Access Token that can be use const { Octokit } = await import("https://esm.sh/@octokit/core"); const octokit = new Octokit({ auth: token }); const { data: { login }, } = await octokit.request("GET /user"); alert("Hi there, " + login); } ``` 🚧 We are working on [`@octokit/auth-oauth-user-client`](https://github.com/octokit/auth-oauth-user-client.js#readme) to provide a simple API for all methods related to OAuth user tokens. The plan is to add an new `GET /api/github/oauth/octokit.js` route to the node middleware which will return a JavaScript file that can be imported into an HTML file. It will make a pre-authenticated `octokit` Instance available. ## Action client **standalone module:** [`@octokit/action`](https://github.com/octokit/action.js#readme) 🚧 A fully fledged `Action` client is pending. You can use [`@actions/github`](https://github.com/actions/toolkit/tree/main/packages/github) for the time being ## LICENSE [MIT](LICENSE) ================================================ FILE: SECURITY.md ================================================ # Security Policy Thanks for helping make GitHub Open Source Software safe for everyone. GitHub takes the security of our software products and services seriously, including all of the open source code repositories managed through our GitHub organizations, such as [Octokit](https://github.com/octokit). Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we want to make sure that your finding gets passed along to the maintainers of this project for remediation. ## Reporting a Vulnerability Since this source is part of [Octokit](https://github.com/octokit) (a GitHub organization) we ask that you follow the guidelines [here](https://github.com/github/.github/blob/master/SECURITY.md#reporting-security-issues) to report anything that you might've found. ================================================ FILE: package.json ================================================ { "name": "octokit", "version": "0.0.0-development", "type": "module", "description": "The all-batteries-included GitHub SDK for Browsers, Node.js, and Deno", "keywords": [ "github", "api", "sdk", "octokit" ], "author": "Gregor Martynus (https://github.com/gr2m)", "repository": "github:octokit/octokit.js", "license": "MIT", "scripts": { "build": "node scripts/build.mjs && tsc -p tsconfig.json", "lint": "prettier --check \"{src,test,scripts}/**/*.{js,json,ts}\" \"*.{md,json}\"", "lint:fix": "prettier --write \"{src,test,scripts}/**/*.{js,json,ts,mjs}\" \"*.{md,json}\"", "pretest": "npm run -s lint", "test": "vitest run --coverage", "test:typescript": "npx tsc --noEmit --declaration --noUnusedLocals --esModuleInterop --module node16 --strict --allowImportingTsExtensions --exactOptionalPropertyTypes test/typescript-validate.ts" }, "dependencies": { "@octokit/app": "^16.1.2", "@octokit/core": "^7.0.6", "@octokit/oauth-app": "^8.0.3", "@octokit/plugin-paginate-graphql": "^6.0.0", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-rest-endpoint-methods": "^17.0.0", "@octokit/plugin-retry": "^8.0.3", "@octokit/plugin-throttling": "^11.0.3", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "@octokit/webhooks": "^14.0.0" }, "devDependencies": { "@octokit/tsconfig": "^4.0.0", "@types/node": "^24.0.0", "@vitest/coverage-v8": "^4.0.0", "esbuild": "^0.27.0", "mockdate": "^3.0.5", "nock": "^14.0.10", "prettier": "3.7.4", "semantic-release-plugin-update-version-in-files": "^2.0.0", "tinyglobby": "^0.2.15", "typescript": "^5.0.0", "vitest": "^4.0.0" }, "release": { "branches": [ "+([0-9]).x", "main", "next", { "name": "beta", "prerelease": true }, { "name": "debug", "prerelease": true } ], "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/github", [ "@semantic-release/npm", { "pkgRoot": "./pkg" } ], [ "semantic-release-plugin-update-version-in-files", { "files": [ "pkg/dist-web/*", "pkg/dist-node/*", "pkg/*/version.*" ] } ] ] }, "engines": { "node": ">= 20" }, "publishConfig": { "provenance": true } } ================================================ FILE: scripts/build.mjs ================================================ // @ts-check import esbuild from "esbuild"; import { copyFile, readFile, writeFile, rm } from "node:fs/promises"; import { glob } from "tinyglobby"; /** * @type {esbuild.BuildOptions} */ const sharedOptions = { sourcemap: "external", sourcesContent: true, minify: false, allowOverwrite: true, packages: "external", platform: "neutral", format: "esm", target: "es2022", }; async function main() { // Start with a clean slate await rm("pkg", { recursive: true, force: true }); // Build the source code for a neutral platform as ESM await esbuild.build({ entryPoints: await glob(["./src/*.ts", "./src/**/*.ts"]), outdir: "pkg/dist-src", bundle: false, ...sharedOptions, sourcemap: false, }); // Remove the types file from the dist-src folder const typeFiles = await glob([ "./pkg/dist-src/**/types.js.map", "./pkg/dist-src/**/types.js", ]); for (const typeFile of typeFiles) { await rm(typeFile); } const entryPoints = ["./pkg/dist-src/index.js"]; // Build an ESM bundle await esbuild.build({ entryPoints, outdir: "pkg/dist-bundle", bundle: true, ...sharedOptions, }); // Copy the README, LICENSE to the pkg folder await copyFile("LICENSE", "pkg/LICENSE"); await copyFile("README.md", "pkg/README.md"); // Handle the package.json let pkg = JSON.parse((await readFile("package.json", "utf8")).toString()); // Remove unnecessary fields from the package.json delete pkg.scripts; delete pkg.prettier; delete pkg.release; delete pkg.jest; await writeFile( "pkg/package.json", JSON.stringify( { ...pkg, files: ["dist-*/**", "bin/**"], types: "./dist-types/index.d.ts", exports: { ".": { types: "./dist-types/index.d.ts", import: "./dist-bundle/index.js", default: "./dist-bundle/index.js", }, }, sideEffects: false, }, null, 2, ), ); } main(); ================================================ FILE: src/app.ts ================================================ import { App as DefaultApp } from "@octokit/app"; import { OAuthApp as DefaultOAuthApp } from "@octokit/oauth-app"; import { Octokit } from "./octokit.js"; export const App = DefaultApp.defaults({ Octokit }); export type App = InstanceType; export const OAuthApp = DefaultOAuthApp.defaults({ Octokit }); export type OAuthApp = InstanceType; export { createNodeMiddleware } from "@octokit/app"; ================================================ FILE: src/index.ts ================================================ export { Octokit, RequestError } from "./octokit.js"; export type { PageInfoForward, PageInfoBackward } from "./octokit.js"; export { App, OAuthApp, createNodeMiddleware } from "./app.js"; ================================================ FILE: src/octokit.ts ================================================ import { Octokit as OctokitCore } from "@octokit/core"; import { paginateRest } from "@octokit/plugin-paginate-rest"; import { paginateGraphQL } from "@octokit/plugin-paginate-graphql"; import { restEndpointMethods } from "@octokit/plugin-rest-endpoint-methods"; import { retry } from "@octokit/plugin-retry"; import { throttling } from "@octokit/plugin-throttling"; import { VERSION } from "./version.js"; import type { EndpointDefaults } from "@octokit/types"; export { RequestError } from "@octokit/request-error"; export type { PageInfoForward, PageInfoBackward, } from "@octokit/plugin-paginate-graphql"; export const Octokit = OctokitCore.plugin( restEndpointMethods, paginateRest, paginateGraphQL, retry, throttling, ).defaults({ userAgent: `octokit.js/${VERSION}`, throttle: { onRateLimit, onSecondaryRateLimit, }, }); export type Octokit = InstanceType; /* v8 ignore next no need to test internals of the throttle plugin -- @preserve */ function onRateLimit( retryAfter: number, options: Required, octokit: InstanceType, ) { octokit.log.warn( `Request quota exhausted for request ${options.method} ${options.url}`, ); if (options.request.retryCount === 0) { // only retries once octokit.log.info(`Retrying after ${retryAfter} seconds!`); return true; } } /* v8 ignore next no need to test internals of the throttle plugin -- @preserve */ function onSecondaryRateLimit( retryAfter: number, options: Required, octokit: InstanceType, ) { octokit.log.warn( `SecondaryRateLimit detected for request ${options.method} ${options.url}`, ); if (options.request.retryCount === 0) { // only retries once octokit.log.info(`Retrying after ${retryAfter} seconds!`); return true; } } ================================================ FILE: src/version.ts ================================================ export const VERSION = "0.0.0-development"; ================================================ FILE: test/app.test.ts ================================================ import { beforeEach, describe, expect, test } from "vitest"; import { createServer } from "node:http"; import nock from "nock"; import MockDate from "mockdate"; import { App, Octokit, createNodeMiddleware } from "../src/index.ts"; const APP_ID = 1; const PRIVATE_KEY = `-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA1c7+9z5Pad7OejecsQ0bu3aozN3tihPmljnnudb9G3HECdnH lWu2/a1gB9JW5TBQ+AVpum9Okx7KfqkfBKL9mcHgSL0yWMdjMfNOqNtrQqKlN4kE p6RD++7sGbzbfZ9arwrlD/HSDAWGdGGJTSOBM6pHehyLmSC3DJoR/CTu0vTGTWXQ rO64Z8tyXQPtVPb/YXrcUhbBp8i72b9Xky0fD6PkEebOy0Ip58XVAn2UPNlNOSPS ye+Qjtius0Md4Nie4+X8kwVI2Qjk3dSm0sw/720KJkdVDmrayeljtKBx6AtNQsSX gzQbeMmiqFFkwrG1+zx6E7H7jqIQ9B6bvWKXGwIDAQABAoIBAD8kBBPL6PPhAqUB K1r1/gycfDkUCQRP4DbZHt+458JlFHm8QL6VstKzkrp8mYDRhffY0WJnYJL98tr4 4tohsDbqFGwmw2mIaHjl24LuWXyyP4xpAGDpl9IcusjXBxLQLp2m4AKXbWpzb0OL Ulrfc1ZooPck2uz7xlMIZOtLlOPjLz2DuejVe24JcwwHzrQWKOfA11R/9e50DVse hnSH/w46Q763y4I0E3BIoUMsolEKzh2ydAAyzkgabGQBUuamZotNfvJoDXeCi1LD 8yNCWyTlYpJZJDDXooBU5EAsCvhN1sSRoaXWrlMSDB7r/E+aQyKua4KONqvmoJuC 21vSKeECgYEA7yW6wBkVoNhgXnk8XSZv3W+Q0xtdVpidJeNGBWnczlZrummt4xw3 xs6zV+rGUDy59yDkKwBKjMMa42Mni7T9Fx8+EKUuhVK3PVQyajoyQqFwT1GORJNz c/eYQ6VYOCSC8OyZmsBM2p+0D4FF2/abwSPMmy0NgyFLCUFVc3OECpkCgYEA5OAm I3wt5s+clg18qS7BKR2DuOFWrzNVcHYXhjx8vOSWV033Oy3yvdUBAhu9A1LUqpwy Ma+unIgxmvmUMQEdyHQMcgBsVs10dR/g2xGjMLcwj6kn+xr3JVIZnbRT50YuPhf+ ns1ScdhP6upo9I0/sRsIuN96Gb65JJx94gQ4k9MCgYBO5V6gA2aMQvZAFLUicgzT u/vGea+oYv7tQfaW0J8E/6PYwwaX93Y7Q3QNXCoCzJX5fsNnoFf36mIThGHGiHY6 y5bZPPWFDI3hUMa1Hu/35XS85kYOP6sGJjf4kTLyirEcNKJUWH7CXY+00cwvTkOC S4Iz64Aas8AilIhRZ1m3eQKBgQCUW1s9azQRxgeZGFrzC3R340LL530aCeta/6FW CQVOJ9nv84DLYohTVqvVowdNDTb+9Epw/JDxtDJ7Y0YU0cVtdxPOHcocJgdUGHrX ZcJjRIt8w8g/s4X6MhKasBYm9s3owALzCuJjGzUKcDHiO2DKu1xXAb0SzRcTzUCn 7daCswKBgQDOYPZ2JGmhibqKjjLFm0qzpcQ6RPvPK1/7g0NInmjPMebP0K6eSPx0 9/49J6WTD++EajN7FhktUSYxukdWaCocAQJTDNYP0K88G4rtC2IYy5JFn9SWz5oh x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== -----END RSA PRIVATE KEY-----`; const CLIENT_ID = "lv1.1234567890abcdef"; const CLIENT_SECRET = "1234567890abcdef1234567890abcdef12345678"; const WEBHOOK_SECRET = "secret"; // see https://runkit.com/gr2m/reproducable-jwt const BEARER = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOi0zMCwiZXhwIjo1NzAsImlzcyI6MX0.q3foRa78U3WegM5PrWLEh5N0bH1SD62OqW66ZYzArp95JBNiCbo8KAlGtiRENCIfBZT9ibDUWy82cI4g3F09mdTq3bD1xLavIfmTksIQCz5EymTWR5v6gL14LSmQdWY9lSqkgUG0XCFljWUglEP39H4yeHbFgdjvAYg3ifDS12z9oQz2ACdSpvxPiTuCC804HkPVw8Qoy0OSXvCkFU70l7VXCVUxnuhHnk8-oCGcKUspmeP6UdDnXk-Aus-eGwDfJbU2WritxxaXw6B4a3flTPojkYLSkPBr6Pi0H2-mBsW_Nvs0aLPVLKobQd4gqTkosX3967DoAG8luUMhrnxe8Q"; describe("App", () => { let app: InstanceType; const mock = nock("https://api.github.com"); beforeEach(() => { MockDate.set(0); nock.cleanAll(); app = new App({ appId: APP_ID, privateKey: PRIVATE_KEY, oauth: { clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, }, webhooks: { secret: WEBHOOK_SECRET, }, Octokit: Octokit.defaults({ throttle: { enabled: false }, }), }); }); test("Readme example: `app.eachRepository.iterator`", async () => { mock .get("/app/installations", undefined, { reqheaders: { authorization: `bearer ${BEARER}` }, }) .reply(200, [{ id: 123 }]); mock .post("/app/installations/123/access_tokens", undefined, { reqheaders: { authorization: `bearer ${BEARER}` }, }) .reply(200, { token: "secret123", expires_at: "1970-01-01T01:00:00.000Z", permissions: { metadata: "read", }, repository_selection: "all", }); mock.get("/installation/repositories").reply(200, { total_count: 1, repositories: [ { owner: { login: "octokit" }, name: "octokit.js", full_name: "octokit/octokit.js", }, ], }); mock .post("/repos/octokit/octokit.js/dispatches", { event_type: "my_event", client_payload: { foo: "bar" }, }) .reply(204); for await (const { octokit, repository } of app.eachRepository.iterator()) { // https://docs.github.com/en/rest/reference/repos#create-a-repository-dispatch-event await octokit.request("POST /repos/{owner}/{repo}/dispatches", { owner: repository.owner.login, repo: repository.name, event_type: "my_event", client_payload: { foo: "bar", }, }); expect(repository.full_name).toEqual("octokit/octokit.js"); } expect(mock.isDone()).toBe(true); }); test("README example: app.getInstallationOctokit", async () => { mock .post("/app/installations/123/access_tokens", undefined, { reqheaders: { authorization: `bearer ${BEARER}` }, }) .reply(200, { token: "secret123", expires_at: "1970-01-01T01:00:00.000Z", permissions: { metadata: "read", }, repository_selection: "all", }); mock .post("/repos/octokit/octokit.js/issues", { title: "Hello, world!" }) .reply(201, { id: 1 }); const octokit = await app.getInstallationOctokit(123); // https://docs.github.com/en/rest/reference/issues#create-an-issue await octokit.request("POST /repos/{owner}/{repo}/issues", { owner: "octokit", repo: "octokit.js", title: "Hello, world!", }); expect(mock.isDone()).toBe(true); }); test("README example: createNodeMiddleware(app)", async () => { expect.assertions(3); mock .post("/app/installations/123/access_tokens", undefined, { reqheaders: { authorization: `bearer ${BEARER}` }, }) .reply(200, { token: "secret123", expires_at: "1970-01-01T01:00:00.000Z", permissions: { metadata: "read", }, repository_selection: "all", }); mock .post("/repos/octokit/octokit.js/issues/1/comments", { body: "Hello, World!", }) .reply(200, { body: 1 }); app.webhooks.on("issues.opened", async ({ octokit, payload }) => { await octokit.rest.issues.createComment({ owner: payload.repository.owner.login, repo: payload.repository.name, issue_number: payload.issue.number, body: "Hello, World!", }); expect(mock.isDone()).toBe(true); }); // Your app can now receive webhook events at `/api/github/webhooks` const server = createServer(createNodeMiddleware(app)).listen(); // @ts-expect-error - port is typed as undefined const port = server.address().port; const issuePayload = JSON.stringify({ repository: { owner: { login: "octokit", }, name: "octokit.js", }, action: "opened", installation: { id: 123 }, issue: { number: 1 }, }); const response = await fetch( `http://localhost:${port}/api/github/webhooks`, { method: "POST", headers: { "content-type": "application/json", "x-github-event": "issues", "x-github-delivery": "1", "x-hub-signature-256": await app.webhooks.sign(issuePayload), }, body: issuePayload, }, ); expect(await response.text()).toEqual("ok\n"); expect(response.status).toEqual(200); server.close(); }); }); ================================================ FILE: test/smoke.test.ts ================================================ import { describe, expect, it } from "vitest"; import { Octokit, App, OAuthApp, RequestError } from "../src/index.ts"; describe("Smoke tests", () => { it("Octokit is a function", () => { expect(Octokit).toBeInstanceOf(Function); expect(() => new Octokit()).not.toThrow(); }); it("Octokit can be used as a type", () => { let octokit: Octokit; octokit = new Octokit(); expect(octokit.rest.repos.get).toBeInstanceOf(Function); }); it("App is a function", () => { expect(App).toBeInstanceOf(Function); expect( () => new App({ appId: 123, privateKey: "private key here", }), ).not.toThrow(); }); it("App can be used as a type", () => { let app: App; app = new App({ appId: 123, privateKey: "private key here", }); expect(app.octokit.request).toBeInstanceOf(Function); }); it("OAuthApp is a function", () => { expect(OAuthApp).toBeInstanceOf(Function); expect( () => new OAuthApp({ clientId: "", clientSecret: "", }), ).not.toThrow(); }); it("OAuthApp can be used as a type", () => { let app: OAuthApp; app = new OAuthApp({ clientId: "", clientSecret: "", }); expect(app.octokit.request).toBeInstanceOf(Function); }); it("RequestError inherits from Error", () => { const error = new RequestError("test", 123, { request: { method: "GET", url: "https://api.github.com/", headers: {}, }, }); expect(error).toBeInstanceOf(RequestError); }); }); ================================================ FILE: test/tsconfig.test.json ================================================ { "extends": "../tsconfig.json", "compilerOptions": { "emitDeclarationOnly": false, "noEmit": true, "verbatimModuleSyntax": false, "allowImportingTsExtensions": true }, "include": ["src/**/*"] } ================================================ FILE: test/typescript-validate.ts ================================================ // ************************************************************ // THIS CODE IS NOT EXECUTED. IT IS JUST FOR TYPECHECKING // ************************************************************ import { App, OAuthApp, Octokit, RequestError } from "../src/index.ts"; function expect(what: T) {} export async function OctokitTest() { const app = new App({ appId: 1, privateKey: "", }); expect(app.octokit); const oauthApp = new OAuthApp({ clientId: "", clientSecret: "", }); expect(oauthApp.octokit); const installationOctokit = await app.getInstallationOctokit(1); const issues = await installationOctokit.paginate( installationOctokit.rest.issues.listForRepo, { owner: "", repo: "", }, ); expect(issues[0].id); const error = new RequestError("test", 123, { request: { method: "GET", url: "https://api.github.com/", headers: {}, }, }); expect(error); } ================================================ FILE: tsconfig.json ================================================ { "extends": "@octokit/tsconfig", "include": ["src/**/*"], "compilerOptions": { "esModuleInterop": true, "declaration": true, "outDir": "pkg/dist-types", "emitDeclarationOnly": true, "sourceMap": true } } ================================================ FILE: vite.config.js ================================================ import { defineConfig } from "vite"; export default defineConfig({ test: { coverage: { include: ["src/**/*.ts"], reporter: ["html"], thresholds: { 100: true, }, }, }, });