├── .nvmrc ├── .gitignore ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── semantic.yml │ ├── test.yml │ └── release.yml ├── .yarnrc.yml ├── .prettierrc.json ├── .gitattributes ├── .releaserc.json ├── tsconfig.json ├── LICENSE ├── package.json ├── src ├── bin.ts └── index.ts ├── README.md └── yarn.lock /.nvmrc: -------------------------------------------------------------------------------- 1 | 22.12 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | .yarn/install-state.gz -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @electron/wg-ecosystem @electron/wg-releases 2 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | yarnPath: .yarn/releases/yarn-4.9.4.cjs 4 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "tabWidth": 2, 4 | "singleQuote": true, 5 | "printWidth": 100, 6 | "parser": "typescript" 7 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Source code and markdown files should always use LF as line ending. 2 | *.json text eol=lf 3 | *.md text eol=lf 4 | *.ts text eol=lf 5 | *.yml text eol=lf 6 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "@semantic-release/commit-analyzer", 4 | "@semantic-release/release-notes-generator", 5 | "@semantic-release/npm", 6 | "@semantic-release/github" 7 | ], 8 | "branches": [ "main" ] 9 | } 10 | 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/node22/tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "outDir": "dist", 6 | "sourceMap": true, 7 | "types": [ 8 | "node" 9 | ], 10 | }, 11 | "include": [ 12 | "src" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.github/workflows/semantic.yml: -------------------------------------------------------------------------------- 1 | name: "Check Semantic Commit" 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | main: 15 | permissions: 16 | pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs 17 | statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR 18 | name: Validate PR Title 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: semantic-pull-request 22 | uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | with: 26 | validateSingleCommit: false 27 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | schedule: 8 | - cron: '0 22 * * 3' 9 | workflow_call: 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | test: 16 | name: Test 17 | strategy: 18 | matrix: 19 | node-version: 20 | - 22.12.x 21 | os: 22 | - macos-latest 23 | - ubuntu-latest 24 | - windows-latest 25 | runs-on: "${{ matrix.os }}" 26 | steps: 27 | - name: Checkout 28 | uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 29 | - name: Setup Node.js 30 | uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 31 | with: 32 | node-version: "${{ matrix.node-version }}" 33 | cache: 'yarn' 34 | - name: Install 35 | run: yarn install --frozen-lockfile 36 | - name: Test 37 | run: yarn test 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Contributors to the Electron project 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | test: 10 | uses: ./.github/workflows/test.yml 11 | 12 | release: 13 | name: Release 14 | runs-on: ubuntu-latest 15 | needs: test 16 | environment: npm-trusted-publisher 17 | permissions: 18 | id-token: write # for publishing releases 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 22 | with: 23 | persist-credentials: false 24 | - name: Setup Node.js 25 | uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 26 | with: 27 | node-version-file: .nvmrc 28 | package-manager-cache: false 29 | - name: Install 30 | run: yarn install --immutable 31 | - name: Get GitHub app token 32 | id: secret-service 33 | uses: electron/secret-service-action@3476425e8b30555aac15b1b7096938e254b0e155 # v1.0.0 34 | - name: Run semantic release 35 | uses: electron/semantic-trusted-release@5eceb399ac8de8863205cf6e34109bce473ba566 # v1.0.1 36 | with: 37 | github-token: ${{ fromJSON(steps.secret-service.outputs.secrets).GITHUB_TOKEN }} 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@electron/github-app-auth", 3 | "version": "0.0.0-development", 4 | "description": "Gets an auth token for a repo via a GitHub app installation", 5 | "type": "module", 6 | "exports": "./dist/index.js", 7 | "author": "Samuel Attard ", 8 | "license": "MIT", 9 | "homepage": "https://github.com/electron/github-app-auth", 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/electron/github-app-auth.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/electron/github-app-auth/issues" 16 | }, 17 | "publishConfig": { 18 | "provenance": true 19 | }, 20 | "engines": { 21 | "node": ">=22.12.0" 22 | }, 23 | "bin": { 24 | "github-app-auth-build": "dist/bin.js" 25 | }, 26 | "scripts": { 27 | "lint": "prettier --check src/**/*.ts", 28 | "lint:fix": "prettier --write src/**/*.ts", 29 | "prepublishOnly": "tsc", 30 | "test": "yarn lint && yarn tsc" 31 | }, 32 | "devDependencies": { 33 | "@octokit/types": "^14.1.0", 34 | "@tsconfig/node22": "^22.0.2", 35 | "@types/node": "^22.18.0", 36 | "prettier": "^3.6.2", 37 | "typescript": "^5.9.2" 38 | }, 39 | "dependencies": { 40 | "@octokit/auth-app": "^8.1.0", 41 | "@octokit/rest": "^22.0.0" 42 | }, 43 | "files": [ 44 | "dist" 45 | ], 46 | "packageManager": "yarn@4.9.4" 47 | } 48 | -------------------------------------------------------------------------------- /src/bin.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import * as fs from 'node:fs'; 4 | 5 | import { 6 | appCredentialsFromString, 7 | bundleAppCredentials, 8 | getTokenForOrg, 9 | getTokenForRepo, 10 | } from './index.js'; 11 | 12 | const args = process.argv; 13 | 14 | function getArg(name: string) { 15 | const prefix = `--${name}=`; 16 | return args.find((arg) => arg.startsWith(prefix))?.substring(prefix.length); 17 | } 18 | 19 | // For getting a token 20 | const creds = getArg('creds'); 21 | const org = getArg('org'); 22 | const owner = getArg('owner'); 23 | const repo = getArg('repo'); 24 | const repoArgs = owner && repo; 25 | 26 | // For generating a creds bundle 27 | const cert = getArg('cert'); 28 | const appId = getArg('app-id'); 29 | 30 | if (creds && ((org && !repoArgs) || (repoArgs && !org))) { 31 | const appCreds = appCredentialsFromString(creds); 32 | 33 | (org ? getTokenForOrg(org, appCreds) : getTokenForRepo({ owner: owner!, name: repo! }, appCreds)) 34 | .then((token) => { 35 | if (token) { 36 | console.log(token); 37 | } else { 38 | console.error('Could not generate token'); 39 | process.exit(1); 40 | } 41 | }) 42 | .catch((err) => { 43 | console.error(err); 44 | process.exit(1); 45 | }); 46 | } else if (cert && appId) { 47 | const privateKey = fs.readFileSync(cert, 'utf8'); 48 | const appIdNumber = parseInt(appId, 10); 49 | 50 | if (isNaN(appIdNumber)) { 51 | console.error('App ID was not a number'); 52 | process.exit(1); 53 | } 54 | 55 | console.log( 56 | bundleAppCredentials({ 57 | appId, 58 | privateKey, 59 | }), 60 | ); 61 | } else { 62 | console.error(`Invalid Usage: 63 | github-app-auth --cert=private.key --app-id=12345 64 | github-app-auth --creds=CREDS_BUNDLE --org=electron 65 | github-app-auth --creds=CREDS_BUNDLE --owner=electron --repo=electron`); 66 | process.exit(1); 67 | } 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @electron/github-app-auth 2 | 3 | > Gets an auth token for a repo via a GitHub app installation 4 | 5 | [![Test](https://github.com/electron/github-app-auth/actions/workflows/test.yml/badge.svg)](https://github.com/electron/github-app-auth/actions/workflows/test.yml) 6 | [![npm version](https://img.shields.io/npm/v/@electron/github-app-auth.svg)](https://npmjs.org/package/@electron/github-app-auth) 7 | 8 | ## Usage 9 | 10 | ### Generating Credentials 11 | 12 | In order to simply credential management `@electron/github-app-auth` contains 13 | a CLI tool to generate a "credential bundle" that contains the requisite 14 | information to generate tokens. You need both a private key for your 15 | application and the application ID. 16 | 17 | * You can find your app's ID on the settings page for your GitHub App. 18 | * To download your app's private key, see [Managing private keys for GitHub Apps](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps). 19 | 20 | ```bash 21 | npx @electron/github-app-auth --cert=my-private.key.pem --app-id=12345 22 | ``` 23 | 24 | This command will output a base64 encoded blob which you should store in your 25 | services secret storage (normally accessed via an environment variable). Below 26 | we will use `MY_GITHUB_APP_CREDS` as the environment variable. 27 | 28 | ### With `@octokit/rest` 29 | 30 | ```typescript 31 | import { appCredentialsFromString, getAuthOptionsForRepo } from '@electron/github-app-auth'; 32 | import { Octokit } from '@octokit/rest'; 33 | 34 | const creds = appCredentialsFromString(process.env.MY_GITHUB_APP_CREDS); 35 | const authOpts = await getAuthOptionsForRepo({ 36 | owner: 'electron', 37 | name: 'electron' 38 | }, creds) 39 | const octo = new Octokit({ 40 | ...authOpts, 41 | }); 42 | 43 | // octo is now a valid octokit instance 44 | ``` 45 | 46 | ### With raw tokens 47 | 48 | ```typescript 49 | import { appCredentialsFromString, getTokenForRepo } from '@electron/github-app-auth'; 50 | import { Octokit } from '@octokit/rest'; 51 | 52 | const creds = appCredentialsFromString(process.env.MY_GITHUB_APP_CREDS); 53 | const token = await getTokenForRepo({ 54 | owner: 'electron', 55 | name: 'electron' 56 | }, creds) 57 | 58 | // token is now a valid github auth token 59 | ``` 60 | 61 | #### With raw tokens on the CLI 62 | 63 | ```bash 64 | gh_token=$(npx @electron/github-app-auth --creds=$MY_GITHUB_APP_CREDS --owner=electron --repo=electron) 65 | ``` 66 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { createAppAuth, InstallationAuthOptions } from '@octokit/auth-app'; 2 | import { Octokit } from '@octokit/rest'; 3 | import { RequestInterface } from '@octokit/types'; 4 | 5 | export interface RepoInfo { 6 | owner: string; 7 | name: string; 8 | } 9 | 10 | export interface AppCredentials { 11 | appId: string; 12 | privateKey: string; 13 | } 14 | 15 | export type AuthNarrowing = Pick< 16 | InstallationAuthOptions, 17 | 'repositoryIds' | 'repositoryNames' | 'permissions' 18 | >; 19 | 20 | export function appCredentialsFromString(str: string): AppCredentials { 21 | return JSON.parse(Buffer.from(str, 'base64').toString('utf-8')) as any as AppCredentials; 22 | } 23 | 24 | export function bundleAppCredentials(appCreds: AppCredentials): string { 25 | return Buffer.from(JSON.stringify(appCreds), 'utf-8').toString('base64'); 26 | } 27 | 28 | export async function getTokenForRepo( 29 | repo: RepoInfo, 30 | appCreds: AppCredentials, 31 | authNarrowing: AuthNarrowing = {}, 32 | ) { 33 | const authOptions = await getAuthOptionsForRepo(repo, appCreds, authNarrowing); 34 | if (!authOptions) return null; 35 | 36 | const { token } = await authOptions.authStrategy(authOptions.auth)(authOptions.auth); 37 | return token as string; 38 | } 39 | 40 | export async function getTokenForOrg( 41 | org: string, 42 | appCreds: AppCredentials, 43 | authNarrowing: AuthNarrowing = {}, 44 | ) { 45 | const authOptions = await getAuthOptionsForOrg(org, appCreds, authNarrowing); 46 | if (!authOptions) return null; 47 | 48 | const { token } = await authOptions.authStrategy(authOptions.auth)(authOptions.auth); 49 | return token as string; 50 | } 51 | 52 | interface OctokitAuthOptions { 53 | auth: object; 54 | authStrategy: Function; 55 | } 56 | 57 | export async function getAuthOptionsForRepo( 58 | repo: RepoInfo, 59 | appCreds: AppCredentials, 60 | authNarrowing: AuthNarrowing = {}, 61 | request?: RequestInterface, 62 | ) { 63 | return await getAuthOptionsForInstallationId( 64 | appCreds, 65 | authNarrowing, 66 | async (octokit) => { 67 | const installation = await octokit.apps.getRepoInstallation({ 68 | owner: repo.owner, 69 | repo: repo.name, 70 | }); 71 | 72 | return installation.data.id; 73 | }, 74 | request, 75 | ); 76 | } 77 | 78 | export async function getAuthOptionsForOrg( 79 | org: string, 80 | appCreds: AppCredentials, 81 | authNarrowing: AuthNarrowing = {}, 82 | request?: RequestInterface, 83 | ) { 84 | return await getAuthOptionsForInstallationId( 85 | appCreds, 86 | authNarrowing, 87 | async (octokit) => { 88 | const installation = await octokit.apps.getOrgInstallation({ 89 | org, 90 | }); 91 | 92 | return installation.data.id; 93 | }, 94 | request, 95 | ); 96 | } 97 | 98 | export async function getAuthOptionsForEnterprise( 99 | enterprise: string, 100 | appCreds: AppCredentials, 101 | authNarrowing: AuthNarrowing = {}, 102 | request?: RequestInterface, 103 | ) { 104 | return await getAuthOptionsForInstallationId( 105 | appCreds, 106 | authNarrowing, 107 | async (octokit) => { 108 | const installations = await octokit.paginate(octokit.apps.listInstallations); 109 | for (const installation of installations) { 110 | if ( 111 | installation.target_type === 'Enterprise' && 112 | installation.account?.slug === enterprise 113 | ) { 114 | return installation.id; 115 | } 116 | } 117 | 118 | throw new Error('Failed to find installation for enterprise'); 119 | }, 120 | request, 121 | ); 122 | } 123 | 124 | async function getAuthOptionsForInstallationId( 125 | appCreds: AppCredentials, 126 | authNarrowing: AuthNarrowing = {}, 127 | installationIdFetcher: (octokit: Octokit) => Promise, 128 | request?: RequestInterface, 129 | ): Promise { 130 | const auth = createAppAuth({ 131 | appId: appCreds.appId, 132 | privateKey: appCreds.privateKey, 133 | request, 134 | }); 135 | const appAuth = await auth({ 136 | type: 'app', 137 | }); 138 | 139 | const octokit = new Octokit({ 140 | auth: appAuth.token, 141 | baseUrl: request?.endpoint.DEFAULTS.baseUrl, 142 | }); 143 | 144 | try { 145 | const installationId = await installationIdFetcher(octokit); 146 | 147 | const strategyOptions: InstallationAuthOptions = { 148 | ...authNarrowing, 149 | type: 'installation', 150 | appId: appCreds.appId, 151 | privateKey: appCreds.privateKey, 152 | installationId, 153 | }; 154 | return { 155 | auth: strategyOptions, 156 | authStrategy: createAppAuth, 157 | }; 158 | } catch (err: any) { 159 | if (err.status !== 404) throw err; 160 | return null; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # This file is generated by running "yarn install" inside your project. 2 | # Manual changes might be lost - proceed with caution! 3 | 4 | __metadata: 5 | version: 8 6 | cacheKey: 10c0 7 | 8 | "@electron/github-app-auth@workspace:.": 9 | version: 0.0.0-use.local 10 | resolution: "@electron/github-app-auth@workspace:." 11 | dependencies: 12 | "@octokit/auth-app": "npm:^8.1.0" 13 | "@octokit/rest": "npm:^22.0.0" 14 | "@octokit/types": "npm:^14.1.0" 15 | "@tsconfig/node22": "npm:^22.0.2" 16 | "@types/node": "npm:^22.18.0" 17 | prettier: "npm:^3.6.2" 18 | typescript: "npm:^5.9.2" 19 | bin: 20 | github-app-auth-build: dist/bin.js 21 | languageName: unknown 22 | linkType: soft 23 | 24 | "@octokit/auth-app@npm:^8.1.0": 25 | version: 8.1.0 26 | resolution: "@octokit/auth-app@npm:8.1.0" 27 | dependencies: 28 | "@octokit/auth-oauth-app": "npm:^9.0.1" 29 | "@octokit/auth-oauth-user": "npm:^6.0.0" 30 | "@octokit/request": "npm:^10.0.2" 31 | "@octokit/request-error": "npm:^7.0.0" 32 | "@octokit/types": "npm:^14.0.0" 33 | toad-cache: "npm:^3.7.0" 34 | universal-github-app-jwt: "npm:^2.2.0" 35 | universal-user-agent: "npm:^7.0.0" 36 | checksum: 10c0/8852c697b04d77ab0aae704e8ee3c6c0ed2810429195f984d2f28833a97170f2d8d9b73f94a50524e2ae93b66841a1e6bc01bb80fd58362d5a40c56d6807a11e 37 | languageName: node 38 | linkType: hard 39 | 40 | "@octokit/auth-oauth-app@npm:^9.0.1": 41 | version: 9.0.1 42 | resolution: "@octokit/auth-oauth-app@npm:9.0.1" 43 | dependencies: 44 | "@octokit/auth-oauth-device": "npm:^8.0.1" 45 | "@octokit/auth-oauth-user": "npm:^6.0.0" 46 | "@octokit/request": "npm:^10.0.2" 47 | "@octokit/types": "npm:^14.0.0" 48 | universal-user-agent: "npm:^7.0.0" 49 | checksum: 10c0/625524f3cef4eae845129463db70d943c8730a992adc365fc1919100d992cb85d4fc988a7b7f16ca4c9637370c3eeeeb0815f087b18e97a509654ab097044cd0 50 | languageName: node 51 | linkType: hard 52 | 53 | "@octokit/auth-oauth-device@npm:^8.0.1": 54 | version: 8.0.1 55 | resolution: "@octokit/auth-oauth-device@npm:8.0.1" 56 | dependencies: 57 | "@octokit/oauth-methods": "npm:^6.0.0" 58 | "@octokit/request": "npm:^10.0.2" 59 | "@octokit/types": "npm:^14.0.0" 60 | universal-user-agent: "npm:^7.0.0" 61 | checksum: 10c0/814e63a2f63d440a8c9b01dff75b71238ee43f509bcb0740ded5a88bb1359dd884e931b9a6c98ec8a29b0f227c4d212442662b0039f7c1f1a9f63b59262b00e9 62 | languageName: node 63 | linkType: hard 64 | 65 | "@octokit/auth-oauth-user@npm:^6.0.0": 66 | version: 6.0.0 67 | resolution: "@octokit/auth-oauth-user@npm:6.0.0" 68 | dependencies: 69 | "@octokit/auth-oauth-device": "npm:^8.0.1" 70 | "@octokit/oauth-methods": "npm:^6.0.0" 71 | "@octokit/request": "npm:^10.0.2" 72 | "@octokit/types": "npm:^14.0.0" 73 | universal-user-agent: "npm:^7.0.0" 74 | checksum: 10c0/fcefb664c809d1070a00bb5c6059d19e1aeb6d33fe89c46f477720b545788069b533be3ded1651d1d384ffd4e7e75435c8b3e44ed3b42aea626873d1ef8758c6 75 | languageName: node 76 | linkType: hard 77 | 78 | "@octokit/auth-token@npm:^6.0.0": 79 | version: 6.0.0 80 | resolution: "@octokit/auth-token@npm:6.0.0" 81 | checksum: 10c0/32ecc904c5f6f4e5d090bfcc679d70318690c0a0b5040cd9a25811ad9dcd44c33f2cf96b6dbee1cd56cf58fde28fb1819c01b58718aa5c971f79c822357cb5c0 82 | languageName: node 83 | linkType: hard 84 | 85 | "@octokit/core@npm:^7.0.2": 86 | version: 7.0.3 87 | resolution: "@octokit/core@npm:7.0.3" 88 | dependencies: 89 | "@octokit/auth-token": "npm:^6.0.0" 90 | "@octokit/graphql": "npm:^9.0.1" 91 | "@octokit/request": "npm:^10.0.2" 92 | "@octokit/request-error": "npm:^7.0.0" 93 | "@octokit/types": "npm:^14.0.0" 94 | before-after-hook: "npm:^4.0.0" 95 | universal-user-agent: "npm:^7.0.0" 96 | checksum: 10c0/51427b4c3337e15b394d60277b673c5628a72d245a23b1a446e4249d15e37983fa01d09f10c8ab281207e024929f4d2f6cc27a4d345ec0ece2df78d42586d846 97 | languageName: node 98 | linkType: hard 99 | 100 | "@octokit/endpoint@npm:^11.0.0": 101 | version: 11.0.0 102 | resolution: "@octokit/endpoint@npm:11.0.0" 103 | dependencies: 104 | "@octokit/types": "npm:^14.0.0" 105 | universal-user-agent: "npm:^7.0.2" 106 | checksum: 10c0/ba929128af5327393fdb3a31f416277ae3036a44566d35955a4eddd484a15b5ddc6abe219a56355f3313c7197d59f4e8bf574a4f0a8680bc1c8725b88433d391 107 | languageName: node 108 | linkType: hard 109 | 110 | "@octokit/graphql@npm:^9.0.1": 111 | version: 9.0.1 112 | resolution: "@octokit/graphql@npm:9.0.1" 113 | dependencies: 114 | "@octokit/request": "npm:^10.0.2" 115 | "@octokit/types": "npm:^14.0.0" 116 | universal-user-agent: "npm:^7.0.0" 117 | checksum: 10c0/d80ec923b7624e8a7c84430a287ff18da3c77058e3166ce8e9a67950af00e88767f85d973b4032fc837b67b72d02b323aff2d8f7eeae1ae463bde1a51ddcb83d 118 | languageName: node 119 | linkType: hard 120 | 121 | "@octokit/oauth-authorization-url@npm:^8.0.0": 122 | version: 8.0.0 123 | resolution: "@octokit/oauth-authorization-url@npm:8.0.0" 124 | checksum: 10c0/ab4964bebd8d076f945a2f3210a8a0a221a408362569d9fc2f49875ad06e594365f5fd871dac08d820793f687bff50237f7acf40d9d39c5f9de7575b6f4bad93 125 | languageName: node 126 | linkType: hard 127 | 128 | "@octokit/oauth-methods@npm:^6.0.0": 129 | version: 6.0.0 130 | resolution: "@octokit/oauth-methods@npm:6.0.0" 131 | dependencies: 132 | "@octokit/oauth-authorization-url": "npm:^8.0.0" 133 | "@octokit/request": "npm:^10.0.2" 134 | "@octokit/request-error": "npm:^7.0.0" 135 | "@octokit/types": "npm:^14.0.0" 136 | checksum: 10c0/2d36706a76c375a2c1fc07948658028e97033cfcba6e07e0ae0a058d13d848288344c5ebf7e8b8712ba580a4f1f8e50934107cd18829315b126d7b09980ea1a7 137 | languageName: node 138 | linkType: hard 139 | 140 | "@octokit/openapi-types@npm:^25.1.0": 141 | version: 25.1.0 142 | resolution: "@octokit/openapi-types@npm:25.1.0" 143 | checksum: 10c0/b5b1293b11c6ec7112c7a2713f8507c2696d5db8902ce893b594080ab0329f5a6fcda1b5ac6fe6eed9425e897f4d03326c1bdf5c337e35d324e7b925e52a2661 144 | languageName: node 145 | linkType: hard 146 | 147 | "@octokit/plugin-paginate-rest@npm:^13.0.1": 148 | version: 13.1.1 149 | resolution: "@octokit/plugin-paginate-rest@npm:13.1.1" 150 | dependencies: 151 | "@octokit/types": "npm:^14.1.0" 152 | peerDependencies: 153 | "@octokit/core": ">=6" 154 | checksum: 10c0/88d80608881df88f8e832856e9279ac1c1af30ced9adb7c847f4d120b4bb308c2ab9d791ffd4c9585759e57a938798b4c3f2f988a389f2d78a61aaaebc36ffa7 155 | languageName: node 156 | linkType: hard 157 | 158 | "@octokit/plugin-request-log@npm:^6.0.0": 159 | version: 6.0.0 160 | resolution: "@octokit/plugin-request-log@npm:6.0.0" 161 | peerDependencies: 162 | "@octokit/core": ">=6" 163 | checksum: 10c0/40e46ad0c77235742d0bf698ab4e17df1ae06e0d7824ffc5867ed71e27de860875adb73d89629b823fe8647459a8f262c26ed1aa6ee374873fa94095f37df0bb 164 | languageName: node 165 | linkType: hard 166 | 167 | "@octokit/plugin-rest-endpoint-methods@npm:^16.0.0": 168 | version: 16.0.0 169 | resolution: "@octokit/plugin-rest-endpoint-methods@npm:16.0.0" 170 | dependencies: 171 | "@octokit/types": "npm:^14.1.0" 172 | peerDependencies: 173 | "@octokit/core": ">=6" 174 | checksum: 10c0/6cfe068dbd550bd5914374e65b89482b9deac29f6c26bf02ab6298e956d95b62fc15a2a49dfc6ff76f5938c6ff7fdfe5b7eccdb7551eaff8b1daf7394bc946cb 175 | languageName: node 176 | linkType: hard 177 | 178 | "@octokit/request-error@npm:^7.0.0": 179 | version: 7.0.0 180 | resolution: "@octokit/request-error@npm:7.0.0" 181 | dependencies: 182 | "@octokit/types": "npm:^14.0.0" 183 | checksum: 10c0/e52bdd832a0187d66b20da5716c374d028f63d824908a9e16cad462754324083839b11cf6956e1d23f6112d3c77f17334ebbd80f49d56840b2b03ed9abef8cb0 184 | languageName: node 185 | linkType: hard 186 | 187 | "@octokit/request@npm:^10.0.2": 188 | version: 10.0.3 189 | resolution: "@octokit/request@npm:10.0.3" 190 | dependencies: 191 | "@octokit/endpoint": "npm:^11.0.0" 192 | "@octokit/request-error": "npm:^7.0.0" 193 | "@octokit/types": "npm:^14.0.0" 194 | fast-content-type-parse: "npm:^3.0.0" 195 | universal-user-agent: "npm:^7.0.2" 196 | checksum: 10c0/2d9b2134390ef3aa9fe0c5e659fe93dd94fbabc4dcc6da6e16998dc84b5bda200e6b7a4e178f567883d0ba99c0ea5a6d095a417d86d76854569196c39d2f9a6d 197 | languageName: node 198 | linkType: hard 199 | 200 | "@octokit/rest@npm:^22.0.0": 201 | version: 22.0.0 202 | resolution: "@octokit/rest@npm:22.0.0" 203 | dependencies: 204 | "@octokit/core": "npm:^7.0.2" 205 | "@octokit/plugin-paginate-rest": "npm:^13.0.1" 206 | "@octokit/plugin-request-log": "npm:^6.0.0" 207 | "@octokit/plugin-rest-endpoint-methods": "npm:^16.0.0" 208 | checksum: 10c0/aea3714301f43fbadb22048045a7aef417cdefa997d1baf0b26860eaa9038fb033f7d4299eab06af57a03433871084cf38144fc5414caf80accce714e76d34e2 209 | languageName: node 210 | linkType: hard 211 | 212 | "@octokit/types@npm:^14.0.0, @octokit/types@npm:^14.1.0": 213 | version: 14.1.0 214 | resolution: "@octokit/types@npm:14.1.0" 215 | dependencies: 216 | "@octokit/openapi-types": "npm:^25.1.0" 217 | checksum: 10c0/4640a6c0a95386be4d015b96c3a906756ea657f7df3c6e706d19fea6bf3ac44fd2991c8c817afe1e670ff9042b85b0e06f7fd373f6bbd47da64208701bb46d5b 218 | languageName: node 219 | linkType: hard 220 | 221 | "@tsconfig/node22@npm:^22.0.2": 222 | version: 22.0.2 223 | resolution: "@tsconfig/node22@npm:22.0.2" 224 | checksum: 10c0/c75e6b9ea86ec2a384adefac0e2f16a6c08202ae5cf6c8c745944396a6931ffb38e742809491c1882d1868c2af1c33744193701779674bfb1e05f6a130045a18 225 | languageName: node 226 | linkType: hard 227 | 228 | "@types/node@npm:^22.18.0": 229 | version: 22.18.0 230 | resolution: "@types/node@npm:22.18.0" 231 | dependencies: 232 | undici-types: "npm:~6.21.0" 233 | checksum: 10c0/02cce4493eee8408e66e76fcad164f33c0600ed0854ad08e5519a76a06402da5b589b278cf71bc975c9e014f2668bdf758bc3be7fed63bdbfd0900495372797c 234 | languageName: node 235 | linkType: hard 236 | 237 | "before-after-hook@npm:^4.0.0": 238 | version: 4.0.0 239 | resolution: "before-after-hook@npm:4.0.0" 240 | checksum: 10c0/9f8ae8d1b06142bcfb9ef6625226b5e50348bb11210f266660eddcf9734e0db6f9afc4cb48397ee3f5ac0a3728f3ae401cdeea88413f7bed748a71db84657be2 241 | languageName: node 242 | linkType: hard 243 | 244 | "fast-content-type-parse@npm:^3.0.0": 245 | version: 3.0.0 246 | resolution: "fast-content-type-parse@npm:3.0.0" 247 | checksum: 10c0/06251880c83b7118af3a5e66e8bcee60d44f48b39396fc60acc2b4630bd5f3e77552b999b5c8e943d45a818854360e5e97164c374ec4b562b4df96a2cdf2e188 248 | languageName: node 249 | linkType: hard 250 | 251 | "prettier@npm:^3.6.2": 252 | version: 3.6.2 253 | resolution: "prettier@npm:3.6.2" 254 | bin: 255 | prettier: bin/prettier.cjs 256 | checksum: 10c0/488cb2f2b99ec13da1e50074912870217c11edaddedeadc649b1244c749d15ba94e846423d062e2c4c9ae683e2d65f754de28889ba06e697ac4f988d44f45812 257 | languageName: node 258 | linkType: hard 259 | 260 | "toad-cache@npm:^3.7.0": 261 | version: 3.7.0 262 | resolution: "toad-cache@npm:3.7.0" 263 | checksum: 10c0/7dae2782ee20b22c9798bb8b71dec7ec6a0091021d2ea9dd6e8afccab6b65b358fdba49a02209fac574499702e2c000660721516c87c2538d1b2c0ba03e8c0c3 264 | languageName: node 265 | linkType: hard 266 | 267 | "typescript@npm:^5.9.2": 268 | version: 5.9.2 269 | resolution: "typescript@npm:5.9.2" 270 | bin: 271 | tsc: bin/tsc 272 | tsserver: bin/tsserver 273 | checksum: 10c0/cd635d50f02d6cf98ed42de2f76289701c1ec587a363369255f01ed15aaf22be0813226bff3c53e99d971f9b540e0b3cc7583dbe05faded49b1b0bed2f638a18 274 | languageName: node 275 | linkType: hard 276 | 277 | "typescript@patch:typescript@npm%3A^5.9.2#optional!builtin": 278 | version: 5.9.2 279 | resolution: "typescript@patch:typescript@npm%3A5.9.2#optional!builtin::version=5.9.2&hash=5786d5" 280 | bin: 281 | tsc: bin/tsc 282 | tsserver: bin/tsserver 283 | checksum: 10c0/34d2a8e23eb8e0d1875072064d5e1d9c102e0bdce56a10a25c0b917b8aa9001a9cf5c225df12497e99da107dc379360bc138163c66b55b95f5b105b50578067e 284 | languageName: node 285 | linkType: hard 286 | 287 | "undici-types@npm:~6.21.0": 288 | version: 6.21.0 289 | resolution: "undici-types@npm:6.21.0" 290 | checksum: 10c0/c01ed51829b10aa72fc3ce64b747f8e74ae9b60eafa19a7b46ef624403508a54c526ffab06a14a26b3120d055e1104d7abe7c9017e83ced038ea5cf52f8d5e04 291 | languageName: node 292 | linkType: hard 293 | 294 | "universal-github-app-jwt@npm:^2.2.0": 295 | version: 2.2.0 296 | resolution: "universal-github-app-jwt@npm:2.2.0" 297 | checksum: 10c0/590a557ef0a675ebafc4813d95459f30a301ce6e9e8f3a91b8a9d79fde09a30a955a145387957b91c9107d9ffb0879838e52edeb3a1366dbece961c44a9917a9 298 | languageName: node 299 | linkType: hard 300 | 301 | "universal-user-agent@npm:^7.0.0, universal-user-agent@npm:^7.0.2": 302 | version: 7.0.2 303 | resolution: "universal-user-agent@npm:7.0.2" 304 | checksum: 10c0/e60517ee929813e6b3ac0ceb3c66deccafadc71341edca160279ff046319c684fd7090a60d63aa61cd34a06c2d2acebeb8c2f8d364244ae7bf8ab788e20cd8c8 305 | languageName: node 306 | linkType: hard 307 | --------------------------------------------------------------------------------