@codraoss/provider-github 0.9.4

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.
@@ -0,0 +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/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 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 async getRepoFileOrNull(owner: string, repo: string, path: string) {\n return withRetry(`getRepoFileOrNull ${owner}/${repo}/${path}`, async () => {\n const response = await this.request(`${repoApiPath(owner, repo)}/contents/${encodeGitHubContentPath(path)}`);\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\n return data.encoding === 'base64' ? atob(data.content.replace(/\\n/g, '')) : data.content;\n });\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 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 { 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 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 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"]}
@@ -0,0 +1,74 @@
1
+ import * as _codraoss_core from '@codraoss/core';
2
+ import { DashboardSessionUser, IdentityProvider, AuthorizationResult } from '@codraoss/core';
3
+ import { ReviewComment } from '@codraoss/core/ports';
4
+
5
+ type AppBindingsConfig = {
6
+ APP_KV: {
7
+ get: (key: string, type?: any) => Promise<any | null>;
8
+ put: (key: string, value: string, opts?: any) => Promise<void>;
9
+ };
10
+ APP_PRIVATE_KEY: string;
11
+ GITHUB_APP_ID: string;
12
+ BOT_USERNAME?: string;
13
+ GITHUB_APP_SLUG?: string;
14
+ GITHUB_CLIENT_ID?: string;
15
+ GITHUB_CLIENT_SECRET?: string;
16
+ AUTH_CALLBACK_URL?: string;
17
+ };
18
+ declare class GitHubService {
19
+ private client;
20
+ constructor(env: AppBindingsConfig, installationId: string, tracker?: {
21
+ incrementSubrequests(count?: number): void;
22
+ });
23
+ getPullRequest(owner: string, repo: string, prNumber: number): Promise<_codraoss_core.PullRequestRecord>;
24
+ getPullRequestDiff(owner: string, repo: string, prNumber: number): Promise<string>;
25
+ getCompareDiff(owner: string, repo: string, base: string, head: string): Promise<string>;
26
+ createCheckRun(owner: string, repo: string, params: {
27
+ headSha: string;
28
+ title: string;
29
+ summary: string;
30
+ }): Promise<{
31
+ id: number;
32
+ }>;
33
+ updateCheckRun(owner: string, repo: string, checkRunId: number, params: {
34
+ title: string;
35
+ summary: string;
36
+ status?: 'in_progress' | 'completed';
37
+ conclusion?: 'success' | 'neutral' | 'failure' | 'cancelled';
38
+ }): Promise<void>;
39
+ createReview(owner: string, repo: string, prNumber: number, params: {
40
+ commitSha: string;
41
+ event: 'APPROVE' | 'COMMENT';
42
+ body: string;
43
+ comments: ReviewComment[];
44
+ }): Promise<{
45
+ id: number;
46
+ postedIndices: number[];
47
+ }>;
48
+ findBotReviewForCommit(owner: string, repo: string, prNumber: number, commitSha: string, botLogin: string): Promise<{
49
+ id: number;
50
+ } | null>;
51
+ ensureLabel(owner: string, repo: string, name: string, color: string): Promise<void>;
52
+ addIssueLabels(owner: string, repo: string, prNumber: number, labels: string[]): Promise<void>;
53
+ removeIssueLabelsIfPresent(owner: string, repo: string, prNumber: number, labels: string[]): Promise<void>;
54
+ removeIssueLabel(owner: string, repo: string, prNumber: number, label: string): Promise<void>;
55
+ }
56
+
57
+ type GitHubOAuthProfile = {
58
+ id: number;
59
+ login: string;
60
+ name: string | null;
61
+ avatar_url: string | null;
62
+ email: string | null;
63
+ };
64
+ declare function exchangeGitHubOAuthCode(env: AppBindingsConfig, code: string): Promise<string>;
65
+ declare function fetchGitHubOAuthProfile(token: string): Promise<GitHubOAuthProfile>;
66
+ declare function toDashboardSessionUser(profile: GitHubOAuthProfile): DashboardSessionUser;
67
+ declare class GitHubIdentityProvider implements IdentityProvider {
68
+ beginAuthorization(redirectUri: string, state: string, env: AppBindingsConfig): Promise<{
69
+ url: string;
70
+ }>;
71
+ completeAuthorization(code: string, state: string, expectedState: string, env: AppBindingsConfig): Promise<AuthorizationResult>;
72
+ }
73
+
74
+ export { type AppBindingsConfig as A, type GitHubOAuthProfile as G, GitHubService as a, GitHubIdentityProvider as b, exchangeGitHubOAuthCode as e, fetchGitHubOAuthProfile as f, toDashboardSessionUser as t };
@@ -0,0 +1,3 @@
1
+ import '@codraoss/core';
2
+ export { b as GitHubIdentityProvider, G as GitHubOAuthProfile, e as exchangeGitHubOAuthCode, f as fetchGitHubOAuthProfile, t as toDashboardSessionUser } from './oauth-mK0KJT6r.js';
3
+ import '@codraoss/core/ports';
package/dist/oauth.js ADDED
@@ -0,0 +1,13 @@
1
+ import {
2
+ GitHubIdentityProvider,
3
+ exchangeGitHubOAuthCode,
4
+ fetchGitHubOAuthProfile,
5
+ toDashboardSessionUser
6
+ } from "./chunk-OACX7HPZ.js";
7
+ export {
8
+ GitHubIdentityProvider,
9
+ exchangeGitHubOAuthCode,
10
+ fetchGitHubOAuthProfile,
11
+ toDashboardSessionUser
12
+ };
13
+ //# sourceMappingURL=oauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,8 @@
1
+ import { WebhookEventName, WebhookPayload } from '@codraoss/schema/webhook';
2
+
3
+ declare function normalizeGitHubWebhook(eventName: string, payload: unknown): {
4
+ eventName: WebhookEventName;
5
+ payload: WebhookPayload;
6
+ } | null;
7
+
8
+ export { normalizeGitHubWebhook };
@@ -0,0 +1,7 @@
1
+ import {
2
+ normalizeGitHubWebhook
3
+ } from "./chunk-JIVK2ZFL.js";
4
+ export {
5
+ normalizeGitHubWebhook
6
+ };
7
+ //# sourceMappingURL=webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@codraoss/provider-github",
3
+ "version": "0.9.4",
4
+ "description": "GitHub git-provider adapter for Codra: App auth, webhooks, OAuth, and review posting.",
5
+ "author": "Devarshi Shimpi",
6
+ "license": "AGPL-3.0-only",
7
+ "homepage": "https://codra.run",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/devarshishimpi/codra.git",
11
+ "directory": "packages/provider-github"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/devarshishimpi/codra/issues"
15
+ },
16
+ "type": "module",
17
+ "sideEffects": false,
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ },
23
+ "./oauth": {
24
+ "types": "./dist/oauth.d.ts",
25
+ "import": "./dist/oauth.js"
26
+ },
27
+ "./webhook": {
28
+ "types": "./dist/webhook.d.ts",
29
+ "import": "./dist/webhook.js"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "LICENSE",
35
+ "README.md"
36
+ ],
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "main": "./dist/index.js",
40
+ "module": "./dist/index.js",
41
+ "types": "./dist/index.d.ts",
42
+ "exports": {
43
+ ".": {
44
+ "types": "./dist/index.d.ts",
45
+ "import": "./dist/index.js"
46
+ },
47
+ "./oauth": {
48
+ "types": "./dist/oauth.d.ts",
49
+ "import": "./dist/oauth.js"
50
+ },
51
+ "./webhook": {
52
+ "types": "./dist/webhook.d.ts",
53
+ "import": "./dist/webhook.js"
54
+ }
55
+ }
56
+ },
57
+ "scripts": {
58
+ "build": "tsup",
59
+ "typecheck": "tsc -p tsconfig.json",
60
+ "test": "vitest run",
61
+ "prepack": "node ../../scripts/swap-publish-exports.mjs promote",
62
+ "postpack": "node ../../scripts/swap-publish-exports.mjs restore"
63
+ },
64
+ "dependencies": {
65
+ "@codraoss/core": "^0.9.4",
66
+ "@codraoss/schema": "^0.9.4"
67
+ },
68
+ "devDependencies": {
69
+ "tsup": "^8.0.0"
70
+ },
71
+ "main": "./dist/index.js",
72
+ "module": "./dist/index.js",
73
+ "types": "./dist/index.d.ts"
74
+ }