@codraoss/provider-github 0.9.5 → 0.9.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -9
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -35,9 +35,9 @@ declare class GitHubError extends Error {
|
|
|
35
35
|
|
|
36
36
|
declare class GitHubClient {
|
|
37
37
|
private env;
|
|
38
|
-
private readonly installationId
|
|
38
|
+
private readonly installationId?;
|
|
39
39
|
private readonly tracker?;
|
|
40
|
-
constructor(env: AppBindingsConfig, installationId
|
|
40
|
+
constructor(env: AppBindingsConfig, installationId?: string | undefined, tracker?: {
|
|
41
41
|
incrementSubrequests(count?: number): void;
|
|
42
42
|
} | undefined);
|
|
43
43
|
private memoToken;
|
package/dist/index.js
CHANGED
|
@@ -20,9 +20,6 @@ var GitHubError = class extends Error {
|
|
|
20
20
|
this.path = path;
|
|
21
21
|
this.name = "GitHubError";
|
|
22
22
|
}
|
|
23
|
-
status;
|
|
24
|
-
body;
|
|
25
|
-
path;
|
|
26
23
|
};
|
|
27
24
|
async function assertResponseOk(response, path, action) {
|
|
28
25
|
if (!response.ok) {
|
|
@@ -413,23 +410,24 @@ var GitHubClient = class {
|
|
|
413
410
|
this.installationId = installationId;
|
|
414
411
|
this.tracker = tracker;
|
|
415
412
|
}
|
|
416
|
-
env;
|
|
417
|
-
installationId;
|
|
418
|
-
tracker;
|
|
419
413
|
// Scoped per invocation to avoid KV hits & 50-subrequest cap.
|
|
420
414
|
memoToken = null;
|
|
421
415
|
async getInstallationToken() {
|
|
416
|
+
if (!this.installationId) {
|
|
417
|
+
throw new GitHubError(400, "Missing installation ID", "getInstallationToken", "Cannot fetch installation token without an installation ID.");
|
|
418
|
+
}
|
|
419
|
+
const installationId = this.installationId;
|
|
422
420
|
if (this.memoToken?.token && new Date(this.memoToken.expiresAt).getTime() > Date.now() + 6e4) {
|
|
423
421
|
return this.memoToken.token;
|
|
424
422
|
}
|
|
425
|
-
const cached = await readCachedInstallationToken(this.env,
|
|
423
|
+
const cached = await readCachedInstallationToken(this.env, installationId, this.tracker);
|
|
426
424
|
if (cached?.token) {
|
|
427
425
|
this.memoToken = cached;
|
|
428
426
|
return cached.token;
|
|
429
427
|
}
|
|
430
428
|
return withRetry("getInstallationToken", async () => {
|
|
431
|
-
const record = await fetchInstallationToken(this.env,
|
|
432
|
-
await writeCachedInstallationToken(this.env,
|
|
429
|
+
const record = await fetchInstallationToken(this.env, installationId);
|
|
430
|
+
await writeCachedInstallationToken(this.env, installationId, record, this.tracker);
|
|
433
431
|
this.memoToken = record;
|
|
434
432
|
return record.token;
|
|
435
433
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/http.ts","../src/constants.ts","../src/app-auth.ts","../src/diff-fetch.ts","../src/review-post.ts","../src/labels.ts","../src/reactions.ts","../src/service.ts"],"sourcesContent":["import type { AppBindingsConfig } from './service';\nimport { withTimeout } from '@codraoss/core/timeout';\nimport {\n GitHubError,\n assertResponseOk,\n type GitHubRequestContext,\n encodeGitHubContentPath,\n repoApiPath,\n withRetry,\n} from './http';\nimport { GITHUB_TIMEOUT_MS, GITHUB_REPOSITORIES_PER_PAGE, GITHUB_REPOSITORY_PAGE_LIMIT } from './constants';\nimport {\n fetchAppInstallationUrl,\n fetchInstallationToken,\n fetchInstallations,\n readCachedInstallationToken,\n writeCachedInstallationToken,\n} from './app-auth';\nimport { fetchCompareDiff, fetchPullRequestDiff } from './diff-fetch';\nimport { findBotReviewForCommit, postReview } from './review-post';\nimport { addIssueLabels, ensureLabel, listIssueLabels, removeIssueLabel } from './labels';\nimport { addIssueReaction } from './reactions';\nimport type {\n GitHubInstallation,\n GitHubRepository,\n ReviewComment,\n PullRequestRecord,\n InstallationTokenCacheRecord,\n} from './types';\n\n// Mock seam: replaced in tests via vi.mock. Enforces module boundary.\nexport type { GitHubInstallation, GitHubRepository, ReviewComment };\nexport { GitHubError };\n\nexport class GitHubClient {\n constructor(\n private env: AppBindingsConfig,\n private readonly installationId: string,\n private readonly tracker?: { incrementSubrequests(count?: number): void },\n ) {}\n\n // Scoped per invocation to avoid KV hits & 50-subrequest cap.\n private memoToken: InstallationTokenCacheRecord | null = null;\n\n async getInstallationToken(): Promise<string> {\n // Reuse the in-memory token while comfortably unexpired.\n if (this.memoToken?.token && new Date(this.memoToken.expiresAt).getTime() > Date.now() + 60_000) {\n return this.memoToken.token;\n }\n\n const cached = await readCachedInstallationToken(this.env, this.installationId, this.tracker);\n if (cached?.token) {\n this.memoToken = cached;\n return cached.token;\n }\n\n return withRetry('getInstallationToken', async () => {\n const record = await fetchInstallationToken(this.env, this.installationId);\n await writeCachedInstallationToken(this.env, this.installationId, record, this.tracker);\n this.memoToken = record;\n\n return record.token;\n });\n }\n\n static async listInstallations(\n env: AppBindingsConfig,\n ): Promise<GitHubInstallation[]> {\n return fetchInstallations(env);\n }\n\n static async getAppInstallationUrl(\n env: AppBindingsConfig,\n ): Promise<string> {\n return fetchAppInstallationUrl(env);\n }\n\n async listRepositories(): Promise<GitHubRepository[]> {\n return withRetry('listRepositories', async () => {\n const repositories: GitHubRepository[] = [];\n\n for (let page = 1; page <= GITHUB_REPOSITORY_PAGE_LIMIT; page += 1) {\n const response = await this.requestAndCheck(`/installation/repositories?per_page=${GITHUB_REPOSITORIES_PER_PAGE}&page=${page}`);\n const data = (await response.json()) as { repositories: GitHubRepository[] };\n repositories.push(...data.repositories);\n\n if (data.repositories.length < GITHUB_REPOSITORIES_PER_PAGE) {\n return repositories;\n }\n }\n\n throw new Error(\n `GitHub repository listing exceeded ${GITHUB_REPOSITORY_PAGE_LIMIT} pages without a terminating page.`,\n );\n });\n }\n\n private async request(\n path: string,\n init: RequestInit = {},\n accept = 'application/vnd.github+json',\n ): Promise<Response> {\n const token = await this.getInstallationToken();\n\n if (this.tracker) this.tracker.incrementSubrequests(1);\n return withTimeout(`GitHub ${init.method ?? 'GET'} ${path}`, GITHUB_TIMEOUT_MS, (signal) =>\n fetch(`https://api.github.com${path}`, {\n ...init,\n signal,\n headers: {\n Accept: accept,\n Authorization: `Bearer ${token}`,\n 'X-GitHub-Api-Version': '2022-11-28',\n 'User-Agent': this.env.BOT_USERNAME ?? 'codra-bot',\n ...init.headers,\n },\n }),\n );\n }\n\n private async requestAndCheck(\n path: string,\n init: RequestInit = {},\n accept = 'application/vnd.github+json',\n ): Promise<Response> {\n const response = await this.request(path, init, accept);\n await assertResponseOk(response, path, `GitHub API ${init.method ?? 'GET'} ${path}`);\n return response;\n }\n\n // Hands the extracted helpers the authenticated-request surface.\n private ctx(): GitHubRequestContext {\n return {\n request: (path, init, accept) => this.request(path, init, accept),\n requestAndCheck: (path, init, accept) => this.requestAndCheck(path, init, accept),\n };\n }\n\n async graphql<T>(query: string, variables: Record<string, unknown>): Promise<T> {\n return withRetry('graphql', async () => {\n const token = await this.getInstallationToken();\n\n if (this.tracker) this.tracker.incrementSubrequests(1);\n const response = await withTimeout('GitHub GraphQL', GITHUB_TIMEOUT_MS, (signal) =>\n fetch('https://api.github.com/graphql', {\n method: 'POST',\n signal,\n headers: {\n Authorization: `Bearer ${token}`,\n 'User-Agent': this.env.BOT_USERNAME ?? 'codra-bot',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ query, variables }),\n }),\n );\n\n await assertResponseOk(response, '/graphql', 'GitHub GraphQL request');\n\n const payload = (await response.json()) as { data?: T; errors?: Array<{ message: string }> };\n if (payload.errors?.length) {\n throw new GitHubError(\n 422,\n JSON.stringify(payload.errors),\n '/graphql',\n `GitHub GraphQL error: ${payload.errors[0].message}`,\n );\n }\n return payload.data as T;\n });\n }\n\n async getPullRequest(owner: string, repo: string, pullNumber: number) {\n return withRetry(`getPullRequest ${owner}/${repo}#${pullNumber}`, async () => {\n const response = await this.requestAndCheck(`${repoApiPath(owner, repo)}/pulls/${pullNumber}`);\n return (await response.json()) as PullRequestRecord;\n });\n }\n\n async getPullRequestDiff(owner: string, repo: string, pullNumber: number) {\n return fetchPullRequestDiff(this.ctx(), owner, repo, pullNumber);\n }\n\n async getCompareDiff(owner: string, repo: string, base: string, head: string) {\n return fetchCompareDiff(this.ctx(), owner, repo, base, head);\n }\n\n // File content at a specific commit; without `ref`, GitHub answers from the default branch instead.\n // Never retried: a secondary rate limit here would sleep 60-120s, worse than just skipping the context.\n async getRepoFile(owner: string, repo: string, path: string, ref?: string) {\n return withRetry(`getRepoFile ${owner}/${repo}/${path}`, async () => {\n const query = ref ? `?ref=${encodeURIComponent(ref)}` : '';\n const response = await this.request(`${repoApiPath(owner, repo)}/contents/${encodeGitHubContentPath(path)}${query}`);\n if (response.status === 404) return null;\n await assertResponseOk(response, path, 'GitHub repo file fetch');\n\n const data = (await response.json()) as { content?: string; encoding?: string };\n if (!data.content) {\n return null;\n }\n if (data.encoding !== 'base64') return data.content;\n\n // atob alone yields one code unit per byte, mangling non-ASCII source files; decode as UTF-8 instead.\n const binary = atob(data.content.replace(/\\n/g, ''));\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n return new TextDecoder().decode(bytes);\n }, 0);\n }\n\n async createCheckRun(\n owner: string,\n repo: string,\n input: { headSha: string; title: string; summary: string; detailsUrl?: string },\n ) {\n return withRetry(`createCheckRun ${owner}/${repo}`, async () => {\n const response = await this.requestAndCheck(`${repoApiPath(owner, repo)}/check-runs`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n name: 'Codra',\n head_sha: input.headSha,\n status: 'in_progress',\n details_url: input.detailsUrl,\n output: {\n title: input.title,\n summary: input.summary,\n },\n }),\n });\n\n return (await response.json()) as { id: number };\n });\n }\n\n async updateCheckRun(\n owner: string,\n repo: string,\n checkRunId: number,\n input: {\n title: string;\n summary: string;\n status?: 'in_progress' | 'completed';\n conclusion?: 'success' | 'neutral' | 'failure' | 'cancelled';\n },\n ) {\n return withRetry(`updateCheckRun ${owner}/${repo} ${checkRunId}`, async () => {\n await this.requestAndCheck(`${repoApiPath(owner, repo)}/check-runs/${checkRunId}`, {\n method: 'PATCH',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n status: input.status ?? 'in_progress',\n conclusion: input.conclusion,\n completed_at: input.status === 'completed' ? new Date().toISOString() : undefined,\n output: {\n title: input.title,\n summary: input.summary,\n },\n }),\n });\n });\n }\n\n async createReview(\n owner: string,\n repo: string,\n pullNumber: number,\n input: {\n commitSha: string;\n event: 'APPROVE' | 'COMMENT' | 'REQUEST_CHANGES';\n body: string;\n comments: ReviewComment[];\n },\n ) {\n return postReview(this.ctx(), owner, repo, pullNumber, input);\n }\n\n async findBotReviewForCommit(\n owner: string,\n repo: string,\n pullNumber: number,\n commitSha: string,\n botLogin: string,\n ): Promise<{ id: number } | null> {\n return findBotReviewForCommit(this.ctx(), owner, repo, pullNumber, commitSha, botLogin);\n }\n\n async ensureLabel(owner: string, repo: string, name: string, color: string) {\n return ensureLabel(this.ctx(), owner, repo, name, color);\n }\n\n async addIssueLabels(owner: string, repo: string, issueNumber: number, labels: string[]) {\n return addIssueLabels(this.ctx(), owner, repo, issueNumber, labels);\n }\n\n async addIssueReaction(owner: string, repo: string, issueNumber: number, content: '+1') {\n return addIssueReaction(this.ctx(), owner, repo, issueNumber, content);\n }\n\n async listIssueLabels(owner: string, repo: string, issueNumber: number) {\n return listIssueLabels(this.ctx(), owner, repo, issueNumber);\n }\n\n // Case-insensitive removal using stored casing.\n async removeIssueLabelsIfPresent(owner: string, repo: string, issueNumber: number, labels: string[]) {\n const currentLabels = await this.listIssueLabels(owner, repo, issueNumber);\n const currentByLowerName = new Map(currentLabels.map(label => [label.toLowerCase(), label]));\n\n const uniqueLabels = Array.from(new Set(labels.map(label => label.toLowerCase())));\n for (const label of uniqueLabels) {\n const currentLabel = currentByLowerName.get(label);\n if (currentLabel) {\n await this.removeIssueLabel(owner, repo, issueNumber, currentLabel);\n }\n }\n }\n\n async removeIssueLabel(owner: string, repo: string, issueNumber: number, label: string) {\n return removeIssueLabel(this.ctx(), owner, repo, issueNumber, label);\n }\n}\n","import { logger } from '@codraoss/core/logger';\n\nexport class GitHubError extends Error {\n constructor(\n public readonly status: number,\n public readonly body: string,\n public readonly path: string,\n message: string,\n ) {\n super(message);\n this.name = 'GitHubError';\n }\n}\n\nexport async function assertResponseOk(response: Response, path: string, action: string) {\n if (!response.ok) {\n let errText;\n try { errText = await response.text(); } catch { errText = '<unreadable>'; }\n throw new GitHubError(response.status, errText, path, `${action} failed with ${response.status}: ${errText}`);\n }\n}\n\n// 406 too_large beyond 20,000 lines diff cap.\nexport function isDiffTooLargeError(error: unknown): boolean {\n return error instanceof GitHubError && error.status === 406 && /too_large|maximum number of lines/i.test(error.body ?? '');\n}\n\nexport async function withRetry<T>(\n operation: string,\n fn: () => Promise<T>,\n maxRetries = 2,\n): Promise<T> {\n let attempt = 0;\n while (true) {\n try {\n return await fn();\n } catch (error: any) {\n attempt++;\n const isSecondaryRateLimit = error instanceof GitHubError &&\n error.status === 403 &&\n error.body?.toLowerCase().includes('secondary rate limit');\n\n const isRetryable =\n isSecondaryRateLimit ||\n (error instanceof GitHubError && (error.status === 429 || error.status >= 500)) ||\n error.name === 'TimeoutError' ||\n error.message.includes('timeout');\n\n if (!isRetryable || attempt > maxRetries) {\n throw error;\n }\n\n const delay = isSecondaryRateLimit ? Math.pow(2, attempt) * 30000 : Math.pow(2, attempt) * 1000;\n logger.warn(`Retrying GitHub operation ${operation} (attempt ${attempt}/${maxRetries}) in ${delay}ms`, {\n status: error instanceof GitHubError ? error.status : undefined,\n error: error.message,\n });\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n}\n\nexport function installationCacheKey(installationId: string) {\n return `install:${installationId}`;\n}\n\nexport function encodeGitHubContentPath(path: string) {\n return path.split('/').map((segment) => encodeURIComponent(segment)).join('/');\n}\n\nexport function repoApiPath(owner: string, repo: string) {\n return `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`;\n}\n\n// The authenticated-request surface the extracted diff-fetch and review-post helpers need.\n// An implementation detail of GitHubClient, NOT new public API: `request`/`requestAndCheck` stay private on the class, which hands one of these to the free functions.\nexport type GitHubRequestContext = {\n request(path: string, init?: RequestInit, accept?: string): Promise<Response>;\n requestAndCheck(path: string, init?: RequestInit, accept?: string): Promise<Response>;\n};\n","export const GITHUB_TIMEOUT_MS = 30_000;\nexport const GITHUB_APP_INSTALL_URL_CACHE_KEY = 'github:app_installation_url';\nexport const GITHUB_REPOSITORIES_PER_PAGE = 100;\nexport const GITHUB_REPOSITORY_PAGE_LIMIT = 100;\nexport const DIFF_FILES_PER_PAGE = 100;\nexport const MAX_DIFF_FILE_PAGES = 5;\n","import type { AppBindingsConfig } from './service';\nimport { withTimeout } from '@codraoss/core/timeout';\nimport { assertResponseOk, installationCacheKey, withRetry } from './http';\nimport type { GitHubAppRecord, GitHubInstallation, InstallationTokenCacheRecord } from './types';\nimport { GITHUB_TIMEOUT_MS, GITHUB_APP_INSTALL_URL_CACHE_KEY } from './constants';\n\ntype AppAuthEnv = AppBindingsConfig;\n\nfunction pemToArrayBuffer(pem: string) {\n const base64 = pem\n .replace(/-----BEGIN (RSA )?PRIVATE KEY-----/g, '')\n .replace(/-----END (RSA )?PRIVATE KEY-----/g, '')\n // Handle \\n escapes from wrangler secrets.\n .replace(/\\\\n/g, '')\n .replace(/\\s+/g, '');\n\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n\n for (let index = 0; index < binary.length; index += 1) {\n bytes[index] = binary.charCodeAt(index);\n }\n\n return bytes.buffer;\n}\n\nfunction base64UrlEncode(input: string) {\n return btoa(input).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nexport async function createGitHubJwt(appId: string, privateKeyPem: string) {\n const now = Math.floor(Date.now() / 1000);\n const header = base64UrlEncode(JSON.stringify({ alg: 'RS256', typ: 'JWT' }));\n const payload = base64UrlEncode(\n JSON.stringify({\n iat: now - 60,\n exp: now + 9 * 60,\n iss: appId,\n }),\n );\n\n const key = await crypto.subtle.importKey(\n 'pkcs8',\n pemToArrayBuffer(privateKeyPem),\n { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n\n const signature = await crypto.subtle.sign('RSASSA-PKCS1-v1_5', key, new TextEncoder().encode(`${header}.${payload}`));\n const signatureString = btoa(String.fromCharCode(...new Uint8Array(signature)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/g, '');\n\n return `${header}.${payload}.${signatureString}`;\n}\n\n// App-level (JWT) endpoint headers.\nasync function appJwtHeaders(env: AppAuthEnv) {\n const jwt = await createGitHubJwt(env.GITHUB_APP_ID, env.APP_PRIVATE_KEY);\n return {\n Accept: 'application/vnd.github+json',\n Authorization: `Bearer ${jwt}`,\n 'X-GitHub-Api-Version': '2022-11-28',\n 'User-Agent': env.BOT_USERNAME ?? 'codra-bot',\n };\n}\n\nexport function normalizeGitHubAppSlug(slug: string | undefined) {\n const normalized = slug?.trim().replace(/\\[bot\\]$/i, '');\n return normalized || null;\n}\n\nfunction installUrlFromSlug(slug: string) {\n return `https://github.com/apps/${encodeURIComponent(slug)}/installations/new`;\n}\n\nexport async function readCachedInstallationToken(\n env: AppBindingsConfig,\n installationId: string,\n tracker?: { incrementSubrequests(count?: number): void },\n) {\n if (tracker) tracker.incrementSubrequests(1);\n const cached = await env.APP_KV.get(installationCacheKey(installationId), 'json');\n return cached as InstallationTokenCacheRecord | null;\n}\n\nexport async function writeCachedInstallationToken(\n env: AppBindingsConfig,\n installationId: string,\n record: InstallationTokenCacheRecord,\n tracker?: { incrementSubrequests(count?: number): void },\n) {\n const expiresAt = new Date(record.expiresAt).getTime();\n const ttl = Math.max(60, Math.floor((expiresAt - Date.now()) / 1000) - 300);\n if (tracker) tracker.incrementSubrequests(1);\n await env.APP_KV.put(installationCacheKey(installationId), JSON.stringify(record), { expirationTtl: ttl });\n}\n\n// Caller wraps in withRetry, avoid nested retries.\nexport async function fetchInstallationToken(\n env: AppAuthEnv,\n installationId: string,\n): Promise<InstallationTokenCacheRecord> {\n const headers = await appJwtHeaders(env);\n const response = await withTimeout('GitHub installation token', GITHUB_TIMEOUT_MS, (signal) =>\n fetch(`https://api.github.com/app/installations/${installationId}/access_tokens`, {\n method: 'POST',\n signal,\n headers,\n }),\n );\n\n await assertResponseOk(response, '/app/installations/.../access_tokens', 'GitHub installation token request');\n\n const data = (await response.json()) as { token: string; expires_at: string };\n return { token: data.token, expiresAt: data.expires_at };\n}\n\nexport async function fetchInstallations(env: AppAuthEnv): Promise<GitHubInstallation[]> {\n return withRetry('listInstallations', async () => {\n const headers = await appJwtHeaders(env);\n const response = await withTimeout('GitHub list installations', GITHUB_TIMEOUT_MS, (signal) =>\n fetch('https://api.github.com/app/installations', { signal, headers }),\n );\n\n await assertResponseOk(response, '/app/installations', 'GitHub list installations');\n\n return (await response.json()) as GitHubInstallation[];\n });\n}\n\nexport async function fetchAppInstallationUrl(\n env: AppBindingsConfig,\n): Promise<string> {\n const configuredSlug = normalizeGitHubAppSlug(env.GITHUB_APP_SLUG);\n if (configuredSlug) {\n return installUrlFromSlug(configuredSlug);\n }\n\n const cached = await env.APP_KV.get(GITHUB_APP_INSTALL_URL_CACHE_KEY);\n if (cached) {\n return cached;\n }\n\n return withRetry('getAppInstallationUrl', async () => {\n const headers = await appJwtHeaders(env);\n const response = await withTimeout('GitHub app lookup', GITHUB_TIMEOUT_MS, (signal) =>\n fetch('https://api.github.com/app', { signal, headers }),\n );\n\n await assertResponseOk(response, '/app', 'GitHub app lookup');\n\n const app = (await response.json()) as GitHubAppRecord;\n const fallbackSlug = normalizeGitHubAppSlug(app.slug);\n const installUrl = app.html_url\n ? `${app.html_url.replace(/\\/$/, '')}/installations/new`\n : fallbackSlug\n ? installUrlFromSlug(fallbackSlug)\n : null;\n\n if (!installUrl) {\n throw new Error('GitHub app lookup did not return a usable app URL.');\n }\n\n await env.APP_KV.put(GITHUB_APP_INSTALL_URL_CACHE_KEY, installUrl, { expirationTtl: 60 * 60 * 24 });\n return installUrl;\n });\n}\n","import { logger } from '@codraoss/core/logger';\nimport { buildUnifiedDiffFromFiles, type DiffFileEntry } from '@codraoss/core/diff';\nimport { type GitHubRequestContext, isDiffTooLargeError, repoApiPath, withRetry } from './http';\nimport { DIFF_FILES_PER_PAGE, MAX_DIFF_FILE_PAGES } from './constants';\n\n// Internal implementation. Class stays the mockable seam.\n\n// Rebuild diff if >20k lines (406 too_large).\nasync function fetchPullRequestDiffFromFiles(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n pullNumber: number,\n) {\n const files: DiffFileEntry[] = [];\n\n // Bounded budget of ~25 subrequests. 5 pages = 500 files limit.\n for (let page = 1; page <= MAX_DIFF_FILE_PAGES; page++) {\n const pageFiles = await withRetry(`getPullRequestFiles ${owner}/${repo}#${pullNumber} p${page}`, async () => {\n const response = await ctx.requestAndCheck(\n `${repoApiPath(owner, repo)}/pulls/${pullNumber}/files?per_page=${DIFF_FILES_PER_PAGE}&page=${page}`,\n );\n return (await response.json()) as DiffFileEntry[];\n });\n\n files.push(...pageFiles);\n if (pageFiles.length < DIFF_FILES_PER_PAGE) break;\n\n if (page === MAX_DIFF_FILE_PAGES) {\n logger.warn(\n `Stopped rebuilding the diff for ${owner}/${repo}#${pullNumber} at ${files.length} files; later files are not reviewed`,\n );\n }\n }\n\n return buildUnifiedDiffFromFiles(files);\n}\n\nexport async function fetchPullRequestDiff(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n pullNumber: number,\n) {\n try {\n return await withRetry(`getPullRequestDiff ${owner}/${repo}#${pullNumber}`, async () => {\n const response = await ctx.requestAndCheck(\n `${repoApiPath(owner, repo)}/pulls/${pullNumber}`,\n {},\n 'application/vnd.github.v3.diff',\n );\n return response.text();\n });\n } catch (error) {\n if (!isDiffTooLargeError(error)) throw error;\n logger.warn(\n `Diff for ${owner}/${repo}#${pullNumber} exceeds GitHub's 20,000-line media-type cap; rebuilding it from the per-file endpoint`,\n );\n return fetchPullRequestDiffFromFiles(ctx, owner, repo, pullNumber);\n }\n}\n\n// Diff between commits, reconstructs expired KV cache.\nexport async function fetchCompareDiff(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n base: string,\n head: string,\n) {\n const comparePath = `${repoApiPath(owner, repo)}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}`;\n try {\n return await withRetry(`getCompareDiff ${owner}/${repo} ${base}...${head}`, async () => {\n const response = await ctx.requestAndCheck(comparePath, {}, 'application/vnd.github.v3.diff');\n return response.text();\n });\n } catch (error) {\n if (!isDiffTooLargeError(error)) throw error;\n // Best-effort diff rebuild via JSON file list (max 300 files).\n logger.warn(`Compare diff ${owner}/${repo} ${base}...${head} is over the line cap; rebuilding from the JSON file list`);\n return withRetry(`getCompareFiles ${owner}/${repo} ${base}...${head}`, async () => {\n const response = await ctx.requestAndCheck(comparePath);\n const payload = (await response.json()) as { files?: DiffFileEntry[] };\n return buildUnifiedDiffFromFiles(payload.files ?? []);\n });\n }\n}\n","import { logger } from '@codraoss/core/logger';\nimport { assertResponseOk, type GitHubRequestContext, repoApiPath, withRetry } from './http';\nimport type { ReviewComment } from './types';\n\nexport async function postReview(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n pullNumber: number,\n input: {\n commitSha: string;\n event: 'APPROVE' | 'COMMENT' | 'REQUEST_CHANGES';\n body: string;\n comments: ReviewComment[];\n },\n) {\n return withRetry(`createReview ${owner}/${repo}#${pullNumber}`, async () => {\n // Address by `line` + `side`, or legacy `position`.\n const mapped = input.comments.map((comment) => {\n if (typeof comment.line === 'number' && comment.line > 0) {\n return {\n path: comment.path,\n line: comment.line,\n side: comment.side ?? 'RIGHT',\n body: comment.body,\n };\n }\n if (typeof comment.position === 'number' && comment.position > 0) {\n return { path: comment.path, position: comment.position, body: comment.body };\n }\n return null;\n });\n\n // Which of the caller's comments survived mapping; marking a dropped one \"posted\" would suppress it on every future commit unseen.\n let postedIndices = mapped.flatMap((c, index) => (c === null ? [] : [index]));\n\n const comments = mapped.filter((c): c is NonNullable<typeof c> => c !== null);\n const unaddressable = mapped.length - comments.length;\n if (unaddressable > 0) {\n logger.warn('Dropping review comments with no usable line/position', {\n owner,\n repo,\n pullNumber,\n unaddressable,\n total: mapped.length,\n });\n }\n\n const body = {\n commit_id: input.commitSha,\n event: input.event,\n body: input.body,\n comments,\n };\n\n const reviewPath = `${repoApiPath(owner, repo)}/pulls/${pullNumber}/reviews`;\n let response = await ctx.request(reviewPath, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (response.status === 422 && body.comments.length > 0) {\n // A 422 here almost always means a comment pointed at a line outside the diff; log the response text or this failure is invisible.\n const reason = await response.clone().text().catch(() => '<unreadable>');\n logger.warn(`GitHub review creation failed with 422, retrying without inline comments`, {\n owner,\n repo,\n pullNumber,\n droppedComments: body.comments.length,\n reason: reason.slice(0, 500),\n });\n response = await ctx.request(reviewPath, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n commit_id: input.commitSha,\n event: input.event,\n body: input.body,\n comments: [],\n }),\n });\n postedIndices = []; // Summary posts, but no inline comments.\n }\n\n await assertResponseOk(response, reviewPath, 'GitHub review creation');\n\n const review = (await response.json()) as { id: number };\n return { id: review.id, postedIndices };\n });\n}\n\n// Used by finalize to avoid double-posting when an earlier invocation died.\nexport async function findBotReviewForCommit(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n pullNumber: number,\n commitSha: string,\n botLogin: string,\n): Promise<{ id: number } | null> {\n return withRetry(`findBotReviewForCommit ${owner}/${repo}#${pullNumber}`, async () => {\n const response = await ctx.requestAndCheck(\n `${repoApiPath(owner, repo)}/pulls/${pullNumber}/reviews?per_page=100`,\n );\n const reviews = (await response.json()) as Array<{\n id: number;\n commit_id?: string | null;\n user?: { login?: string | null } | null;\n }>;\n const login = botLogin.toLowerCase();\n const match = reviews.find(\n (review) =>\n review.commit_id === commitSha &&\n (review.user?.login ?? '').toLowerCase().startsWith(login),\n );\n return match ? { id: match.id } : null;\n });\n}\n","import { assertResponseOk, type GitHubRequestContext, repoApiPath, withRetry } from './http';\nimport type { GitHubIssueLabel } from './types';\n\nexport async function ensureLabel(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n name: string,\n color: string,\n) {\n return withRetry(`ensureLabel ${owner}/${repo} ${name}`, async () => {\n const listResponse = await ctx.request(`${repoApiPath(owner, repo)}/labels/${encodeURIComponent(name)}`);\n if (listResponse.ok) return;\n \n if (listResponse.status !== 404) {\n await assertResponseOk(listResponse, name, 'GitHub label lookup');\n }\n\n const createResponse = await ctx.request(`${repoApiPath(owner, repo)}/labels`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ name, color }),\n });\n\n // 422: already exists (concurrent job).\n if (!createResponse.ok && createResponse.status !== 422) {\n await assertResponseOk(createResponse, name, 'GitHub label creation');\n }\n });\n}\n\nexport async function addIssueLabels(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n issueNumber: number,\n labels: string[],\n) {\n return withRetry(`addIssueLabels ${owner}/${repo}#${issueNumber}`, async () => {\n await ctx.requestAndCheck(`${repoApiPath(owner, repo)}/issues/${issueNumber}/labels`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ labels }),\n });\n });\n}\n\nexport async function listIssueLabels(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n issueNumber: number,\n) {\n return withRetry(`listIssueLabels ${owner}/${repo}#${issueNumber}`, async () => {\n const response = await ctx.requestAndCheck(`${repoApiPath(owner, repo)}/issues/${issueNumber}/labels?per_page=100`);\n const labels = await response.json();\n if (!Array.isArray(labels)) {\n throw new Error('Expected an array of labels from GitHub API.');\n }\n return labels\n .map((label: GitHubIssueLabel) => label.name)\n .filter((name): name is string => typeof name === 'string' && name.length > 0);\n });\n}\n\nexport async function removeIssueLabel(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n issueNumber: number,\n label: string,\n) {\n return withRetry(`removeIssueLabel ${owner}/${repo}#${issueNumber} ${label}`, async () => {\n const response = await ctx.request(\n `${repoApiPath(owner, repo)}/issues/${issueNumber}/labels/${encodeURIComponent(label)}`,\n {\n method: 'DELETE',\n },\n );\n\n if (!response.ok && response.status !== 404) {\n await assertResponseOk(response, label, 'GitHub label removal');\n }\n });\n}\n","import { assertResponseOk, type GitHubRequestContext, repoApiPath, withRetry } from './http';\n\n/**\n * React to the pull request's opening post -- the author's own comment, which is what a reader sees\n * first. `/issues/{n}/reactions` is the right endpoint: a pull request IS an issue for this purpose,\n * and `/pulls/{n}` has no reactions collection.\n *\n * Idempotent by design at GitHub's end: re-reacting with the same content as the same user returns the\n * existing reaction rather than duplicating it, so a retried finalize is safe.\n */\nexport async function addIssueReaction(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n issueNumber: number,\n content: '+1' | '-1' | 'eyes' | 'rocket' | 'heart',\n) {\n return withRetry(`addIssueReaction ${owner}/${repo}#${issueNumber} ${content}`, async () => {\n const response = await ctx.request(`${repoApiPath(owner, repo)}/issues/${issueNumber}/reactions`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ content }),\n });\n\n // 200 = the reaction already existed, 201 = created. Both are success.\n if (response.status === 200 || response.status === 201) return;\n await assertResponseOk(response, String(issueNumber), 'GitHub reaction');\n });\n}\n","import { GitHubClient } from './client';\nimport type { ReviewComment } from './types';\n\nexport type AppBindingsConfig = {\n APP_KV: { get: (key: string, type?: any) => Promise<any | null>; put: (key: string, value: string, opts?: any) => Promise<void> };\n APP_PRIVATE_KEY: string;\n GITHUB_APP_ID: string;\n BOT_USERNAME?: string;\n GITHUB_APP_SLUG?: string;\n GITHUB_CLIENT_ID?: string;\n GITHUB_CLIENT_SECRET?: string;\n AUTH_CALLBACK_URL?: string;\n};\n\nexport class GitHubService {\n private client: GitHubClient;\n\n constructor(env: AppBindingsConfig, installationId: string, tracker?: { incrementSubrequests(count?: number): void }) {\n this.client = new GitHubClient(env, installationId, tracker);\n }\n\n async getPullRequest(owner: string, repo: string, prNumber: number) {\n return this.client.getPullRequest(owner, repo, prNumber);\n }\n\n async getPullRequestDiff(owner: string, repo: string, prNumber: number) {\n return this.client.getPullRequestDiff(owner, repo, prNumber);\n }\n\n async getCompareDiff(owner: string, repo: string, base: string, head: string) {\n return this.client.getCompareDiff(owner, repo, base, head);\n }\n\n async getRepoFile(owner: string, repo: string, path: string, ref?: string) {\n return this.client.getRepoFile(owner, repo, path, ref);\n }\n\n async createCheckRun(owner: string, repo: string, params: { headSha: string; title: string; summary: string }) {\n return this.client.createCheckRun(owner, repo, params);\n }\n\n async updateCheckRun(owner: string, repo: string, checkRunId: number, params: { title: string; summary: string; status?: 'in_progress' | 'completed'; conclusion?: 'success' | 'neutral' | 'failure' | 'cancelled' }) {\n return this.client.updateCheckRun(owner, repo, checkRunId, params);\n }\n\n async createReview(owner: string, repo: string, prNumber: number, params: { commitSha: string; event: 'APPROVE' | 'COMMENT'; body: string; comments: ReviewComment[] }) {\n return this.client.createReview(owner, repo, prNumber, params);\n }\n\n async findBotReviewForCommit(owner: string, repo: string, prNumber: number, commitSha: string, botLogin: string) {\n return this.client.findBotReviewForCommit(owner, repo, prNumber, commitSha, botLogin);\n }\n\n async ensureLabel(owner: string, repo: string, name: string, color: string) {\n return this.client.ensureLabel(owner, repo, name, color);\n }\n\n async addIssueLabels(owner: string, repo: string, prNumber: number, labels: string[]) {\n return this.client.addIssueLabels(owner, repo, prNumber, labels);\n }\n\n async addIssueReaction(owner: string, repo: string, prNumber: number, content: '+1') {\n return this.client.addIssueReaction(owner, repo, prNumber, content);\n }\n\n async removeIssueLabelsIfPresent(owner: string, repo: string, prNumber: number, labels: string[]) {\n return this.client.removeIssueLabelsIfPresent(owner, repo, prNumber, labels);\n }\n\n async removeIssueLabel(owner: string, repo: string, prNumber: number, label: string) {\n return this.client.removeIssueLabel(owner, repo, prNumber, label);\n }\n}\n"],"mappings":"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","names":["withTimeout","logger","logger","logger","logger","withTimeout"]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/http.ts","../src/constants.ts","../src/app-auth.ts","../src/diff-fetch.ts","../src/review-post.ts","../src/labels.ts","../src/reactions.ts","../src/service.ts"],"sourcesContent":["import type { AppBindingsConfig } from './service';\nimport { withTimeout } from '@codraoss/core/timeout';\nimport {\n GitHubError,\n assertResponseOk,\n type GitHubRequestContext,\n encodeGitHubContentPath,\n repoApiPath,\n withRetry,\n} from './http';\nimport { GITHUB_TIMEOUT_MS, GITHUB_REPOSITORIES_PER_PAGE, GITHUB_REPOSITORY_PAGE_LIMIT } from './constants';\nimport {\n fetchAppInstallationUrl,\n fetchInstallationToken,\n fetchInstallations,\n readCachedInstallationToken,\n writeCachedInstallationToken,\n} from './app-auth';\nimport { fetchCompareDiff, fetchPullRequestDiff } from './diff-fetch';\nimport { findBotReviewForCommit, postReview } from './review-post';\nimport { addIssueLabels, ensureLabel, listIssueLabels, removeIssueLabel } from './labels';\nimport { addIssueReaction } from './reactions';\nimport type {\n GitHubInstallation,\n GitHubRepository,\n ReviewComment,\n PullRequestRecord,\n InstallationTokenCacheRecord,\n} from './types';\n\n// Mock seam: replaced in tests via vi.mock. Enforces module boundary.\nexport type { GitHubInstallation, GitHubRepository, ReviewComment };\nexport { GitHubError };\n\nexport class GitHubClient {\n constructor(\n private env: AppBindingsConfig,\n private readonly installationId?: string,\n private readonly tracker?: { incrementSubrequests(count?: number): void },\n ) {}\n\n // Scoped per invocation to avoid KV hits & 50-subrequest cap.\n private memoToken: InstallationTokenCacheRecord | null = null;\n\n async getInstallationToken(): Promise<string> {\n if (!this.installationId) {\n throw new GitHubError(400, 'Missing installation ID', 'getInstallationToken', 'Cannot fetch installation token without an installation ID.');\n }\n const installationId = this.installationId; // Type narrowed to string here\n\n // Reuse the in-memory token while comfortably unexpired.\n if (this.memoToken?.token && new Date(this.memoToken.expiresAt).getTime() > Date.now() + 60_000) {\n return this.memoToken.token;\n }\n\n const cached = await readCachedInstallationToken(this.env, installationId, this.tracker);\n if (cached?.token) {\n this.memoToken = cached;\n return cached.token;\n }\n\n return withRetry('getInstallationToken', async () => {\n const record = await fetchInstallationToken(this.env, installationId);\n await writeCachedInstallationToken(this.env, installationId, record, this.tracker);\n this.memoToken = record;\n\n return record.token;\n });\n }\n\n static async listInstallations(\n env: AppBindingsConfig,\n ): Promise<GitHubInstallation[]> {\n return fetchInstallations(env);\n }\n\n static async getAppInstallationUrl(\n env: AppBindingsConfig,\n ): Promise<string> {\n return fetchAppInstallationUrl(env);\n }\n\n async listRepositories(): Promise<GitHubRepository[]> {\n return withRetry('listRepositories', async () => {\n const repositories: GitHubRepository[] = [];\n\n for (let page = 1; page <= GITHUB_REPOSITORY_PAGE_LIMIT; page += 1) {\n const response = await this.requestAndCheck(`/installation/repositories?per_page=${GITHUB_REPOSITORIES_PER_PAGE}&page=${page}`);\n const data = (await response.json()) as { repositories: GitHubRepository[] };\n repositories.push(...data.repositories);\n\n if (data.repositories.length < GITHUB_REPOSITORIES_PER_PAGE) {\n return repositories;\n }\n }\n\n throw new Error(\n `GitHub repository listing exceeded ${GITHUB_REPOSITORY_PAGE_LIMIT} pages without a terminating page.`,\n );\n });\n }\n\n private async request(\n path: string,\n init: RequestInit = {},\n accept = 'application/vnd.github+json',\n ): Promise<Response> {\n const token = await this.getInstallationToken();\n\n if (this.tracker) this.tracker.incrementSubrequests(1);\n return withTimeout(`GitHub ${init.method ?? 'GET'} ${path}`, GITHUB_TIMEOUT_MS, (signal) =>\n fetch(`https://api.github.com${path}`, {\n ...init,\n signal,\n headers: {\n Accept: accept,\n Authorization: `Bearer ${token}`,\n 'X-GitHub-Api-Version': '2022-11-28',\n 'User-Agent': this.env.BOT_USERNAME ?? 'codra-bot',\n ...init.headers,\n },\n }),\n );\n }\n\n private async requestAndCheck(\n path: string,\n init: RequestInit = {},\n accept = 'application/vnd.github+json',\n ): Promise<Response> {\n const response = await this.request(path, init, accept);\n await assertResponseOk(response, path, `GitHub API ${init.method ?? 'GET'} ${path}`);\n return response;\n }\n\n // Hands the extracted helpers the authenticated-request surface.\n private ctx(): GitHubRequestContext {\n return {\n request: (path, init, accept) => this.request(path, init, accept),\n requestAndCheck: (path, init, accept) => this.requestAndCheck(path, init, accept),\n };\n }\n\n async graphql<T>(query: string, variables: Record<string, unknown>): Promise<T> {\n return withRetry('graphql', async () => {\n const token = await this.getInstallationToken();\n\n if (this.tracker) this.tracker.incrementSubrequests(1);\n const response = await withTimeout('GitHub GraphQL', GITHUB_TIMEOUT_MS, (signal) =>\n fetch('https://api.github.com/graphql', {\n method: 'POST',\n signal,\n headers: {\n Authorization: `Bearer ${token}`,\n 'User-Agent': this.env.BOT_USERNAME ?? 'codra-bot',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ query, variables }),\n }),\n );\n\n await assertResponseOk(response, '/graphql', 'GitHub GraphQL request');\n\n const payload = (await response.json()) as { data?: T; errors?: Array<{ message: string }> };\n if (payload.errors?.length) {\n throw new GitHubError(\n 422,\n JSON.stringify(payload.errors),\n '/graphql',\n `GitHub GraphQL error: ${payload.errors[0].message}`,\n );\n }\n return payload.data as T;\n });\n }\n\n async getPullRequest(owner: string, repo: string, pullNumber: number) {\n return withRetry(`getPullRequest ${owner}/${repo}#${pullNumber}`, async () => {\n const response = await this.requestAndCheck(`${repoApiPath(owner, repo)}/pulls/${pullNumber}`);\n return (await response.json()) as PullRequestRecord;\n });\n }\n\n async getPullRequestDiff(owner: string, repo: string, pullNumber: number) {\n return fetchPullRequestDiff(this.ctx(), owner, repo, pullNumber);\n }\n\n async getCompareDiff(owner: string, repo: string, base: string, head: string) {\n return fetchCompareDiff(this.ctx(), owner, repo, base, head);\n }\n\n // File content at a specific commit; without `ref`, GitHub answers from the default branch instead.\n // Never retried: a secondary rate limit here would sleep 60-120s, worse than just skipping the context.\n async getRepoFile(owner: string, repo: string, path: string, ref?: string) {\n return withRetry(`getRepoFile ${owner}/${repo}/${path}`, async () => {\n const query = ref ? `?ref=${encodeURIComponent(ref)}` : '';\n const response = await this.request(`${repoApiPath(owner, repo)}/contents/${encodeGitHubContentPath(path)}${query}`);\n if (response.status === 404) return null;\n await assertResponseOk(response, path, 'GitHub repo file fetch');\n\n const data = (await response.json()) as { content?: string; encoding?: string };\n if (!data.content) {\n return null;\n }\n if (data.encoding !== 'base64') return data.content;\n\n // atob alone yields one code unit per byte, mangling non-ASCII source files; decode as UTF-8 instead.\n const binary = atob(data.content.replace(/\\n/g, ''));\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n return new TextDecoder().decode(bytes);\n }, 0);\n }\n\n async createCheckRun(\n owner: string,\n repo: string,\n input: { headSha: string; title: string; summary: string; detailsUrl?: string },\n ) {\n return withRetry(`createCheckRun ${owner}/${repo}`, async () => {\n const response = await this.requestAndCheck(`${repoApiPath(owner, repo)}/check-runs`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n name: 'Codra',\n head_sha: input.headSha,\n status: 'in_progress',\n details_url: input.detailsUrl,\n output: {\n title: input.title,\n summary: input.summary,\n },\n }),\n });\n\n return (await response.json()) as { id: number };\n });\n }\n\n async updateCheckRun(\n owner: string,\n repo: string,\n checkRunId: number,\n input: {\n title: string;\n summary: string;\n status?: 'in_progress' | 'completed';\n conclusion?: 'success' | 'neutral' | 'failure' | 'cancelled';\n },\n ) {\n return withRetry(`updateCheckRun ${owner}/${repo} ${checkRunId}`, async () => {\n await this.requestAndCheck(`${repoApiPath(owner, repo)}/check-runs/${checkRunId}`, {\n method: 'PATCH',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n status: input.status ?? 'in_progress',\n conclusion: input.conclusion,\n completed_at: input.status === 'completed' ? new Date().toISOString() : undefined,\n output: {\n title: input.title,\n summary: input.summary,\n },\n }),\n });\n });\n }\n\n async createReview(\n owner: string,\n repo: string,\n pullNumber: number,\n input: {\n commitSha: string;\n event: 'APPROVE' | 'COMMENT' | 'REQUEST_CHANGES';\n body: string;\n comments: ReviewComment[];\n },\n ) {\n return postReview(this.ctx(), owner, repo, pullNumber, input);\n }\n\n async findBotReviewForCommit(\n owner: string,\n repo: string,\n pullNumber: number,\n commitSha: string,\n botLogin: string,\n ): Promise<{ id: number } | null> {\n return findBotReviewForCommit(this.ctx(), owner, repo, pullNumber, commitSha, botLogin);\n }\n\n async ensureLabel(owner: string, repo: string, name: string, color: string) {\n return ensureLabel(this.ctx(), owner, repo, name, color);\n }\n\n async addIssueLabels(owner: string, repo: string, issueNumber: number, labels: string[]) {\n return addIssueLabels(this.ctx(), owner, repo, issueNumber, labels);\n }\n\n async addIssueReaction(owner: string, repo: string, issueNumber: number, content: '+1') {\n return addIssueReaction(this.ctx(), owner, repo, issueNumber, content);\n }\n\n async listIssueLabels(owner: string, repo: string, issueNumber: number) {\n return listIssueLabels(this.ctx(), owner, repo, issueNumber);\n }\n\n // Case-insensitive removal using stored casing.\n async removeIssueLabelsIfPresent(owner: string, repo: string, issueNumber: number, labels: string[]) {\n const currentLabels = await this.listIssueLabels(owner, repo, issueNumber);\n const currentByLowerName = new Map(currentLabels.map(label => [label.toLowerCase(), label]));\n\n const uniqueLabels = Array.from(new Set(labels.map(label => label.toLowerCase())));\n for (const label of uniqueLabels) {\n const currentLabel = currentByLowerName.get(label);\n if (currentLabel) {\n await this.removeIssueLabel(owner, repo, issueNumber, currentLabel);\n }\n }\n }\n\n async removeIssueLabel(owner: string, repo: string, issueNumber: number, label: string) {\n return removeIssueLabel(this.ctx(), owner, repo, issueNumber, label);\n }\n}\n","import { logger } from '@codraoss/core/logger';\n\nexport class GitHubError extends Error {\n constructor(\n public readonly status: number,\n public readonly body: string,\n public readonly path: string,\n message: string,\n ) {\n super(message);\n this.name = 'GitHubError';\n }\n}\n\nexport async function assertResponseOk(response: Response, path: string, action: string) {\n if (!response.ok) {\n let errText;\n try { errText = await response.text(); } catch { errText = '<unreadable>'; }\n throw new GitHubError(response.status, errText, path, `${action} failed with ${response.status}: ${errText}`);\n }\n}\n\n// 406 too_large beyond 20,000 lines diff cap.\nexport function isDiffTooLargeError(error: unknown): boolean {\n return error instanceof GitHubError && error.status === 406 && /too_large|maximum number of lines/i.test(error.body ?? '');\n}\n\nexport async function withRetry<T>(\n operation: string,\n fn: () => Promise<T>,\n maxRetries = 2,\n): Promise<T> {\n let attempt = 0;\n while (true) {\n try {\n return await fn();\n } catch (error: any) {\n attempt++;\n const isSecondaryRateLimit = error instanceof GitHubError &&\n error.status === 403 &&\n error.body?.toLowerCase().includes('secondary rate limit');\n\n const isRetryable =\n isSecondaryRateLimit ||\n (error instanceof GitHubError && (error.status === 429 || error.status >= 500)) ||\n error.name === 'TimeoutError' ||\n error.message.includes('timeout');\n\n if (!isRetryable || attempt > maxRetries) {\n throw error;\n }\n\n const delay = isSecondaryRateLimit ? Math.pow(2, attempt) * 30000 : Math.pow(2, attempt) * 1000;\n logger.warn(`Retrying GitHub operation ${operation} (attempt ${attempt}/${maxRetries}) in ${delay}ms`, {\n status: error instanceof GitHubError ? error.status : undefined,\n error: error.message,\n });\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n}\n\nexport function installationCacheKey(installationId: string) {\n return `install:${installationId}`;\n}\n\nexport function encodeGitHubContentPath(path: string) {\n return path.split('/').map((segment) => encodeURIComponent(segment)).join('/');\n}\n\nexport function repoApiPath(owner: string, repo: string) {\n return `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`;\n}\n\n// The authenticated-request surface the extracted diff-fetch and review-post helpers need.\n// An implementation detail of GitHubClient, NOT new public API: `request`/`requestAndCheck` stay private on the class, which hands one of these to the free functions.\nexport type GitHubRequestContext = {\n request(path: string, init?: RequestInit, accept?: string): Promise<Response>;\n requestAndCheck(path: string, init?: RequestInit, accept?: string): Promise<Response>;\n};\n","export const GITHUB_TIMEOUT_MS = 30_000;\nexport const GITHUB_APP_INSTALL_URL_CACHE_KEY = 'github:app_installation_url';\nexport const GITHUB_REPOSITORIES_PER_PAGE = 100;\nexport const GITHUB_REPOSITORY_PAGE_LIMIT = 100;\nexport const DIFF_FILES_PER_PAGE = 100;\nexport const MAX_DIFF_FILE_PAGES = 5;\n","import type { AppBindingsConfig } from './service';\nimport { withTimeout } from '@codraoss/core/timeout';\nimport { assertResponseOk, installationCacheKey, withRetry } from './http';\nimport type { GitHubAppRecord, GitHubInstallation, InstallationTokenCacheRecord } from './types';\nimport { GITHUB_TIMEOUT_MS, GITHUB_APP_INSTALL_URL_CACHE_KEY } from './constants';\n\ntype AppAuthEnv = AppBindingsConfig;\n\nfunction pemToArrayBuffer(pem: string) {\n const base64 = pem\n .replace(/-----BEGIN (RSA )?PRIVATE KEY-----/g, '')\n .replace(/-----END (RSA )?PRIVATE KEY-----/g, '')\n // Handle \\n escapes from wrangler secrets.\n .replace(/\\\\n/g, '')\n .replace(/\\s+/g, '');\n\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n\n for (let index = 0; index < binary.length; index += 1) {\n bytes[index] = binary.charCodeAt(index);\n }\n\n return bytes.buffer;\n}\n\nfunction base64UrlEncode(input: string) {\n return btoa(input).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nexport async function createGitHubJwt(appId: string, privateKeyPem: string) {\n const now = Math.floor(Date.now() / 1000);\n const header = base64UrlEncode(JSON.stringify({ alg: 'RS256', typ: 'JWT' }));\n const payload = base64UrlEncode(\n JSON.stringify({\n iat: now - 60,\n exp: now + 9 * 60,\n iss: appId,\n }),\n );\n\n const key = await crypto.subtle.importKey(\n 'pkcs8',\n pemToArrayBuffer(privateKeyPem),\n { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n\n const signature = await crypto.subtle.sign('RSASSA-PKCS1-v1_5', key, new TextEncoder().encode(`${header}.${payload}`));\n const signatureString = btoa(String.fromCharCode(...new Uint8Array(signature)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/g, '');\n\n return `${header}.${payload}.${signatureString}`;\n}\n\n// App-level (JWT) endpoint headers.\nasync function appJwtHeaders(env: AppAuthEnv) {\n const jwt = await createGitHubJwt(env.GITHUB_APP_ID, env.APP_PRIVATE_KEY);\n return {\n Accept: 'application/vnd.github+json',\n Authorization: `Bearer ${jwt}`,\n 'X-GitHub-Api-Version': '2022-11-28',\n 'User-Agent': env.BOT_USERNAME ?? 'codra-bot',\n };\n}\n\nexport function normalizeGitHubAppSlug(slug: string | undefined) {\n const normalized = slug?.trim().replace(/\\[bot\\]$/i, '');\n return normalized || null;\n}\n\nfunction installUrlFromSlug(slug: string) {\n return `https://github.com/apps/${encodeURIComponent(slug)}/installations/new`;\n}\n\nexport async function readCachedInstallationToken(\n env: AppBindingsConfig,\n installationId: string,\n tracker?: { incrementSubrequests(count?: number): void },\n) {\n if (tracker) tracker.incrementSubrequests(1);\n const cached = await env.APP_KV.get(installationCacheKey(installationId), 'json');\n return cached as InstallationTokenCacheRecord | null;\n}\n\nexport async function writeCachedInstallationToken(\n env: AppBindingsConfig,\n installationId: string,\n record: InstallationTokenCacheRecord,\n tracker?: { incrementSubrequests(count?: number): void },\n) {\n const expiresAt = new Date(record.expiresAt).getTime();\n const ttl = Math.max(60, Math.floor((expiresAt - Date.now()) / 1000) - 300);\n if (tracker) tracker.incrementSubrequests(1);\n await env.APP_KV.put(installationCacheKey(installationId), JSON.stringify(record), { expirationTtl: ttl });\n}\n\n// Caller wraps in withRetry, avoid nested retries.\nexport async function fetchInstallationToken(\n env: AppAuthEnv,\n installationId: string,\n): Promise<InstallationTokenCacheRecord> {\n const headers = await appJwtHeaders(env);\n const response = await withTimeout('GitHub installation token', GITHUB_TIMEOUT_MS, (signal) =>\n fetch(`https://api.github.com/app/installations/${installationId}/access_tokens`, {\n method: 'POST',\n signal,\n headers,\n }),\n );\n\n await assertResponseOk(response, '/app/installations/.../access_tokens', 'GitHub installation token request');\n\n const data = (await response.json()) as { token: string; expires_at: string };\n return { token: data.token, expiresAt: data.expires_at };\n}\n\nexport async function fetchInstallations(env: AppAuthEnv): Promise<GitHubInstallation[]> {\n return withRetry('listInstallations', async () => {\n const headers = await appJwtHeaders(env);\n const response = await withTimeout('GitHub list installations', GITHUB_TIMEOUT_MS, (signal) =>\n fetch('https://api.github.com/app/installations', { signal, headers }),\n );\n\n await assertResponseOk(response, '/app/installations', 'GitHub list installations');\n\n return (await response.json()) as GitHubInstallation[];\n });\n}\n\nexport async function fetchAppInstallationUrl(\n env: AppBindingsConfig,\n): Promise<string> {\n const configuredSlug = normalizeGitHubAppSlug(env.GITHUB_APP_SLUG);\n if (configuredSlug) {\n return installUrlFromSlug(configuredSlug);\n }\n\n const cached = await env.APP_KV.get(GITHUB_APP_INSTALL_URL_CACHE_KEY);\n if (cached) {\n return cached;\n }\n\n return withRetry('getAppInstallationUrl', async () => {\n const headers = await appJwtHeaders(env);\n const response = await withTimeout('GitHub app lookup', GITHUB_TIMEOUT_MS, (signal) =>\n fetch('https://api.github.com/app', { signal, headers }),\n );\n\n await assertResponseOk(response, '/app', 'GitHub app lookup');\n\n const app = (await response.json()) as GitHubAppRecord;\n const fallbackSlug = normalizeGitHubAppSlug(app.slug);\n const installUrl = app.html_url\n ? `${app.html_url.replace(/\\/$/, '')}/installations/new`\n : fallbackSlug\n ? installUrlFromSlug(fallbackSlug)\n : null;\n\n if (!installUrl) {\n throw new Error('GitHub app lookup did not return a usable app URL.');\n }\n\n await env.APP_KV.put(GITHUB_APP_INSTALL_URL_CACHE_KEY, installUrl, { expirationTtl: 60 * 60 * 24 });\n return installUrl;\n });\n}\n","import { logger } from '@codraoss/core/logger';\nimport { buildUnifiedDiffFromFiles, type DiffFileEntry } from '@codraoss/core/diff';\nimport { type GitHubRequestContext, isDiffTooLargeError, repoApiPath, withRetry } from './http';\nimport { DIFF_FILES_PER_PAGE, MAX_DIFF_FILE_PAGES } from './constants';\n\n// Internal implementation. Class stays the mockable seam.\n\n// Rebuild diff if >20k lines (406 too_large).\nasync function fetchPullRequestDiffFromFiles(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n pullNumber: number,\n) {\n const files: DiffFileEntry[] = [];\n\n // Bounded budget of ~25 subrequests. 5 pages = 500 files limit.\n for (let page = 1; page <= MAX_DIFF_FILE_PAGES; page++) {\n const pageFiles = await withRetry(`getPullRequestFiles ${owner}/${repo}#${pullNumber} p${page}`, async () => {\n const response = await ctx.requestAndCheck(\n `${repoApiPath(owner, repo)}/pulls/${pullNumber}/files?per_page=${DIFF_FILES_PER_PAGE}&page=${page}`,\n );\n return (await response.json()) as DiffFileEntry[];\n });\n\n files.push(...pageFiles);\n if (pageFiles.length < DIFF_FILES_PER_PAGE) break;\n\n if (page === MAX_DIFF_FILE_PAGES) {\n logger.warn(\n `Stopped rebuilding the diff for ${owner}/${repo}#${pullNumber} at ${files.length} files; later files are not reviewed`,\n );\n }\n }\n\n return buildUnifiedDiffFromFiles(files);\n}\n\nexport async function fetchPullRequestDiff(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n pullNumber: number,\n) {\n try {\n return await withRetry(`getPullRequestDiff ${owner}/${repo}#${pullNumber}`, async () => {\n const response = await ctx.requestAndCheck(\n `${repoApiPath(owner, repo)}/pulls/${pullNumber}`,\n {},\n 'application/vnd.github.v3.diff',\n );\n return response.text();\n });\n } catch (error) {\n if (!isDiffTooLargeError(error)) throw error;\n logger.warn(\n `Diff for ${owner}/${repo}#${pullNumber} exceeds GitHub's 20,000-line media-type cap; rebuilding it from the per-file endpoint`,\n );\n return fetchPullRequestDiffFromFiles(ctx, owner, repo, pullNumber);\n }\n}\n\n// Diff between commits, reconstructs expired KV cache.\nexport async function fetchCompareDiff(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n base: string,\n head: string,\n) {\n const comparePath = `${repoApiPath(owner, repo)}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}`;\n try {\n return await withRetry(`getCompareDiff ${owner}/${repo} ${base}...${head}`, async () => {\n const response = await ctx.requestAndCheck(comparePath, {}, 'application/vnd.github.v3.diff');\n return response.text();\n });\n } catch (error) {\n if (!isDiffTooLargeError(error)) throw error;\n // Best-effort diff rebuild via JSON file list (max 300 files).\n logger.warn(`Compare diff ${owner}/${repo} ${base}...${head} is over the line cap; rebuilding from the JSON file list`);\n return withRetry(`getCompareFiles ${owner}/${repo} ${base}...${head}`, async () => {\n const response = await ctx.requestAndCheck(comparePath);\n const payload = (await response.json()) as { files?: DiffFileEntry[] };\n return buildUnifiedDiffFromFiles(payload.files ?? []);\n });\n }\n}\n","import { logger } from '@codraoss/core/logger';\nimport { assertResponseOk, type GitHubRequestContext, repoApiPath, withRetry } from './http';\nimport type { ReviewComment } from './types';\n\nexport async function postReview(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n pullNumber: number,\n input: {\n commitSha: string;\n event: 'APPROVE' | 'COMMENT' | 'REQUEST_CHANGES';\n body: string;\n comments: ReviewComment[];\n },\n) {\n return withRetry(`createReview ${owner}/${repo}#${pullNumber}`, async () => {\n // Address by `line` + `side`, or legacy `position`.\n const mapped = input.comments.map((comment) => {\n if (typeof comment.line === 'number' && comment.line > 0) {\n return {\n path: comment.path,\n line: comment.line,\n side: comment.side ?? 'RIGHT',\n body: comment.body,\n };\n }\n if (typeof comment.position === 'number' && comment.position > 0) {\n return { path: comment.path, position: comment.position, body: comment.body };\n }\n return null;\n });\n\n // Which of the caller's comments survived mapping; marking a dropped one \"posted\" would suppress it on every future commit unseen.\n let postedIndices = mapped.flatMap((c, index) => (c === null ? [] : [index]));\n\n const comments = mapped.filter((c): c is NonNullable<typeof c> => c !== null);\n const unaddressable = mapped.length - comments.length;\n if (unaddressable > 0) {\n logger.warn('Dropping review comments with no usable line/position', {\n owner,\n repo,\n pullNumber,\n unaddressable,\n total: mapped.length,\n });\n }\n\n const body = {\n commit_id: input.commitSha,\n event: input.event,\n body: input.body,\n comments,\n };\n\n const reviewPath = `${repoApiPath(owner, repo)}/pulls/${pullNumber}/reviews`;\n let response = await ctx.request(reviewPath, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (response.status === 422 && body.comments.length > 0) {\n // A 422 here almost always means a comment pointed at a line outside the diff; log the response text or this failure is invisible.\n const reason = await response.clone().text().catch(() => '<unreadable>');\n logger.warn(`GitHub review creation failed with 422, retrying without inline comments`, {\n owner,\n repo,\n pullNumber,\n droppedComments: body.comments.length,\n reason: reason.slice(0, 500),\n });\n response = await ctx.request(reviewPath, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n commit_id: input.commitSha,\n event: input.event,\n body: input.body,\n comments: [],\n }),\n });\n postedIndices = []; // Summary posts, but no inline comments.\n }\n\n await assertResponseOk(response, reviewPath, 'GitHub review creation');\n\n const review = (await response.json()) as { id: number };\n return { id: review.id, postedIndices };\n });\n}\n\n// Used by finalize to avoid double-posting when an earlier invocation died.\nexport async function findBotReviewForCommit(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n pullNumber: number,\n commitSha: string,\n botLogin: string,\n): Promise<{ id: number } | null> {\n return withRetry(`findBotReviewForCommit ${owner}/${repo}#${pullNumber}`, async () => {\n const response = await ctx.requestAndCheck(\n `${repoApiPath(owner, repo)}/pulls/${pullNumber}/reviews?per_page=100`,\n );\n const reviews = (await response.json()) as Array<{\n id: number;\n commit_id?: string | null;\n user?: { login?: string | null } | null;\n }>;\n const login = botLogin.toLowerCase();\n const match = reviews.find(\n (review) =>\n review.commit_id === commitSha &&\n (review.user?.login ?? '').toLowerCase().startsWith(login),\n );\n return match ? { id: match.id } : null;\n });\n}\n","import { assertResponseOk, type GitHubRequestContext, repoApiPath, withRetry } from './http';\nimport type { GitHubIssueLabel } from './types';\n\nexport async function ensureLabel(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n name: string,\n color: string,\n) {\n return withRetry(`ensureLabel ${owner}/${repo} ${name}`, async () => {\n const listResponse = await ctx.request(`${repoApiPath(owner, repo)}/labels/${encodeURIComponent(name)}`);\n if (listResponse.ok) return;\n \n if (listResponse.status !== 404) {\n await assertResponseOk(listResponse, name, 'GitHub label lookup');\n }\n\n const createResponse = await ctx.request(`${repoApiPath(owner, repo)}/labels`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ name, color }),\n });\n\n // 422: already exists (concurrent job).\n if (!createResponse.ok && createResponse.status !== 422) {\n await assertResponseOk(createResponse, name, 'GitHub label creation');\n }\n });\n}\n\nexport async function addIssueLabels(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n issueNumber: number,\n labels: string[],\n) {\n return withRetry(`addIssueLabels ${owner}/${repo}#${issueNumber}`, async () => {\n await ctx.requestAndCheck(`${repoApiPath(owner, repo)}/issues/${issueNumber}/labels`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ labels }),\n });\n });\n}\n\nexport async function listIssueLabels(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n issueNumber: number,\n) {\n return withRetry(`listIssueLabels ${owner}/${repo}#${issueNumber}`, async () => {\n const response = await ctx.requestAndCheck(`${repoApiPath(owner, repo)}/issues/${issueNumber}/labels?per_page=100`);\n const labels = await response.json();\n if (!Array.isArray(labels)) {\n throw new Error('Expected an array of labels from GitHub API.');\n }\n return labels\n .map((label: GitHubIssueLabel) => label.name)\n .filter((name): name is string => typeof name === 'string' && name.length > 0);\n });\n}\n\nexport async function removeIssueLabel(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n issueNumber: number,\n label: string,\n) {\n return withRetry(`removeIssueLabel ${owner}/${repo}#${issueNumber} ${label}`, async () => {\n const response = await ctx.request(\n `${repoApiPath(owner, repo)}/issues/${issueNumber}/labels/${encodeURIComponent(label)}`,\n {\n method: 'DELETE',\n },\n );\n\n if (!response.ok && response.status !== 404) {\n await assertResponseOk(response, label, 'GitHub label removal');\n }\n });\n}\n","import { assertResponseOk, type GitHubRequestContext, repoApiPath, withRetry } from './http';\n\n/**\n * React to the pull request's opening post -- the author's own comment, which is what a reader sees\n * first. `/issues/{n}/reactions` is the right endpoint: a pull request IS an issue for this purpose,\n * and `/pulls/{n}` has no reactions collection.\n *\n * Idempotent by design at GitHub's end: re-reacting with the same content as the same user returns the\n * existing reaction rather than duplicating it, so a retried finalize is safe.\n */\nexport async function addIssueReaction(\n ctx: GitHubRequestContext,\n owner: string,\n repo: string,\n issueNumber: number,\n content: '+1' | '-1' | 'eyes' | 'rocket' | 'heart',\n) {\n return withRetry(`addIssueReaction ${owner}/${repo}#${issueNumber} ${content}`, async () => {\n const response = await ctx.request(`${repoApiPath(owner, repo)}/issues/${issueNumber}/reactions`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ content }),\n });\n\n // 200 = the reaction already existed, 201 = created. Both are success.\n if (response.status === 200 || response.status === 201) return;\n await assertResponseOk(response, String(issueNumber), 'GitHub reaction');\n });\n}\n","import { GitHubClient } from './client';\nimport type { ReviewComment } from './types';\n\nexport type AppBindingsConfig = {\n APP_KV: { get: (key: string, type?: any) => Promise<any | null>; put: (key: string, value: string, opts?: any) => Promise<void> };\n APP_PRIVATE_KEY: string;\n GITHUB_APP_ID: string;\n BOT_USERNAME?: string;\n GITHUB_APP_SLUG?: string;\n GITHUB_CLIENT_ID?: string;\n GITHUB_CLIENT_SECRET?: string;\n AUTH_CALLBACK_URL?: string;\n};\n\nexport class GitHubService {\n private client: GitHubClient;\n\n constructor(env: AppBindingsConfig, installationId: string, tracker?: { incrementSubrequests(count?: number): void }) {\n this.client = new GitHubClient(env, installationId, tracker);\n }\n\n async getPullRequest(owner: string, repo: string, prNumber: number) {\n return this.client.getPullRequest(owner, repo, prNumber);\n }\n\n async getPullRequestDiff(owner: string, repo: string, prNumber: number) {\n return this.client.getPullRequestDiff(owner, repo, prNumber);\n }\n\n async getCompareDiff(owner: string, repo: string, base: string, head: string) {\n return this.client.getCompareDiff(owner, repo, base, head);\n }\n\n async getRepoFile(owner: string, repo: string, path: string, ref?: string) {\n return this.client.getRepoFile(owner, repo, path, ref);\n }\n\n async createCheckRun(owner: string, repo: string, params: { headSha: string; title: string; summary: string }) {\n return this.client.createCheckRun(owner, repo, params);\n }\n\n async updateCheckRun(owner: string, repo: string, checkRunId: number, params: { title: string; summary: string; status?: 'in_progress' | 'completed'; conclusion?: 'success' | 'neutral' | 'failure' | 'cancelled' }) {\n return this.client.updateCheckRun(owner, repo, checkRunId, params);\n }\n\n async createReview(owner: string, repo: string, prNumber: number, params: { commitSha: string; event: 'APPROVE' | 'COMMENT'; body: string; comments: ReviewComment[] }) {\n return this.client.createReview(owner, repo, prNumber, params);\n }\n\n async findBotReviewForCommit(owner: string, repo: string, prNumber: number, commitSha: string, botLogin: string) {\n return this.client.findBotReviewForCommit(owner, repo, prNumber, commitSha, botLogin);\n }\n\n async ensureLabel(owner: string, repo: string, name: string, color: string) {\n return this.client.ensureLabel(owner, repo, name, color);\n }\n\n async addIssueLabels(owner: string, repo: string, prNumber: number, labels: string[]) {\n return this.client.addIssueLabels(owner, repo, prNumber, labels);\n }\n\n async addIssueReaction(owner: string, repo: string, prNumber: number, content: '+1') {\n return this.client.addIssueReaction(owner, repo, prNumber, content);\n }\n\n async removeIssueLabelsIfPresent(owner: string, repo: string, prNumber: number, labels: string[]) {\n return this.client.removeIssueLabelsIfPresent(owner, repo, prNumber, labels);\n }\n\n async removeIssueLabel(owner: string, repo: string, prNumber: number, label: string) {\n return this.client.removeIssueLabel(owner, repo, prNumber, label);\n }\n}\n"],"mappings":";;;;;;;;;;AACA,SAAS,eAAAA,oBAAmB;;;ACD5B,SAAS,cAAc;AAEhB,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrC,YACkB,QACA,MACA,MAChB,SACA;AACA,UAAM,OAAO;AALG;AACA;AACA;AAIhB,SAAK,OAAO;AAAA,EACd;AACF;AAEA,eAAsB,iBAAiB,UAAoB,MAAc,QAAgB;AACvF,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI;AACJ,QAAI;AAAE,gBAAU,MAAM,SAAS,KAAK;AAAA,IAAG,QAAQ;AAAE,gBAAU;AAAA,IAAgB;AAC3E,UAAM,IAAI,YAAY,SAAS,QAAQ,SAAS,MAAM,GAAG,MAAM,gBAAgB,SAAS,MAAM,KAAK,OAAO,EAAE;AAAA,EAC9G;AACF;AAGO,SAAS,oBAAoB,OAAyB;AAC3D,SAAO,iBAAiB,eAAe,MAAM,WAAW,OAAO,qCAAqC,KAAK,MAAM,QAAQ,EAAE;AAC3H;AAEA,eAAsB,UACpB,WACA,IACA,aAAa,GACD;AACZ,MAAI,UAAU;AACd,SAAO,MAAM;AACX,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,OAAY;AACnB;AACA,YAAM,uBAAuB,iBAAiB,eAC5C,MAAM,WAAW,OACjB,MAAM,MAAM,YAAY,EAAE,SAAS,sBAAsB;AAE3D,YAAM,cACJ,wBACC,iBAAiB,gBAAgB,MAAM,WAAW,OAAO,MAAM,UAAU,QAC1E,MAAM,SAAS,kBACf,MAAM,QAAQ,SAAS,SAAS;AAElC,UAAI,CAAC,eAAe,UAAU,YAAY;AACxC,cAAM;AAAA,MACR;AAEA,YAAM,QAAQ,uBAAuB,KAAK,IAAI,GAAG,OAAO,IAAI,MAAQ,KAAK,IAAI,GAAG,OAAO,IAAI;AAC3F,aAAO,KAAK,6BAA6B,SAAS,aAAa,OAAO,IAAI,UAAU,QAAQ,KAAK,MAAM;AAAA,QACrG,QAAQ,iBAAiB,cAAc,MAAM,SAAS;AAAA,QACtD,OAAO,MAAM;AAAA,MACf,CAAC;AACD,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,IAC3D;AAAA,EACF;AACF;AAEO,SAAS,qBAAqB,gBAAwB;AAC3D,SAAO,WAAW,cAAc;AAClC;AAEO,SAAS,wBAAwB,MAAc;AACpD,SAAO,KAAK,MAAM,GAAG,EAAE,IAAI,CAAC,YAAY,mBAAmB,OAAO,CAAC,EAAE,KAAK,GAAG;AAC/E;AAEO,SAAS,YAAY,OAAe,MAAc;AACvD,SAAO,UAAU,mBAAmB,KAAK,CAAC,IAAI,mBAAmB,IAAI,CAAC;AACxE;;;ACxEO,IAAM,oBAAoB;AAC1B,IAAM,mCAAmC;AACzC,IAAM,+BAA+B;AACrC,IAAM,+BAA+B;AACrC,IAAM,sBAAsB;AAC5B,IAAM,sBAAsB;;;ACJnC,SAAS,mBAAmB;AAO5B,SAAS,iBAAiB,KAAa;AACrC,QAAM,SAAS,IACZ,QAAQ,uCAAuC,EAAE,EACjD,QAAQ,qCAAqC,EAAE,EAE/C,QAAQ,QAAQ,EAAE,EAClB,QAAQ,QAAQ,EAAE;AAErB,QAAM,SAAS,KAAK,MAAM;AAC1B,QAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;AAE1C,WAAS,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,GAAG;AACrD,UAAM,KAAK,IAAI,OAAO,WAAW,KAAK;AAAA,EACxC;AAEA,SAAO,MAAM;AACf;AAEA,SAAS,gBAAgB,OAAe;AACtC,SAAO,KAAK,KAAK,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAC/E;AAEA,eAAsB,gBAAgB,OAAe,eAAuB;AAC1E,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAM,SAAS,gBAAgB,KAAK,UAAU,EAAE,KAAK,SAAS,KAAK,MAAM,CAAC,CAAC;AAC3E,QAAM,UAAU;AAAA,IACd,KAAK,UAAU;AAAA,MACb,KAAK,MAAM;AAAA,MACX,KAAK,MAAM,IAAI;AAAA,MACf,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AAEA,QAAM,MAAM,MAAM,OAAO,OAAO;AAAA,IAC9B;AAAA,IACA,iBAAiB,aAAa;AAAA,IAC9B,EAAE,MAAM,qBAAqB,MAAM,UAAU;AAAA,IAC7C;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,YAAY,MAAM,OAAO,OAAO,KAAK,qBAAqB,KAAK,IAAI,YAAY,EAAE,OAAO,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC;AACrH,QAAM,kBAAkB,KAAK,OAAO,aAAa,GAAG,IAAI,WAAW,SAAS,CAAC,CAAC,EAC3E,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,GAAG,EAClB,QAAQ,QAAQ,EAAE;AAErB,SAAO,GAAG,MAAM,IAAI,OAAO,IAAI,eAAe;AAChD;AAGA,eAAe,cAAc,KAAiB;AAC5C,QAAM,MAAM,MAAM,gBAAgB,IAAI,eAAe,IAAI,eAAe;AACxE,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,eAAe,UAAU,GAAG;AAAA,IAC5B,wBAAwB;AAAA,IACxB,cAAc,IAAI,gBAAgB;AAAA,EACpC;AACF;AAEO,SAAS,uBAAuB,MAA0B;AAC/D,QAAM,aAAa,MAAM,KAAK,EAAE,QAAQ,aAAa,EAAE;AACvD,SAAO,cAAc;AACvB;AAEA,SAAS,mBAAmB,MAAc;AACxC,SAAO,2BAA2B,mBAAmB,IAAI,CAAC;AAC5D;AAEA,eAAsB,4BACpB,KACA,gBACA,SACA;AACA,MAAI,QAAS,SAAQ,qBAAqB,CAAC;AAC3C,QAAM,SAAS,MAAM,IAAI,OAAO,IAAI,qBAAqB,cAAc,GAAG,MAAM;AAChF,SAAO;AACT;AAEA,eAAsB,6BACpB,KACA,gBACA,QACA,SACA;AACA,QAAM,YAAY,IAAI,KAAK,OAAO,SAAS,EAAE,QAAQ;AACrD,QAAM,MAAM,KAAK,IAAI,IAAI,KAAK,OAAO,YAAY,KAAK,IAAI,KAAK,GAAI,IAAI,GAAG;AAC1E,MAAI,QAAS,SAAQ,qBAAqB,CAAC;AAC3C,QAAM,IAAI,OAAO,IAAI,qBAAqB,cAAc,GAAG,KAAK,UAAU,MAAM,GAAG,EAAE,eAAe,IAAI,CAAC;AAC3G;AAGA,eAAsB,uBACpB,KACA,gBACuC;AACvC,QAAM,UAAU,MAAM,cAAc,GAAG;AACvC,QAAM,WAAW,MAAM;AAAA,IAAY;AAAA,IAA6B;AAAA,IAAmB,CAAC,WAClF,MAAM,4CAA4C,cAAc,kBAAkB;AAAA,MAChF,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,iBAAiB,UAAU,wCAAwC,mCAAmC;AAE5G,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO,EAAE,OAAO,KAAK,OAAO,WAAW,KAAK,WAAW;AACzD;AAEA,eAAsB,mBAAmB,KAAgD;AACvF,SAAO,UAAU,qBAAqB,YAAY;AAChD,UAAM,UAAU,MAAM,cAAc,GAAG;AACvC,UAAM,WAAW,MAAM;AAAA,MAAY;AAAA,MAA6B;AAAA,MAAmB,CAAC,WAClF,MAAM,4CAA4C,EAAE,QAAQ,QAAQ,CAAC;AAAA,IACvE;AAEA,UAAM,iBAAiB,UAAU,sBAAsB,2BAA2B;AAElF,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC9B,CAAC;AACH;AAEA,eAAsB,wBACpB,KACiB;AACjB,QAAM,iBAAiB,uBAAuB,IAAI,eAAe;AACjE,MAAI,gBAAgB;AAClB,WAAO,mBAAmB,cAAc;AAAA,EAC1C;AAEA,QAAM,SAAS,MAAM,IAAI,OAAO,IAAI,gCAAgC;AACpE,MAAI,QAAQ;AACV,WAAO;AAAA,EACT;AAEA,SAAO,UAAU,yBAAyB,YAAY;AACpD,UAAM,UAAU,MAAM,cAAc,GAAG;AACvC,UAAM,WAAW,MAAM;AAAA,MAAY;AAAA,MAAqB;AAAA,MAAmB,CAAC,WAC1E,MAAM,8BAA8B,EAAE,QAAQ,QAAQ,CAAC;AAAA,IACzD;AAEA,UAAM,iBAAiB,UAAU,QAAQ,mBAAmB;AAE5D,UAAM,MAAO,MAAM,SAAS,KAAK;AACjC,UAAM,eAAe,uBAAuB,IAAI,IAAI;AACpD,UAAM,aAAa,IAAI,WACnB,GAAG,IAAI,SAAS,QAAQ,OAAO,EAAE,CAAC,uBAClC,eACE,mBAAmB,YAAY,IAC/B;AAEN,QAAI,CAAC,YAAY;AACf,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AAEA,UAAM,IAAI,OAAO,IAAI,kCAAkC,YAAY,EAAE,eAAe,KAAK,KAAK,GAAG,CAAC;AAClG,WAAO;AAAA,EACT,CAAC;AACH;;;ACzKA,SAAS,UAAAC,eAAc;AACvB,SAAS,iCAAqD;AAO9D,eAAe,8BACb,KACA,OACA,MACA,YACA;AACA,QAAM,QAAyB,CAAC;AAGhC,WAAS,OAAO,GAAG,QAAQ,qBAAqB,QAAQ;AACtD,UAAM,YAAY,MAAM,UAAU,uBAAuB,KAAK,IAAI,IAAI,IAAI,UAAU,KAAK,IAAI,IAAI,YAAY;AAC3G,YAAM,WAAW,MAAM,IAAI;AAAA,QACzB,GAAG,YAAY,OAAO,IAAI,CAAC,UAAU,UAAU,mBAAmB,mBAAmB,SAAS,IAAI;AAAA,MACpG;AACA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B,CAAC;AAED,UAAM,KAAK,GAAG,SAAS;AACvB,QAAI,UAAU,SAAS,oBAAqB;AAE5C,QAAI,SAAS,qBAAqB;AAChC,MAAAC,QAAO;AAAA,QACL,mCAAmC,KAAK,IAAI,IAAI,IAAI,UAAU,OAAO,MAAM,MAAM;AAAA,MACnF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,0BAA0B,KAAK;AACxC;AAEA,eAAsB,qBACpB,KACA,OACA,MACA,YACA;AACA,MAAI;AACF,WAAO,MAAM,UAAU,sBAAsB,KAAK,IAAI,IAAI,IAAI,UAAU,IAAI,YAAY;AACtF,YAAM,WAAW,MAAM,IAAI;AAAA,QACzB,GAAG,YAAY,OAAO,IAAI,CAAC,UAAU,UAAU;AAAA,QAC/C,CAAC;AAAA,QACD;AAAA,MACF;AACA,aAAO,SAAS,KAAK;AAAA,IACvB,CAAC;AAAA,EACH,SAAS,OAAO;AACd,QAAI,CAAC,oBAAoB,KAAK,EAAG,OAAM;AACvC,IAAAA,QAAO;AAAA,MACL,YAAY,KAAK,IAAI,IAAI,IAAI,UAAU;AAAA,IACzC;AACA,WAAO,8BAA8B,KAAK,OAAO,MAAM,UAAU;AAAA,EACnE;AACF;AAGA,eAAsB,iBACpB,KACA,OACA,MACA,MACA,MACA;AACA,QAAM,cAAc,GAAG,YAAY,OAAO,IAAI,CAAC,YAAY,mBAAmB,IAAI,CAAC,MAAM,mBAAmB,IAAI,CAAC;AACjH,MAAI;AACF,WAAO,MAAM,UAAU,kBAAkB,KAAK,IAAI,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,YAAY;AACtF,YAAM,WAAW,MAAM,IAAI,gBAAgB,aAAa,CAAC,GAAG,gCAAgC;AAC5F,aAAO,SAAS,KAAK;AAAA,IACvB,CAAC;AAAA,EACH,SAAS,OAAO;AACd,QAAI,CAAC,oBAAoB,KAAK,EAAG,OAAM;AAEvC,IAAAA,QAAO,KAAK,gBAAgB,KAAK,IAAI,IAAI,IAAI,IAAI,MAAM,IAAI,2DAA2D;AACtH,WAAO,UAAU,mBAAmB,KAAK,IAAI,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,YAAY;AACjF,YAAM,WAAW,MAAM,IAAI,gBAAgB,WAAW;AACtD,YAAM,UAAW,MAAM,SAAS,KAAK;AACrC,aAAO,0BAA0B,QAAQ,SAAS,CAAC,CAAC;AAAA,IACtD,CAAC;AAAA,EACH;AACF;;;ACtFA,SAAS,UAAAC,eAAc;AAIvB,eAAsB,WACpB,KACA,OACA,MACA,YACA,OAMA;AACA,SAAO,UAAU,gBAAgB,KAAK,IAAI,IAAI,IAAI,UAAU,IAAI,YAAY;AAE1E,UAAM,SAAS,MAAM,SAAS,IAAI,CAAC,YAAY;AAC7C,UAAI,OAAO,QAAQ,SAAS,YAAY,QAAQ,OAAO,GAAG;AACxD,eAAO;AAAA,UACL,MAAM,QAAQ;AAAA,UACd,MAAM,QAAQ;AAAA,UACd,MAAM,QAAQ,QAAQ;AAAA,UACtB,MAAM,QAAQ;AAAA,QAChB;AAAA,MACF;AACA,UAAI,OAAO,QAAQ,aAAa,YAAY,QAAQ,WAAW,GAAG;AAChE,eAAO,EAAE,MAAM,QAAQ,MAAM,UAAU,QAAQ,UAAU,MAAM,QAAQ,KAAK;AAAA,MAC9E;AACA,aAAO;AAAA,IACT,CAAC;AAGD,QAAI,gBAAgB,OAAO,QAAQ,CAAC,GAAG,UAAW,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAE;AAE5E,UAAM,WAAW,OAAO,OAAO,CAAC,MAAkC,MAAM,IAAI;AAC5E,UAAM,gBAAgB,OAAO,SAAS,SAAS;AAC/C,QAAI,gBAAgB,GAAG;AACrB,MAAAC,QAAO,KAAK,yDAAyD;AAAA,QACnE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,OAAO;AAAA,MAChB,CAAC;AAAA,IACH;AAEA,UAAM,OAAO;AAAA,MACX,WAAW,MAAM;AAAA,MACjB,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ;AAAA,IACF;AAEA,UAAM,aAAa,GAAG,YAAY,OAAO,IAAI,CAAC,UAAU,UAAU;AAClE,QAAI,WAAW,MAAM,IAAI,QAAQ,YAAY;AAAA,MAC3C,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,SAAS,WAAW,OAAO,KAAK,SAAS,SAAS,GAAG;AAEvD,YAAM,SAAS,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,MAAM,cAAc;AACvE,MAAAA,QAAO,KAAK,4EAA4E;AAAA,QACtF;AAAA,QACA;AAAA,QACA;AAAA,QACA,iBAAiB,KAAK,SAAS;AAAA,QAC/B,QAAQ,OAAO,MAAM,GAAG,GAAG;AAAA,MAC7B,CAAC;AACD,iBAAW,MAAM,IAAI,QAAQ,YAAY;AAAA,QACvC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,WAAW,MAAM;AAAA,UACjB,OAAO,MAAM;AAAA,UACb,MAAM,MAAM;AAAA,UACZ,UAAU,CAAC;AAAA,QACb,CAAC;AAAA,MACH,CAAC;AACD,sBAAgB,CAAC;AAAA,IACnB;AAEA,UAAM,iBAAiB,UAAU,YAAY,wBAAwB;AAErE,UAAM,SAAU,MAAM,SAAS,KAAK;AACpC,WAAO,EAAE,IAAI,OAAO,IAAI,cAAc;AAAA,EACxC,CAAC;AACH;AAGA,eAAsB,uBACpB,KACA,OACA,MACA,YACA,WACA,UACgC;AAChC,SAAO,UAAU,0BAA0B,KAAK,IAAI,IAAI,IAAI,UAAU,IAAI,YAAY;AACpF,UAAM,WAAW,MAAM,IAAI;AAAA,MACzB,GAAG,YAAY,OAAO,IAAI,CAAC,UAAU,UAAU;AAAA,IACjD;AACA,UAAM,UAAW,MAAM,SAAS,KAAK;AAKrC,UAAM,QAAQ,SAAS,YAAY;AACnC,UAAM,QAAQ,QAAQ;AAAA,MACpB,CAAC,WACC,OAAO,cAAc,cACpB,OAAO,MAAM,SAAS,IAAI,YAAY,EAAE,WAAW,KAAK;AAAA,IAC7D;AACA,WAAO,QAAQ,EAAE,IAAI,MAAM,GAAG,IAAI;AAAA,EACpC,CAAC;AACH;;;ACvHA,eAAsB,YACpB,KACA,OACA,MACA,MACA,OACA;AACA,SAAO,UAAU,eAAe,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,YAAY;AACnE,UAAM,eAAe,MAAM,IAAI,QAAQ,GAAG,YAAY,OAAO,IAAI,CAAC,WAAW,mBAAmB,IAAI,CAAC,EAAE;AACvG,QAAI,aAAa,GAAI;AAErB,QAAI,aAAa,WAAW,KAAK;AAC/B,YAAM,iBAAiB,cAAc,MAAM,qBAAqB;AAAA,IAClE;AAEA,UAAM,iBAAiB,MAAM,IAAI,QAAQ,GAAG,YAAY,OAAO,IAAI,CAAC,WAAW;AAAA,MAC7E,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAAA,IACtC,CAAC;AAGD,QAAI,CAAC,eAAe,MAAM,eAAe,WAAW,KAAK;AACvD,YAAM,iBAAiB,gBAAgB,MAAM,uBAAuB;AAAA,IACtE;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,eACpB,KACA,OACA,MACA,aACA,QACA;AACA,SAAO,UAAU,kBAAkB,KAAK,IAAI,IAAI,IAAI,WAAW,IAAI,YAAY;AAC7E,UAAM,IAAI,gBAAgB,GAAG,YAAY,OAAO,IAAI,CAAC,WAAW,WAAW,WAAW;AAAA,MACpF,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,IACjC,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,gBACpB,KACA,OACA,MACA,aACA;AACA,SAAO,UAAU,mBAAmB,KAAK,IAAI,IAAI,IAAI,WAAW,IAAI,YAAY;AAC9E,UAAM,WAAW,MAAM,IAAI,gBAAgB,GAAG,YAAY,OAAO,IAAI,CAAC,WAAW,WAAW,sBAAsB;AAClH,UAAM,SAAS,MAAM,SAAS,KAAK;AACnC,QAAI,CAAC,MAAM,QAAQ,MAAM,GAAG;AAC1B,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AACA,WAAO,OACJ,IAAI,CAAC,UAA4B,MAAM,IAAI,EAC3C,OAAO,CAAC,SAAyB,OAAO,SAAS,YAAY,KAAK,SAAS,CAAC;AAAA,EACjF,CAAC;AACH;AAEA,eAAsB,iBACpB,KACA,OACA,MACA,aACA,OACA;AACA,SAAO,UAAU,oBAAoB,KAAK,IAAI,IAAI,IAAI,WAAW,IAAI,KAAK,IAAI,YAAY;AACxF,UAAM,WAAW,MAAM,IAAI;AAAA,MACzB,GAAG,YAAY,OAAO,IAAI,CAAC,WAAW,WAAW,WAAW,mBAAmB,KAAK,CAAC;AAAA,MACrF;AAAA,QACE,QAAQ;AAAA,MACV;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,MAAM,SAAS,WAAW,KAAK;AAC3C,YAAM,iBAAiB,UAAU,OAAO,sBAAsB;AAAA,IAChE;AAAA,EACF,CAAC;AACH;;;AC9EA,eAAsB,iBACpB,KACA,OACA,MACA,aACA,SACA;AACA,SAAO,UAAU,oBAAoB,KAAK,IAAI,IAAI,IAAI,WAAW,IAAI,OAAO,IAAI,YAAY;AAC1F,UAAM,WAAW,MAAM,IAAI,QAAQ,GAAG,YAAY,OAAO,IAAI,CAAC,WAAW,WAAW,cAAc;AAAA,MAChG,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,QAAQ,CAAC;AAAA,IAClC,CAAC;AAGD,QAAI,SAAS,WAAW,OAAO,SAAS,WAAW,IAAK;AACxD,UAAM,iBAAiB,UAAU,OAAO,WAAW,GAAG,iBAAiB;AAAA,EACzE,CAAC;AACH;;;APMO,IAAM,eAAN,MAAmB;AAAA,EACxB,YACU,KACS,gBACA,SACjB;AAHQ;AACS;AACA;AAAA,EAChB;AAAA;AAAA,EAGK,YAAiD;AAAA,EAEzD,MAAM,uBAAwC;AACxC,QAAI,CAAC,KAAK,gBAAgB;AAC5B,YAAM,IAAI,YAAY,KAAK,2BAA2B,wBAAwB,6DAA6D;AAAA,IAC7I;AACA,UAAM,iBAAiB,KAAK;AAG5B,QAAI,KAAK,WAAW,SAAS,IAAI,KAAK,KAAK,UAAU,SAAS,EAAE,QAAQ,IAAI,KAAK,IAAI,IAAI,KAAQ;AAC/F,aAAO,KAAK,UAAU;AAAA,IACxB;AAEA,UAAM,SAAS,MAAM,4BAA4B,KAAK,KAAK,gBAAgB,KAAK,OAAO;AACvF,QAAI,QAAQ,OAAO;AACjB,WAAK,YAAY;AACjB,aAAO,OAAO;AAAA,IAChB;AAEA,WAAO,UAAU,wBAAwB,YAAY;AACnD,YAAM,SAAS,MAAM,uBAAuB,KAAK,KAAK,cAAc;AACpE,YAAM,6BAA6B,KAAK,KAAK,gBAAgB,QAAQ,KAAK,OAAO;AACjF,WAAK,YAAY;AAEjB,aAAO,OAAO;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEA,aAAa,kBACX,KAC+B;AAC/B,WAAO,mBAAmB,GAAG;AAAA,EAC/B;AAAA,EAEA,aAAa,sBACX,KACiB;AACjB,WAAO,wBAAwB,GAAG;AAAA,EACpC;AAAA,EAEA,MAAM,mBAAgD;AACpD,WAAO,UAAU,oBAAoB,YAAY;AAC/C,YAAM,eAAmC,CAAC;AAE1C,eAAS,OAAO,GAAG,QAAQ,8BAA8B,QAAQ,GAAG;AAClE,cAAM,WAAW,MAAM,KAAK,gBAAgB,uCAAuC,4BAA4B,SAAS,IAAI,EAAE;AAC9H,cAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,qBAAa,KAAK,GAAG,KAAK,YAAY;AAEtC,YAAI,KAAK,aAAa,SAAS,8BAA8B;AAC3D,iBAAO;AAAA,QACT;AAAA,MACF;AAEA,YAAM,IAAI;AAAA,QACR,sCAAsC,4BAA4B;AAAA,MACpE;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,QACZ,MACA,OAAoB,CAAC,GACrB,SAAS,+BACU;AACnB,UAAM,QAAQ,MAAM,KAAK,qBAAqB;AAE9C,QAAI,KAAK,QAAS,MAAK,QAAQ,qBAAqB,CAAC;AACrD,WAAOC;AAAA,MAAY,UAAU,KAAK,UAAU,KAAK,IAAI,IAAI;AAAA,MAAI;AAAA,MAAmB,CAAC,WAC/E,MAAM,yBAAyB,IAAI,IAAI;AAAA,QACrC,GAAG;AAAA,QACH;AAAA,QACA,SAAS;AAAA,UACP,QAAQ;AAAA,UACR,eAAe,UAAU,KAAK;AAAA,UAC9B,wBAAwB;AAAA,UACxB,cAAc,KAAK,IAAI,gBAAgB;AAAA,UACvC,GAAG,KAAK;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAc,gBACZ,MACA,OAAoB,CAAC,GACrB,SAAS,+BACU;AACnB,UAAM,WAAW,MAAM,KAAK,QAAQ,MAAM,MAAM,MAAM;AACtD,UAAM,iBAAiB,UAAU,MAAM,cAAc,KAAK,UAAU,KAAK,IAAI,IAAI,EAAE;AACnF,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,MAA4B;AAClC,WAAO;AAAA,MACL,SAAS,CAAC,MAAM,MAAM,WAAW,KAAK,QAAQ,MAAM,MAAM,MAAM;AAAA,MAChE,iBAAiB,CAAC,MAAM,MAAM,WAAW,KAAK,gBAAgB,MAAM,MAAM,MAAM;AAAA,IAClF;AAAA,EACF;AAAA,EAEA,MAAM,QAAW,OAAe,WAAgD;AAC9E,WAAO,UAAU,WAAW,YAAY;AACtC,YAAM,QAAQ,MAAM,KAAK,qBAAqB;AAE9C,UAAI,KAAK,QAAS,MAAK,QAAQ,qBAAqB,CAAC;AACrD,YAAM,WAAW,MAAMA;AAAA,QAAY;AAAA,QAAkB;AAAA,QAAmB,CAAC,WACvE,MAAM,kCAAkC;AAAA,UACtC,QAAQ;AAAA,UACR;AAAA,UACA,SAAS;AAAA,YACP,eAAe,UAAU,KAAK;AAAA,YAC9B,cAAc,KAAK,IAAI,gBAAgB;AAAA,YACvC,gBAAgB;AAAA,UAClB;AAAA,UACA,MAAM,KAAK,UAAU,EAAE,OAAO,UAAU,CAAC;AAAA,QAC3C,CAAC;AAAA,MACH;AAEA,YAAM,iBAAiB,UAAU,YAAY,wBAAwB;AAErE,YAAM,UAAW,MAAM,SAAS,KAAK;AACrC,UAAI,QAAQ,QAAQ,QAAQ;AAC1B,cAAM,IAAI;AAAA,UACR;AAAA,UACA,KAAK,UAAU,QAAQ,MAAM;AAAA,UAC7B;AAAA,UACA,yBAAyB,QAAQ,OAAO,CAAC,EAAE,OAAO;AAAA,QACpD;AAAA,MACF;AACA,aAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eAAe,OAAe,MAAc,YAAoB;AACpE,WAAO,UAAU,kBAAkB,KAAK,IAAI,IAAI,IAAI,UAAU,IAAI,YAAY;AAC5E,YAAM,WAAW,MAAM,KAAK,gBAAgB,GAAG,YAAY,OAAO,IAAI,CAAC,UAAU,UAAU,EAAE;AAC7F,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,mBAAmB,OAAe,MAAc,YAAoB;AACxE,WAAO,qBAAqB,KAAK,IAAI,GAAG,OAAO,MAAM,UAAU;AAAA,EACjE;AAAA,EAEA,MAAM,eAAe,OAAe,MAAc,MAAc,MAAc;AAC5E,WAAO,iBAAiB,KAAK,IAAI,GAAG,OAAO,MAAM,MAAM,IAAI;AAAA,EAC7D;AAAA;AAAA;AAAA,EAIA,MAAM,YAAY,OAAe,MAAc,MAAc,KAAc;AACzE,WAAO,UAAU,eAAe,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,YAAY;AACnE,YAAM,QAAQ,MAAM,QAAQ,mBAAmB,GAAG,CAAC,KAAK;AACxD,YAAM,WAAW,MAAM,KAAK,QAAQ,GAAG,YAAY,OAAO,IAAI,CAAC,aAAa,wBAAwB,IAAI,CAAC,GAAG,KAAK,EAAE;AACnH,UAAI,SAAS,WAAW,IAAK,QAAO;AACpC,YAAM,iBAAiB,UAAU,MAAM,wBAAwB;AAE/D,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,UAAI,CAAC,KAAK,SAAS;AACjB,eAAO;AAAA,MACT;AACA,UAAI,KAAK,aAAa,SAAU,QAAO,KAAK;AAG5C,YAAM,SAAS,KAAK,KAAK,QAAQ,QAAQ,OAAO,EAAE,CAAC;AACnD,YAAM,QAAQ,WAAW,KAAK,QAAQ,CAAC,SAAS,KAAK,WAAW,CAAC,CAAC;AAClE,aAAO,IAAI,YAAY,EAAE,OAAO,KAAK;AAAA,IACvC,GAAG,CAAC;AAAA,EACN;AAAA,EAEA,MAAM,eACJ,OACA,MACA,OACA;AACA,WAAO,UAAU,kBAAkB,KAAK,IAAI,IAAI,IAAI,YAAY;AAC9D,YAAM,WAAW,MAAM,KAAK,gBAAgB,GAAG,YAAY,OAAO,IAAI,CAAC,eAAe;AAAA,QACpF,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,MAAM;AAAA,UACN,UAAU,MAAM;AAAA,UAChB,QAAQ;AAAA,UACR,aAAa,MAAM;AAAA,UACnB,QAAQ;AAAA,YACN,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,UACjB;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAED,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eACJ,OACA,MACA,YACA,OAMA;AACA,WAAO,UAAU,kBAAkB,KAAK,IAAI,IAAI,IAAI,UAAU,IAAI,YAAY;AAC5E,YAAM,KAAK,gBAAgB,GAAG,YAAY,OAAO,IAAI,CAAC,eAAe,UAAU,IAAI;AAAA,QACjF,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,QAAQ,MAAM,UAAU;AAAA,UACxB,YAAY,MAAM;AAAA,UAClB,cAAc,MAAM,WAAW,eAAc,oBAAI,KAAK,GAAE,YAAY,IAAI;AAAA,UACxE,QAAQ;AAAA,YACN,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,UACjB;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,aACJ,OACA,MACA,YACA,OAMA;AACA,WAAO,WAAW,KAAK,IAAI,GAAG,OAAO,MAAM,YAAY,KAAK;AAAA,EAC9D;AAAA,EAEA,MAAM,uBACJ,OACA,MACA,YACA,WACA,UACgC;AAChC,WAAO,uBAAuB,KAAK,IAAI,GAAG,OAAO,MAAM,YAAY,WAAW,QAAQ;AAAA,EACxF;AAAA,EAEA,MAAM,YAAY,OAAe,MAAc,MAAc,OAAe;AAC1E,WAAO,YAAY,KAAK,IAAI,GAAG,OAAO,MAAM,MAAM,KAAK;AAAA,EACzD;AAAA,EAEA,MAAM,eAAe,OAAe,MAAc,aAAqB,QAAkB;AACvF,WAAO,eAAe,KAAK,IAAI,GAAG,OAAO,MAAM,aAAa,MAAM;AAAA,EACpE;AAAA,EAEA,MAAM,iBAAiB,OAAe,MAAc,aAAqB,SAAe;AACtF,WAAO,iBAAiB,KAAK,IAAI,GAAG,OAAO,MAAM,aAAa,OAAO;AAAA,EACvE;AAAA,EAEA,MAAM,gBAAgB,OAAe,MAAc,aAAqB;AACtE,WAAO,gBAAgB,KAAK,IAAI,GAAG,OAAO,MAAM,WAAW;AAAA,EAC7D;AAAA;AAAA,EAGA,MAAM,2BAA2B,OAAe,MAAc,aAAqB,QAAkB;AACnG,UAAM,gBAAgB,MAAM,KAAK,gBAAgB,OAAO,MAAM,WAAW;AACzE,UAAM,qBAAqB,IAAI,IAAI,cAAc,IAAI,WAAS,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC;AAE3F,UAAM,eAAe,MAAM,KAAK,IAAI,IAAI,OAAO,IAAI,WAAS,MAAM,YAAY,CAAC,CAAC,CAAC;AACjF,eAAW,SAAS,cAAc;AAChC,YAAM,eAAe,mBAAmB,IAAI,KAAK;AACjD,UAAI,cAAc;AAChB,cAAM,KAAK,iBAAiB,OAAO,MAAM,aAAa,YAAY;AAAA,MACpE;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,iBAAiB,OAAe,MAAc,aAAqB,OAAe;AACtF,WAAO,iBAAiB,KAAK,IAAI,GAAG,OAAO,MAAM,aAAa,KAAK;AAAA,EACrE;AACF;;;AQzTO,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EAER,YAAY,KAAwB,gBAAwB,SAA0D;AACpH,SAAK,SAAS,IAAI,aAAa,KAAK,gBAAgB,OAAO;AAAA,EAC7D;AAAA,EAEA,MAAM,eAAe,OAAe,MAAc,UAAkB;AAClE,WAAO,KAAK,OAAO,eAAe,OAAO,MAAM,QAAQ;AAAA,EACzD;AAAA,EAEA,MAAM,mBAAmB,OAAe,MAAc,UAAkB;AACtE,WAAO,KAAK,OAAO,mBAAmB,OAAO,MAAM,QAAQ;AAAA,EAC7D;AAAA,EAEA,MAAM,eAAe,OAAe,MAAc,MAAc,MAAc;AAC5E,WAAO,KAAK,OAAO,eAAe,OAAO,MAAM,MAAM,IAAI;AAAA,EAC3D;AAAA,EAEA,MAAM,YAAY,OAAe,MAAc,MAAc,KAAc;AACzE,WAAO,KAAK,OAAO,YAAY,OAAO,MAAM,MAAM,GAAG;AAAA,EACvD;AAAA,EAEA,MAAM,eAAe,OAAe,MAAc,QAA6D;AAC7G,WAAO,KAAK,OAAO,eAAe,OAAO,MAAM,MAAM;AAAA,EACvD;AAAA,EAEA,MAAM,eAAe,OAAe,MAAc,YAAoB,QAAgJ;AACpN,WAAO,KAAK,OAAO,eAAe,OAAO,MAAM,YAAY,MAAM;AAAA,EACnE;AAAA,EAEA,MAAM,aAAa,OAAe,MAAc,UAAkB,QAAsG;AACtK,WAAO,KAAK,OAAO,aAAa,OAAO,MAAM,UAAU,MAAM;AAAA,EAC/D;AAAA,EAEA,MAAM,uBAAuB,OAAe,MAAc,UAAkB,WAAmB,UAAkB;AAC/G,WAAO,KAAK,OAAO,uBAAuB,OAAO,MAAM,UAAU,WAAW,QAAQ;AAAA,EACtF;AAAA,EAEA,MAAM,YAAY,OAAe,MAAc,MAAc,OAAe;AAC1E,WAAO,KAAK,OAAO,YAAY,OAAO,MAAM,MAAM,KAAK;AAAA,EACzD;AAAA,EAEA,MAAM,eAAe,OAAe,MAAc,UAAkB,QAAkB;AACpF,WAAO,KAAK,OAAO,eAAe,OAAO,MAAM,UAAU,MAAM;AAAA,EACjE;AAAA,EAEA,MAAM,iBAAiB,OAAe,MAAc,UAAkB,SAAe;AACnF,WAAO,KAAK,OAAO,iBAAiB,OAAO,MAAM,UAAU,OAAO;AAAA,EACpE;AAAA,EAEA,MAAM,2BAA2B,OAAe,MAAc,UAAkB,QAAkB;AAChG,WAAO,KAAK,OAAO,2BAA2B,OAAO,MAAM,UAAU,MAAM;AAAA,EAC7E;AAAA,EAEA,MAAM,iBAAiB,OAAe,MAAc,UAAkB,OAAe;AACnF,WAAO,KAAK,OAAO,iBAAiB,OAAO,MAAM,UAAU,KAAK;AAAA,EAClE;AACF;","names":["withTimeout","logger","logger","logger","logger","withTimeout"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codraoss/provider-github",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.12",
|
|
4
4
|
"description": "GitHub git-provider adapter for Codra: App auth, webhooks, OAuth, and review posting.",
|
|
5
5
|
"author": "Devarshi Shimpi",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
"postpack": "node ../../scripts/swap-publish-exports.mjs restore"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@codraoss/core": "
|
|
66
|
-
"@codraoss/schema": "
|
|
65
|
+
"@codraoss/core": "*",
|
|
66
|
+
"@codraoss/schema": "*"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"tsup": "^8.0.0"
|