@codraoss/api 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/chunk-N45ONQ2Q.js +145 -0
- package/dist/chunk-N45ONQ2Q.js.map +1 -0
- package/dist/chunk-RMQQ4RZ4.js +53 -0
- package/dist/chunk-RMQQ4RZ4.js.map +1 -0
- package/dist/index.d.ts +38 -2
- package/dist/index.js +268 -53
- package/dist/index.js.map +1 -1
- package/dist/kv-ByAbDUqn.d.ts +10 -0
- package/dist/logger.d.ts +14 -0
- package/dist/logger.js +7 -0
- package/dist/logger.js.map +1 -0
- package/dist/platform/index.d.ts +30 -0
- package/dist/platform/index.js +23 -0
- package/dist/platform/index.js.map +1 -0
- package/package.json +22 -6
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/router.ts","../src/middleware/auth.ts","../src/http.ts","../src/sessions.ts","../src/middleware/csrf.ts","../src/logger.ts","../src/middleware/observability.ts","../src/routes/auth.ts","../src/routes/webhook.ts","../src/routes/api/auth.ts","../src/middleware/authorize.ts","../src/routes/api/jobs.ts","../src/routes/api/repos.ts","../src/routes/api/stats.ts","../src/routes/api/models.ts","../src/routes/api/settings.ts"],"sourcesContent":["import { Hono } from 'hono';\nimport type { Context, MiddlewareHandler } from 'hono';\nimport type { ApiEnv } from './ports';\nimport { requireSession } from './middleware/auth';\nimport { requireCsrfHeader } from './middleware/csrf';\nimport { observability } from './middleware/observability';\nimport { createAuthRouter } from './routes/auth';\nimport { createWebhookRouter } from './routes/webhook';\nimport { createAuthApiRouter } from './routes/api/auth';\nimport { createJobsRouter } from './routes/api/jobs';\nimport { createReposRouter } from './routes/api/repos';\nimport { createStatsRouter } from './routes/api/stats';\nimport { createModelsRouter } from './routes/api/models';\nimport { createSettingsRouter } from './routes/api/settings';\n\nasync function serveIndex(c: Context<ApiEnv>) {\n // If the host platform passes an ASSETS binding via `c.env`, use it (e.g., Cloudflare Workers).\n const assets = (c.env as any).ASSETS;\n if (assets && typeof assets.fetch === 'function') {\n // Method call, and `/` not `/index.html`: detaching throws, and `/index.html` 307s into a loop.\n return assets.fetch(new Request(new URL('/', c.req.url), c.req.raw));\n }\n\n return c.text('Not Found: Please mount UI static assets handler here.', 404);\n}\n\nexport interface ApiRouterOptions {\n // Cross-cutting request middleware; also sees /webhook and /auth, which the /api/* guards skip.\n beforeAuth?: MiddlewareHandler<ApiEnv>[];\n // Runs on /api/* after the session and CSRF guards, so `sessionUser` is populated.\n afterAuth?: MiddlewareHandler<ApiEnv>[];\n pages?: string[];\n publicPages?: string[];\n // Called last, so paths added under /api/* still inherit the session, CSRF and afterAuth middleware.\n routes?: (app: Hono<ApiEnv>) => void;\n}\n\nexport function createApiRouter(options: ApiRouterOptions = {}) {\n const app = new Hono<ApiEnv>();\n\n app.use('*', observability);\n for (const middleware of options.beforeAuth ?? []) {\n app.use('*', middleware);\n }\n app.use('/auth/logout', requireSession);\n app.use('/auth/logout', requireCsrfHeader);\n\n app.route('/auth', createAuthRouter());\n app.route('/webhook', createWebhookRouter());\n\n app.use('/api/*', requireSession);\n app.use('/api/*', requireCsrfHeader);\n for (const middleware of options.afterAuth ?? []) {\n app.use('/api/*', middleware);\n }\n\n app.route('/api/auth', createAuthApiRouter());\n app.route('/api/jobs', createJobsRouter());\n app.route('/api/repos', createReposRouter());\n app.route('/api/stats', createStatsRouter());\n app.route('/api/models', createModelsRouter());\n app.route('/api/settings', createSettingsRouter());\n\n app.get('/login', serveIndex);\n app.get('/', serveIndex); // Unauthenticated landing page\n app.get('/dashboard', requireSession, serveIndex);\n app.get('/jobs', requireSession, serveIndex);\n app.get('/jobs/*', requireSession, serveIndex);\n app.get('/repos', requireSession, serveIndex);\n app.get('/stats', requireSession, serveIndex);\n app.get('/health', requireSession, serveIndex);\n app.get('/settings', requireSession, serveIndex);\n app.get('/account', requireSession, serveIndex);\n\n for (const path of options.publicPages ?? []) {\n app.get(path, serveIndex);\n }\n for (const path of options.pages ?? []) {\n app.get(path, requireSession, serveIndex);\n }\n\n options.routes?.(app);\n\n return app;\n}\n","import { createMiddleware } from 'hono/factory';\nimport type { ApiEnv } from '../ports';\nimport { wantsHtml } from '../http';\nimport { readSession } from '../sessions';\n\nexport const requireSession = createMiddleware<ApiEnv>(async (c, next) => {\n const session = await readSession(c);\n if (!session) {\n if (wantsHtml(c.req.raw)) {\n return c.redirect('/login');\n }\n\n return Response.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n await next();\n});\n","export function jsonError(message: string, status = 400) {\n return Response.json({ error: message }, { status });\n}\n\nexport function wantsHtml(request: Request) {\n const accept = request.headers.get('accept') ?? '';\n return accept.includes('text/html');\n}\n","import { deleteCookie, getCookie, setCookie } from 'hono/cookie';\nimport type { Context } from 'hono';\nimport type { ApiEnv } from './ports';\nimport type { DashboardSessionUser } from '@codraoss/core/ports';\n\nconst SESSION_COOKIE_NAME = 'codra_session';\nconst SESSION_TTL_SECONDS = 60 * 60 * 24 * 7;\n\ntype SessionRecord = DashboardSessionUser;\n\nexport async function createSession(c: Context<ApiEnv>, session: SessionRecord) {\n const token = await c.env.deps.sessionStore.createSession(session);\n\n setCookie(c, SESSION_COOKIE_NAME, token, {\n httpOnly: true,\n sameSite: 'Lax',\n secure: true,\n path: '/',\n maxAge: SESSION_TTL_SECONDS,\n });\n\n c.set('sessionToken', token);\n c.set('sessionUser', session);\n\n return token;\n}\n\nexport async function destroySession(c: Context<ApiEnv>) {\n const token = getCookie(c, SESSION_COOKIE_NAME);\n if (token) {\n await c.env.deps.sessionStore.destroySession(token);\n }\n\n c.set('sessionToken', null);\n c.set('sessionUser', null);\n\n deleteCookie(c, SESSION_COOKIE_NAME, {\n path: '/',\n });\n}\n\nexport async function readSession(c: Context<ApiEnv>) {\n const token = getCookie(c, SESSION_COOKIE_NAME) ?? null;\n c.set('sessionToken', token);\n\n if (!token) {\n c.set('sessionUser', null);\n return null;\n }\n\n const session = await c.env.deps.sessionStore.readSession(token);\n c.set('sessionUser', session);\n return session;\n}\n","import { createMiddleware } from 'hono/factory';\nimport type { ApiEnv } from '../ports';\n\nconst SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);\nconst REQUESTED_WITH = 'XMLHttpRequest';\n\nexport const requireCsrfHeader = createMiddleware<ApiEnv>(async (c, next) => {\n if (SAFE_METHODS.has(c.req.method.toUpperCase())) {\n await next();\n return;\n }\n\n if (c.req.header('x-requested-with') !== REQUESTED_WITH) {\n return c.json({ error: 'Forbidden' }, 403);\n }\n\n await next();\n});\n","import { AsyncLocalStorage } from 'node:async_hooks';\nimport { formatLogRecord, setLoggerSink } from '@codraoss/core/logger';\n\n// The request-context half of the logger. Scrubbing and record shaping live in @codraoss/core/logger;\n// this file owns everything platform-bound -- AsyncLocalStorage and the console sink -- so that\n// node:async_hooks never enters the engine package. Importing this module installs it as the sink\n// that @codraoss/core's `logger` facade delegates to (see the bottom of the file).\nconst storage = new AsyncLocalStorage<Record<string, any>>();\n\nclass Logger {\n constructor(private context: Record<string, any> = {}) {}\n\n withContext(newContext: Record<string, any>) {\n return new Logger({ ...this.context, ...newContext });\n }\n\n private log(level: string, message: string, data?: any) {\n const store = storage.getStore() || {};\n const output = formatLogRecord(level, message, [store, this.context], data);\n\n if (level === 'error') {\n console.error(JSON.stringify(output));\n } else if (level === 'warn') {\n console.warn(JSON.stringify(output));\n } else {\n console.log(JSON.stringify(output));\n }\n }\n\n runWithContext<T>(context: Record<string, any>, fn: () => T): T {\n return storage.run({ ...storage.getStore(), ...context }, fn);\n }\n\n info(message: string, data?: any) {\n this.log('info', message, data);\n }\n\n error(message: string, data?: any) {\n if (data instanceof Error) {\n this.log('error', message, {\n name: data.name,\n message: data.message,\n stack: data.stack,\n });\n } else {\n this.log('error', message, data);\n }\n }\n\n warn(message: string, data?: any) {\n this.log('warn', message, data);\n }\n\n debug(message: string, data?: any) {\n this.log('debug', message, data);\n }\n}\n\nexport const logger = new Logger();\n\n// Wired at import scope so engine code logging through @codraoss/core's facade lands here, with request\n// context attached, rather than in core's bare console fallback.\nsetLoggerSink(logger);\n","import type { MiddlewareHandler } from 'hono';\nimport type { ApiEnv } from '../ports';\nimport { logger } from '../logger';\n\nexport const observability: MiddlewareHandler<ApiEnv> = async (c, next) => {\n const requestId = c.req.header('x-request-id') || crypto.randomUUID();\n c.set('requestId', requestId);\n\n return logger.runWithContext({\n requestId,\n method: c.req.method,\n path: c.req.path,\n }, async () => {\n logger.info(`Incoming request: ${c.req.method} ${c.req.path}`);\n\n const start = Date.now();\n await next();\n const duration = Date.now() - start;\n\n logger.info(`Request completed: ${c.req.method} ${c.req.path}`, {\n status: c.res.status,\n durationMs: duration,\n });\n });\n};\n","import { Hono } from 'hono';\nimport type { ApiEnv } from '../ports';\nimport { createSession, destroySession } from '../sessions';\n\nfunction redirectToLogin(reason: string) {\n const params = new URLSearchParams({ error: reason });\n return `/login?${params.toString()}`;\n}\n\nexport function parseAllowedUsers(input: string) {\n return new Set(\n input\n .split(',')\n .map((value) => value.trim().toLowerCase())\n .filter(Boolean),\n );\n}\n\nexport function createAuthRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/github', async (c) => {\n const state = await c.env.deps.authProvider.createOAuthState();\n const result = await c.env.deps.authProvider.beginAuthorization(c.env.AUTH_CALLBACK_URL, state);\n return c.redirect(result.url, 302);\n });\n\n app.get('/github/callback', async (c) => {\n const error = c.req.query('error');\n if (error) {\n return c.redirect(redirectToLogin(error), 302);\n }\n\n const code = c.req.query('code')?.trim();\n const state = c.req.query('state')?.trim();\n if (!code || !state) {\n return c.redirect(redirectToLogin('invalid_callback'), 302);\n }\n\n const stateMatches = await c.env.deps.authProvider.consumeOAuthState(state);\n if (!stateMatches) {\n return c.redirect(redirectToLogin('invalid_state'), 302);\n }\n\n try {\n const { identity } = await c.env.deps.authProvider.completeAuthorization(code, state, state);\n const allowedUsers = parseAllowedUsers(c.env.DASHBOARD_ALLOWED_USERS);\n\n if (!allowedUsers.has(identity.login.toLowerCase())) {\n return c.redirect(redirectToLogin('not_allowed'), 302);\n }\n\n await destroySession(c);\n await createSession(c, identity);\n\n // Best-effort: a DB hiccup must not block sign-in (the account page self-heals on next load).\n try {\n await c.env.deps.repositories.accounts.upsertAccountSettings(c.env as any, {\n githubUserId: Number(identity.providerUserId),\n githubUsername: identity.login,\n accountName: identity.name,\n accountEmail: identity.email,\n });\n } catch (err) {\n c.env.deps.platform.logger.warn('Failed to persist account settings on sign-in', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n return c.redirect('/dashboard', 302);\n } catch {\n return c.redirect(redirectToLogin('oauth_failed'), 302);\n }\n });\n\n app.post('/logout', async (c) => {\n await destroySession(c);\n return c.json({ ok: true });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { Context } from 'hono';\nimport {\n isFeedbackGitHubWebhookEvent,\n type FeedbackWebhookPayload,\n type GitHubReviewCommentPayload,\n type GitHubWebhookPayload,\n} from '@codraoss/schema/github';\nimport type { ApiEnv } from '../ports';\nimport { jsonError } from '../http';\n\n// Matches via the invisible `codra-fp` marker GitHub echoes back verbatim; comments without one are ignored. Best-effort: failures here must never surface as a webhook error GitHub retries.\nasync function handleFeedbackEvent(\n c: Context<ApiEnv>,\n input: {\n eventName: string;\n payload: FeedbackWebhookPayload;\n repositoryId: number | null;\n },\n): Promise<number> {\n const { eventName, payload, repositoryId } = input;\n // The repository has to be one we know; the FK would reject anything else.\n if (repositoryId === null) return 0;\n\n const botLogin = (c.env.BOT_USERNAME ?? '').toLowerCase();\n // GitHub fires these events for human threads too; without this filter we'd suppress our own findings based on humans deleting each other's comments.\n const isOurs = (comment: GitHubReviewCommentPayload) =>\n Boolean(botLogin) && (comment.user?.login ?? '').toLowerCase().startsWith(botLogin);\n\n const prNumber = payload.pull_request?.number ?? null;\n const entries: any[] = [];\n const reopened: number[] = [];\n\n const add = (comment: GitHubReviewCommentPayload, outcome: any) => {\n if (!isOurs(comment) || !comment?.body) return;\n \n // We need a port for parsing finding markers since it used to come from @server/services/formatter\n // We'll use a local minimal parser or expect the webhook port to provide it\n const markerMatch = (comment.body || '').match(/<!-- codra-fp: (.*?) -->/);\n if (!markerMatch) return;\n \n let fingerprint = markerMatch[1];\n let anchorHash = '';\n let fingerprintV2 = null;\n try {\n const parts = JSON.parse(fingerprint);\n if (Array.isArray(parts) && parts.length >= 2) {\n fingerprintV2 = parts[0];\n fingerprint = parts[1];\n if (parts.length >= 3) anchorHash = parts[2];\n }\n } catch {\n // old format\n }\n \n entries.push({\n repositoryId,\n prNumber,\n fingerprint,\n anchorHash,\n fingerprintV2,\n githubCommentId: comment.id,\n outcome,\n });\n };\n\n if (eventName === 'pull_request_review_comment') {\n const { action, comment } = payload as Extract<FeedbackWebhookPayload, { comment: unknown }>;\n // 'created' is how we learn the real GitHub comment id for free, with no extra request; 'deleted' is the only negative signal we act on.\n if (action === 'created') add(comment, 'posted');\n else if (action === 'deleted') add(comment, 'deleted');\n } else if (eventName === 'pull_request_review_thread') {\n const { action, thread } = payload as Extract<FeedbackWebhookPayload, { thread: unknown }>;\n for (const comment of thread?.comments ?? []) {\n if (action === 'resolved') {\n add(comment, 'resolved');\n } else if (action === 'unresolved') {\n add(comment, 'unresolved');\n if (isOurs(comment)) reopened.push(comment.id);\n }\n }\n }\n\n if (entries.length === 0) return 0;\n\n try {\n const feedbackRepo = c.env.deps.repositories.commentFeedback;\n // Reopening a thread must retract the earlier 'resolved' row, or the finding stays recorded as accepted forever.\n if (reopened.length > 0) await feedbackRepo.clearResolvedFeedback(c.env as any, repositoryId, reopened);\n return await feedbackRepo.recordCommentFeedback(c.env as any, entries);\n } catch (error) {\n c.env.deps.platform.logger.warn('Could not record comment feedback', {\n eventName,\n repositoryId,\n error: error instanceof Error ? error.message : String(error),\n });\n return 0;\n }\n}\n\nexport async function handleGitHubWebhook(c: Context<ApiEnv>) {\n const eventName = c.req.header('x-github-event');\n const deliveryId = c.req.header('x-github-delivery');\n const signature = c.req.header('x-hub-signature-256');\n const rawBody = await c.req.text();\n\n if (!eventName || !deliveryId) {\n return jsonError('Missing GitHub webhook headers.', 400);\n }\n\n const verified = await c.env.deps.webhook.verifySignature(signature ?? null, rawBody);\n if (!verified) {\n return jsonError('Invalid webhook signature.', 401);\n }\n\n let payload: GitHubWebhookPayload;\n try {\n payload = JSON.parse(rawBody) as GitHubWebhookPayload;\n } catch {\n return jsonError('Invalid webhook JSON payload.', 400);\n }\n\n // Feedback deliveries carry the whole PR object plus diff hunks per comment; skip storing the payload (row is still written, so dedup still works).\n const isFeedbackEvent = isFeedbackGitHubWebhookEvent(eventName);\n\n const delivery = await c.env.deps.repositories.webhookDeliveries.recordWebhookDelivery(c.env as any, {\n deliveryId,\n eventName,\n owner: 'repository' in payload ? (payload as any).repository.owner.login : null,\n repo: 'repository' in payload ? (payload as any).repository.name : null,\n payload: isFeedbackEvent ? null : payload,\n });\n\n if (!delivery.inserted) {\n return c.json({ ok: true, duplicate: true }, 202);\n }\n\n const installationId = String((payload as any).installation?.id ?? '');\n if (!installationId || !('repository' in payload) || !payload.repository) {\n return c.json({ ok: true, ignored: true }, 202);\n }\n\n // Handled inline before loadRepoConfig: recording feedback needs no repo config, queue message, or Workflow, so skip that KV/DB cost entirely.\n if (isFeedbackEvent) {\n const recorded = await handleFeedbackEvent(c, {\n eventName,\n payload: payload as unknown as FeedbackWebhookPayload,\n repositoryId: delivery.repositoryId,\n });\n return c.json({ ok: true, feedback: true, recorded }, 202);\n }\n\n const normalized = c.env.deps.webhook.normalizePayload(eventName, payload);\n if (!normalized) {\n return c.json({ ok: true, ignored: true, eventName }, 202);\n }\n\n const repoConfig = await c.env.deps.config.loadRepoConfig({\n installationId,\n owner: (payload as any).repository.owner.login,\n repo: (payload as any).repository.name,\n });\n\n if (repoConfig.enabled === false) {\n return c.json({ ok: true, ignored: true, reason: 'repository_disabled' }, 202);\n }\n\n const extracted = c.env.deps.webhook.extractReviewRequest({\n eventName: normalized.eventName,\n payload: normalized.payload,\n botUsername: c.env.BOT_USERNAME,\n config: repoConfig.parsedJson,\n });\n\n if (extracted?.commitSha && extracted.baseSha) {\n const jobsRepo = c.env.deps.repositories.jobs;\n const existingJob = await jobsRepo.findExistingJobForHead(c.env as any, {\n owner: extracted.owner,\n repo: extracted.repo,\n prNumber: extracted.prNumber,\n commitSha: extracted.commitSha,\n trigger: extracted.trigger,\n });\n\n if (existingJob) {\n return c.json({\n ok: true,\n duplicate: true,\n message: existingJob.status === 'queued' ? 'queued' : 'duplicate',\n job: existingJob,\n }, 202);\n }\n\n const throttled = await c.env.deps.checkQuota?.({\n action: 'reviews.enqueue',\n subject: {\n installationId: extracted.installationId,\n owner: extracted.owner,\n repo: extracted.repo,\n },\n });\n if (throttled && !throttled.allowed) {\n // Deliberately 202, not 429: GitHub redelivers failed webhooks, so 4xx causes retry storms.\n return c.json({ ok: true, ignored: true, reason: 'quota_exceeded' }, 202);\n }\n\n const job = await jobsRepo.insertJob(c.env as any, {\n installationId: extracted.installationId,\n owner: extracted.owner,\n repo: extracted.repo,\n prNumber: extracted.prNumber,\n prTitle: extracted.prTitle,\n prAuthor: extracted.prAuthor,\n commitSha: extracted.commitSha,\n baseSha: extracted.baseSha,\n trigger: extracted.trigger,\n headRef: extracted.headRef,\n baseRef: extracted.baseRef,\n configSnapshot: repoConfig.parsedJson,\n });\n\n await jobsRepo.supersedeOlderJobs(c.env as any, {\n installationId: extracted.installationId,\n owner: extracted.owner,\n repo: extracted.repo,\n prNumber: extracted.prNumber,\n newJobId: job.id,\n });\n\n await c.env.deps.platform.enqueueReviewJob({\n jobId: job.id,\n deliveryId,\n phase: 'prepare',\n requestId: c.get('requestId'),\n });\n\n return c.json({ ok: true, message: 'queued', job }, 202);\n }\n\n // Events without a concrete job (e.g. PR close cleanup, mention lookups) still get handled by the worker.\n await c.env.deps.platform.enqueueReviewJob({\n deliveryId,\n eventName,\n requestId: c.get('requestId'),\n } as any);\n\n return c.json({ ok: true, message: 'queued' }, 202);\n}\n\nexport function createWebhookRouter() {\n const app = new Hono<ApiEnv>();\n\n app.post('/', handleGitHubWebhook);\n\n return app;\n}\n","import { isSupportedTimeZone } from '@codraoss/schema/timezone';\nimport { Hono } from 'hono';\nimport { z } from 'zod';\nimport { jsonError } from '../../http';\nimport type { ApiEnv } from '../../ports';\nimport { requirePermission } from '../../middleware/authorize';\n\nconst emailSchema = z.strictObject({\n email: z.string().trim().email().max(254),\n});\n\n// Fields are independently optional (at least one required); timezone null means \"follow the browser\", else must be an Intl-known zone.\nconst accountUpdateSchema = z.strictObject({\n name: z.string().trim().min(1).max(120).optional(),\n timezone: z.string().trim().min(1).max(64).refine(isSupportedTimeZone, {\n message: 'Unknown time zone.',\n }).nullable().optional(),\n}).refine(\n (body) => body.name !== undefined || body.timezone !== undefined,\n { message: 'Nothing to update.' },\n);\n\nexport function createAuthApiRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/session', async (c) => {\n const sessionUser = c.get('sessionUser');\n if (!sessionUser) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n // Omitted when nothing is restricted, which the dashboard reads as \"every action allowed\".\n const permissions = await c.env.deps.authz?.listPermissions?.(sessionUser);\n\n return c.json(permissions ? { user: sessionUser, permissions } : { user: sessionUser });\n });\n\n app.get('/account', async (c) => {\n const sessionUser = c.get('sessionUser');\n if (!sessionUser) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n const accounts = c.env.deps.repositories.accounts;\n const githubUserId = Number(sessionUser.providerUserId);\n\n // Self-heals for sessions created before the account_settings table existed.\n let account = await accounts.getAccountSettings(c.env as any, githubUserId);\n if (!account) {\n account = await accounts.upsertAccountSettings(c.env as any, {\n githubUserId,\n githubUsername: sessionUser.login,\n accountName: sessionUser.name,\n accountEmail: sessionUser.email,\n });\n }\n\n return c.json({ account });\n });\n\n app.patch('/account', async (c) => {\n const denied = await requirePermission(c, 'account.write');\n if (denied) return denied;\n const sessionUser = c.get('sessionUser');\n if (!sessionUser) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n const body = await c.req.json().catch(() => null);\n const parsed = accountUpdateSchema.safeParse(body);\n if (!parsed.success) {\n const issue = parsed.error.issues[0]?.message;\n return jsonError(\n issue && issue !== 'Invalid input' ? issue : 'Enter a name (1-120 characters).',\n 400,\n );\n }\n\n const accounts = c.env.deps.repositories.accounts;\n const githubUserId = Number(sessionUser.providerUserId);\n\n // Ensure a row exists first (self-heal for pre-existing sessions), then update.\n const existing = await accounts.getAccountSettings(c.env as any, githubUserId);\n if (!existing) {\n await accounts.upsertAccountSettings(c.env as any, {\n githubUserId,\n githubUsername: sessionUser.login,\n accountName: sessionUser.name,\n accountEmail: sessionUser.email,\n });\n }\n\n const account = await accounts.updateAccountSettings(c.env as any, githubUserId, {\n accountName: parsed.data.name,\n timezone: parsed.data.timezone,\n });\n return c.json({ account });\n });\n\n app.get('/updates-email', async (c) => {\n const sessionUser = c.get('sessionUser');\n if (!sessionUser) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n const githubUserId = Number(sessionUser.providerUserId);\n const preference = await c.env.deps.platform.getUpdatesEmailPreference(githubUserId);\n return c.json({\n status: preference?.status ?? 'pending',\n email: preference?.email ?? null,\n updatedAt: preference?.updatedAt ?? null,\n });\n });\n\n app.post('/updates-email', async (c) => {\n const denied = await requirePermission(c, 'account.updatesEmail.write');\n if (denied) return denied;\n const sessionUser = c.get('sessionUser');\n if (!sessionUser) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n const body = await c.req.json().catch(() => null);\n const parsed = emailSchema.safeParse(body);\n if (!parsed.success) {\n return jsonError('Enter a valid email address.', 400);\n }\n\n const platform = c.env.deps.platform;\n const githubUserId = Number(sessionUser.providerUserId);\n\n const existingPreference = await platform.getUpdatesEmailPreference(githubUserId);\n if (existingPreference) {\n return c.json({\n status: existingPreference.status,\n email: existingPreference.email,\n updatedAt: existingPreference.updatedAt,\n });\n }\n\n const synced = await platform.syncUpdatesEmail(githubUserId, parsed.data.email);\n if (!synced) {\n return jsonError('Could not save updates email right now.', 502);\n }\n\n const preference = await platform.getUpdatesEmailPreference(githubUserId);\n\n return c.json({\n status: preference?.status ?? 'pending',\n email: preference?.email ?? null,\n updatedAt: preference?.updatedAt ?? null,\n });\n });\n\n return app;\n}\n","import type { Context } from 'hono';\nimport type { ApiAction } from '@codraoss/schema/api';\nimport type { ApiEnv, QuotaCheckInput } from '../ports';\n\n// Guards return a Response to short-circuit with, or null to continue.\n// Both are inert when the corresponding port is not provided.\n\nexport async function requirePermission(\n c: Context<ApiEnv>,\n action: ApiAction,\n resource?: { type: string; id?: string },\n): Promise<Response | null> {\n const authz = c.env.deps.authz;\n if (!authz) return null;\n\n const user = c.get('sessionUser');\n if (!user) {\n return c.json({ error: 'Unauthorized', code: 'unauthorized', action, reason: null }, 401);\n }\n\n const result = await authz.authorize({ user, action, resource });\n if (result.allowed) return null;\n\n return c.json(\n { error: 'Forbidden', code: 'forbidden', action, reason: result.reason ?? null },\n 403,\n );\n}\n\nexport async function requireQuota(\n c: Context<ApiEnv>,\n input: Omit<QuotaCheckInput, 'user'>,\n): Promise<Response | null> {\n const checkQuota = c.env.deps.checkQuota;\n if (!checkQuota) return null;\n\n const user = c.get('sessionUser') ?? undefined;\n const result = await checkQuota({ ...input, user });\n if (result.allowed) return null;\n\n const headers = result.retryAfterSeconds\n ? { 'Retry-After': String(result.retryAfterSeconds) }\n : undefined;\n\n return c.json(\n {\n error: 'Too many requests',\n code: 'quota_exceeded',\n action: input.action,\n reason: result.reason ?? null,\n },\n 429,\n headers,\n );\n}\n","import { Hono } from 'hono';\nimport type { Context } from 'hono';\nimport { defaultRepoConfig, findingLabelSchema, jobsQuerySchema } from '@codraoss/schema';\nimport { jsonError } from '../../http';\nimport { parseUnifiedDiff } from '@codraoss/core/diff';\nimport { buildFileReviewPrompts, changelogExcerptFromDiff, wantsFileContext } from '@codraoss/core/prompts/file-review';\nimport type { ApiEnv } from '../../ports';\nimport { requirePermission, requireQuota } from '../../middleware/authorize';\n\n// Best-effort: .get()/.terminate() throw if instance is gone/already terminal; both non-fatal.\nasync function terminateJobWorkflow(c: Context<ApiEnv>, job: { id: string; workflowInstanceId?: string | null }) {\n // Goes through platform port; handlers must not touch bindings directly.\n await c.env.deps.platform.terminateJobWorkflow(job);\n}\n\nfunction jobEtag(input: { id: string; status: string; updatedAt: string; fileCount: number; commentCount: number }) {\n return `\"job-${input.id}-${input.status}-${input.fileCount}-${input.commentCount}-${new Date(input.updatedAt).getTime()}\"`;\n}\n\nfunction getExecutionContext(c: Context<ApiEnv>) {\n try {\n return c.executionCtx;\n } catch {\n return undefined;\n }\n}\n\nexport function createJobsRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/', async (c) => {\n const denied = await requirePermission(c, 'jobs.read');\n if (denied) return denied;\n c.env.deps.platform.scheduleBestEffortJobMaintenance(getExecutionContext(c));\n\n const rawQuery = c.req.query();\n const query = jobsQuerySchema.parse(rawQuery);\n\n const result = await c.env.deps.repositories.jobs.listJobs(c.env as any, query as any);\n return c.json(result);\n });\n\n app.get('/:id', async (c) => {\n const denied = await requirePermission(c, 'jobs.read', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n c.env.deps.platform.scheduleBestEffortJobMaintenance(getExecutionContext(c));\n\n const job = await c.env.deps.repositories.jobs.getJobDetail(c.env as any, c.req.param('id'));\n if (!job) {\n return jsonError('Job not found.', 404);\n }\n\n const etag = jobEtag(job);\n const lastModified = new Date(job.updatedAt).toUTCString();\n if (c.req.header('if-none-match') === etag) {\n return new Response(null, {\n status: 304,\n headers: {\n ETag: etag,\n 'Last-Modified': lastModified,\n },\n });\n }\n\n const response = c.json({ job });\n response.headers.set('ETag', etag);\n response.headers.set('Last-Modified', lastModified);\n response.headers.set('Cache-Control', 'private, no-cache');\n return response;\n });\n\n // diff_input isn't persisted; rebuilt from the job's own base/head commits (not the live PR), via KV cache.\n app.get('/:id/diffs', async (c) => {\n const denied = await requirePermission(c, 'jobs.read', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const job = await c.env.deps.repositories.jobs.getJobDetail(c.env as any, c.req.param('id'));\n if (!job) {\n return jsonError('Job not found.', 404);\n }\n\n const config = job.configSnapshot ?? defaultRepoConfig;\n const github = c.env.deps.gitProvider.createService(job.installationId);\n\n let rawDiff: string;\n try {\n rawDiff = await c.env.deps.platform.getOrFetchRawDiffForCompletedJob(\n c.env.deps.platform.createReviewRuntime(),\n { id: job.id, owner: job.owner, repo: job.repo, baseSha: job.baseSha, commitSha: job.commitSha },\n github,\n );\n } catch (error) {\n c.env.deps.platform.logger.warn(`Could not reconstruct diff for job ${job.id}`, error instanceof Error ? error : new Error(String(error)));\n return c.json({ diffs: {} });\n }\n\n // Reconstructs the prompt the model actually saw, so it needs the PR description too.\n let prDescription: string | null = null;\n try {\n prDescription = (await github.getPullRequest(job.owner, job.repo, job.prNumber)).body ?? null;\n } catch (error) {\n // Best-effort: missing description degrades fidelity, doesn't fail the view.\n c.env.deps.platform.logger.warn(`Could not load the PR body for job ${job.id}; prompts will omit the description`,\n error instanceof Error ? error : new Error(String(error)));\n }\n\n // Full PR diff, not just reviewed files, so file count matches GitHub mid-review.\n const diffs: Record<string, string> = {};\n const parsedFiles = parseUnifiedDiff(rawDiff, config.review);\n const changelogExcerpt = changelogExcerptFromDiff(parsedFiles);\n for (const file of parsedFiles) {\n if (file.isDeleted || file.isBinary || !file.path) continue;\n const { userPrompt } = buildFileReviewPrompts({\n file,\n prTitle: job.prTitle,\n prDescription,\n changelogExcerpt,\n config: config.review,\n });\n const hadContext = wantsFileContext(file, config.review.full_file_context);\n diffs[file.path] = hadContext\n ? `${userPrompt}\\n\\n[The full file at the reviewed commit was included here at review time; it is omitted from this preview.]`\n : userPrompt;\n }\n\n const response = c.json({ diffs });\n response.headers.set('Cache-Control', 'private, max-age=60');\n return response;\n });\n\n // inherit=true links retryOfJobId and reuses done file reviews; false reviews everything.\n async function startReplacementJob(c: Context<ApiEnv>, rawSource: any, options: { inherit: boolean }) {\n const jobs = c.env.deps.repositories.jobs;\n const source = jobs.mapJob(rawSource);\n let configSnapshot;\n try {\n const currentConfig = await c.env.deps.config.loadRepoConfig({\n installationId: source.installationId,\n owner: source.owner,\n repo: source.repo,\n });\n configSnapshot = currentConfig?.parsedJson ?? defaultRepoConfig;\n } catch (e) {\n configSnapshot = defaultRepoConfig;\n }\n\n const job = await jobs.insertJob(c.env as any, {\n installationId: source.installationId,\n owner: source.owner,\n repo: source.repo,\n prNumber: source.prNumber,\n prTitle: source.prTitle,\n prAuthor: source.prAuthor,\n commitSha: source.commitSha,\n baseSha: jobs.bytesToHex(rawSource.base_sha), // base_sha is only in raw row/detail\n trigger: 'retry',\n headRef: rawSource.head_ref,\n baseRef: rawSource.base_ref,\n configSnapshot,\n ...(options.inherit ? { retryOfJobId: source.id } : {}),\n });\n\n await jobs.supersedeOlderJobs(c.env as any, {\n installationId: source.installationId,\n owner: source.owner,\n repo: source.repo,\n prNumber: source.prNumber,\n newJobId: job.id,\n });\n\n await c.env.deps.platform.enqueueReviewJob({\n jobId: job.id,\n deliveryId: crypto.randomUUID(),\n phase: 'prepare',\n requestId: c.get('requestId'),\n });\n\n return job;\n }\n\n app.post('/:id/retry', async (c) => {\n const denied = await requirePermission(c, 'jobs.retry', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const throttled = await requireQuota(c, { action: 'jobs.retry' });\n if (throttled) return throttled;\n const jobs = c.env.deps.repositories.jobs;\n const rawSource = await jobs.getJobForProcessing(c.env as any, c.req.param('id'));\n if (!rawSource) {\n return jsonError('Job not found.', 404);\n }\n const job = await startReplacementJob(c, rawSource, { inherit: true });\n return c.json({ job }, 202);\n });\n\n // No inheritance; stops the current run first so two workflows can't race.\n app.post('/:id/rerun', async (c) => {\n const denied = await requirePermission(c, 'jobs.rerun', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const throttled = await requireQuota(c, { action: 'jobs.rerun' });\n if (throttled) return throttled;\n const jobs = c.env.deps.repositories.jobs;\n const rawSource = await jobs.getJobForProcessing(c.env as any, c.req.param('id'));\n if (!rawSource) {\n return jsonError('Job not found.', 404);\n }\n const source = jobs.mapJob(rawSource);\n if (source.status === 'queued' || source.status === 'running') {\n await terminateJobWorkflow(c, source);\n }\n const job = await startReplacementJob(c, rawSource, { inherit: false });\n return c.json({ job }, 202);\n });\n\n app.post('/:id/stop', async (c) => {\n const denied = await requirePermission(c, 'jobs.stop', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const jobs = c.env.deps.repositories.jobs;\n const id = c.req.param('id');\n const raw = await jobs.getJobForProcessing(c.env as any, id);\n if (!raw) {\n return jsonError('Job not found.', 404);\n }\n const job = jobs.mapJob(raw);\n if (job.status !== 'queued' && job.status !== 'running') {\n return jsonError('Only a queued or running job can be stopped.', 409);\n }\n await terminateJobWorkflow(c, job);\n await jobs.cancelJob(c.env as any, id);\n const updated = await jobs.getJobForProcessing(c.env as any, id);\n return c.json({ job: updated ? jobs.mapJob(updated) : job }, 200);\n });\n\n // \"wrong\" suppresses this finding repo-wide; \"right\" is measurement only.\n app.put('/:id/findings/:fingerprint/label', async (c) => {\n const denied = await requirePermission(c, 'jobs.label', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const jobId = c.req.param('id');\n const fingerprint = c.req.param('fingerprint');\n\n const parsed = findingLabelSchema.safeParse(await c.req.json().catch(() => null));\n if (!parsed.success) return jsonError('Body must be {\"label\":\"right\"|\"wrong\"}.', 400);\n\n const target = await c.env.deps.repositories.fileReviews.getFindingLabelTarget(c.env as any, jobId, fingerprint);\n if (!target) return jsonError('Finding not found on this job.', 404);\n\n await c.env.deps.repositories.commentFeedback.upsertDashboardFeedback(c.env as any, {\n repositoryId: target.repository_id,\n prNumber: target.pr_number,\n fingerprint,\n anchorHash: target.anchor_hash,\n // Keeps rejection valid even if the model rewords the title.\n fingerprintV2: target.fingerprint_v2,\n jobId,\n labelledBy: c.get('sessionUser')?.providerUserId ? Number(c.get('sessionUser')?.providerUserId) : null,\n outcome: parsed.data.label === 'wrong' ? 'marked_wrong' : 'marked_right',\n });\n\n return c.json({ label: parsed.data.label }, 200);\n });\n\n // Scoped to dashboard rows; a real GitHub deletion still stays recorded.\n app.delete('/:id/findings/:fingerprint/label', async (c) => {\n const denied = await requirePermission(c, 'jobs.label', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const jobId = c.req.param('id');\n const fingerprint = c.req.param('fingerprint');\n\n const target = await c.env.deps.repositories.fileReviews.getFindingLabelTarget(c.env as any, jobId, fingerprint);\n if (!target) return jsonError('Finding not found on this job.', 404);\n\n await c.env.deps.repositories.commentFeedback.clearDashboardFeedback(c.env as any, target.repository_id, fingerprint);\n return c.body(null, 204);\n });\n\n app.delete('/:id', async (c) => {\n const denied = await requirePermission(c, 'jobs.delete', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const jobs = c.env.deps.repositories.jobs;\n const id = c.req.param('id');\n const raw = await jobs.getJobForProcessing(c.env as any, id);\n if (!raw) {\n return jsonError('Job not found.', 404);\n }\n const job = jobs.mapJob(raw);\n if (job.status === 'queued' || job.status === 'running') {\n await terminateJobWorkflow(c, job);\n }\n await jobs.deleteJob(c.env as any, id);\n return c.body(null, 204);\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport { z } from 'zod';\nimport type { ApiEnv } from '../../ports';\nimport { requirePermission, requireQuota } from '../../middleware/authorize';\nimport { jsonError } from '../../http';\nimport { repoConfigSchema } from '@codraoss/schema';\n\nconst repoConfigPatchSchema = z\n .strictObject({\n enabled: z.boolean().optional(),\n review: repoConfigSchema.shape.review.optional(),\n model: repoConfigSchema.shape.model.optional(),\n })\n .refine(\n (patch) => patch.enabled !== undefined || patch.review !== undefined || patch.model !== undefined,\n 'Repository config patch cannot be empty.',\n );\n\nasync function mapWithConcurrency<T, R>(\n items: T[],\n limit: number,\n mapper: (item: T) => Promise<R>,\n) {\n const results: R[] = new Array(items.length);\n let nextIndex = 0;\n\n async function worker() {\n while (nextIndex < items.length) {\n const currentIndex = nextIndex;\n nextIndex += 1;\n results[currentIndex] = await mapper(items[currentIndex]);\n }\n }\n\n await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));\n return results;\n}\n\nexport function createReposRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/', async (c) => {\n const denied = await requirePermission(c, 'repos.read');\n if (denied) return denied;\n const repos = await c.env.deps.repositories.repoConfigs.listRepoConfigs(c.env as any);\n return c.json({ repos });\n });\n\n app.get('/install', async (c) => {\n const denied = await requirePermission(c, 'repos.install');\n if (denied) return denied;\n try {\n return c.redirect(await c.env.deps.gitProvider.getAppInstallationUrl(), 302);\n } catch (error) {\n c.env.deps.platform.logger.error('Failed to resolve GitHub App installation URL:', error);\n return jsonError(`Failed to resolve GitHub App installation URL: ${error instanceof Error ? error.message : String(error)}`, 500);\n }\n });\n\n app.post('/sync', async (c) => {\n const denied = await requirePermission(c, 'repos.sync');\n if (denied) return denied;\n const throttled = await requireQuota(c, { action: 'repos.sync' });\n if (throttled) return throttled;\n try {\n const installations = await c.env.deps.gitProvider.listInstallations();\n const synced: string[] = [];\n const repoConfigs = c.env.deps.repositories.repoConfigs;\n\n for (const inst of installations) {\n const github = c.env.deps.gitProvider.createService(String(inst.id));\n const repos = await github.listRepositories();\n\n const results = await mapWithConcurrency(\n repos,\n 5,\n async (repo: any) => {\n const owner = repo.owner.login;\n const name = repo.name;\n const fullName = `${owner}/${name}`;\n try {\n await repoConfigs.syncRepoConfig(c.env as any, {\n installationId: String(inst.id),\n owner,\n repo: name,\n });\n return fullName;\n } catch (repoError) {\n c.env.deps.platform.logger.error(`Failed to sync repo: ${fullName}`, repoError);\n return null;\n }\n },\n );\n\n const installationSynced: string[] = [];\n for (const res of results) {\n if (res) {\n synced.push(res);\n installationSynced.push(res);\n }\n }\n \n await repoConfigs.deleteStaleRepoConfigs(c.env as any, String(inst.id), installationSynced);\n }\n\n return c.json({ ok: true, synced });\n } catch (error) {\n c.env.deps.platform.logger.error('Manual sync failed:', error);\n return jsonError(`Sync failed: ${error instanceof Error ? error.message : String(error)}`, 500);\n }\n });\n\n app.get('/:owner/:repo/config', async (c) => {\n const denied = await requirePermission(c, 'repos.read', { type: 'repo', id: `${c.req.param('owner')}/${c.req.param('repo')}` });\n if (denied) return denied;\n const repo = await c.env.deps.repositories.repoConfigs.getRepoConfigRecord(c.env as any, c.req.param('owner'), c.req.param('repo'));\n if (!repo) {\n return jsonError('Repository config not found.', 404);\n }\n\n return c.json({ repo });\n });\n \n app.patch('/:owner/:repo/config', async (c) => {\n const denied = await requirePermission(c, 'repos.config.write', { type: 'repo', id: `${c.req.param('owner')}/${c.req.param('repo')}` });\n if (denied) return denied;\n const { owner, repo } = c.req.param();\n const body = await c.req.json();\n const parsedPatch = repoConfigPatchSchema.safeParse(body);\n if (!parsedPatch.success) {\n return jsonError('Invalid repository config patch.', 400);\n }\n\n const repoConfigs = c.env.deps.repositories.repoConfigs;\n const existing = await repoConfigs.getRepoConfigRecord(c.env as any, owner, repo);\n \n if (!existing) {\n return jsonError('Repository config not found.', 404);\n }\n\n const patch = parsedPatch.data;\n const hasConfigPatch = patch.review !== undefined || patch.model !== undefined;\n\n if (!hasConfigPatch && patch.enabled !== undefined) {\n await repoConfigs.updateRepoConfigEnabled(c.env as any, {\n owner,\n repo,\n enabled: patch.enabled,\n });\n await c.env.deps.config.invalidateRepoConfigCache(owner, repo);\n return c.json({ ok: true });\n }\n\n const configPatch: Partial<z.infer<typeof repoConfigSchema>> = {};\n if (patch.review !== undefined) {\n configPatch.review = patch.review;\n }\n if (patch.model !== undefined) {\n configPatch.model = patch.model;\n }\n \n const updatedParsedJson = {\n ...existing.parsedJson,\n ...configPatch,\n };\n const parsedConfig = repoConfigSchema.safeParse(updatedParsedJson);\n\n if (!parsedConfig.success) {\n return jsonError('Invalid repository config.', 400);\n }\n \n await repoConfigs.upsertRepoConfig(c.env as any, {\n installationId: existing.installationId,\n owner,\n repo,\n parsedJson: parsedConfig.data,\n enabled: patch.enabled,\n });\n await c.env.deps.config.invalidateRepoConfigCache(owner, repo);\n \n return c.json({ ok: true });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { ApiEnv } from '../../ports';\nimport { requirePermission } from '../../middleware/authorize';\n\nexport function createStatsRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/', async (c) => {\n const denied = await requirePermission(c, 'stats.read');\n if (denied) return denied;\n const daysParam = c.req.query('days');\n const days = daysParam ? parseInt(daysParam, 10) : 30;\n // Grouped in the caller's display zone so the trend matches timestamps shown elsewhere; getStats falls back to UTC if invalid.\n const timeZone = c.req.query('tz') ?? 'UTC';\n const stats = await c.env.deps.repositories.stats.getStats(c.env as any, days, timeZone);\n return c.json({ stats });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport { z } from 'zod';\nimport { jsonError } from '../../http';\nimport { llmApiFormats } from '@codraoss/schema';\nimport type { ApiEnv } from '../../ports';\nimport { requirePermission, requireQuota } from '../../middleware/authorize';\n\nconst apiFormatSchema = z.enum(llmApiFormats);\nconst positiveIntegerSchema = z.number().int().positive().finite();\nconst modelIdSchema = z.string().trim().min(1);\nconst optionalUrlSchema = z.string().trim().url().nullable().optional();\nconst providerIdSchema = z.string().uuid();\n\nconst providerCreateSchema = z.strictObject({\n name: z.string().trim().min(1),\n apiFormat: apiFormatSchema,\n baseUrl: optionalUrlSchema,\n apiKey: z.string().optional(),\n enabled: z.boolean().default(true),\n});\n\n// `.extend()` carries the parent's strictness through, so no second `.strict()` is needed here.\nconst providerUpdateSchema = providerCreateSchema.extend({\n clearApiKey: z.boolean().optional(),\n});\n\nconst modelConfigUpdateSchema = z.strictObject({\n providerId: providerIdSchema,\n modelName: z.string().trim().min(1),\n});\n\nconst globalModelConfigSchema = z.strictObject({\n main: modelIdSchema.nullable().default(null),\n fallbacks: z.array(modelIdSchema).nullable().default([]),\n size_overrides: z\n .array(\n z.strictObject({\n max_lines: positiveIntegerSchema,\n model: modelIdSchema,\n fallbacks: z.array(modelIdSchema).optional(),\n }),\n )\n .nullable()\n .optional(),\n});\n\nfunction requiresExplicitBaseUrl(apiFormat: z.infer<typeof apiFormatSchema>, baseUrl: string | null | undefined) {\n return apiFormat === 'vertex' && !baseUrl;\n}\n\nfunction readModelIdParam(value: string) {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nexport function createModelsRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/', async (c) => {\n const denied = await requirePermission(c, 'models.read');\n if (denied) return denied;\n const modelConfigsRepo = c.env.deps.repositories.modelConfigs;\n const [providers, configs] = await Promise.all([\n modelConfigsRepo.listLlmProviders(c.env as any),\n modelConfigsRepo.listModelConfigs(c.env as any),\n ]);\n return c.json({ providers, configs });\n });\n\n app.post('/sync', async (c) => {\n const denied = await requirePermission(c, 'models.sync');\n if (denied) return denied;\n const modelConfigsRepo = c.env.deps.repositories.modelConfigs;\n const syncErrors = await c.env.deps.modelRunner.syncProviderModelCatalog();\n const [providers, configs] = await Promise.all([\n modelConfigsRepo.listLlmProviders(c.env as any),\n modelConfigsRepo.listModelConfigs(c.env as any),\n ]);\n return c.json({ providers, configs, syncErrors });\n });\n\n app.get('/global', async (c) => {\n const denied = await requirePermission(c, 'models.read');\n if (denied) return denied;\n const config = await c.env.deps.config.getGlobalConfig();\n return c.json({ config });\n });\n\n app.patch('/global', async (c) => {\n const denied = await requirePermission(c, 'models.global.write');\n if (denied) return denied;\n const body = await c.req.json();\n const parsed = globalModelConfigSchema.safeParse(body);\n if (!parsed.success) {\n return jsonError('Invalid global model config.', 400);\n }\n\n await c.env.deps.config.updateGlobalConfig(parsed.data);\n return c.json({ ok: true });\n });\n\n app.post('/providers', async (c) => {\n const denied = await requirePermission(c, 'models.provider.create');\n if (denied) return denied;\n const parsed = providerCreateSchema.safeParse(await c.req.json());\n if (!parsed.success) {\n return jsonError('Invalid provider config.', 400);\n }\n\n const input = parsed.data;\n if (requiresExplicitBaseUrl(input.apiFormat, input.baseUrl)) {\n return jsonError('Vertex AI requires a base URL with your GCP project ID and region, e.g. https://us-central1-aiplatform.googleapis.com/v1/projects/YOUR_PROJECT_ID/locations/us-central1', 400);\n }\n\n try {\n const provider = await c.env.deps.modelRunner.createProviderWithSecret(input);\n return c.json({ provider }, 201);\n } catch (error) {\n const err = error as any;\n if (err.isUniqueNameError) {\n return jsonError(`Provider ${input.name} already exists. Update the existing provider instead.`, 409);\n }\n if (err.isEncryptionConfigError) {\n return jsonError(err.message || 'LLM encryption is not configured.', 400);\n }\n if (err.isKeyRequiredError) {\n return jsonError(`Provider ${input.name} needs an API key before it can be enabled.`, 400);\n }\n throw error;\n }\n });\n\n app.patch('/providers/:id', async (c) => {\n const denied = await requirePermission(c, 'models.provider.update', { type: 'llmProvider', id: c.req.param('id') });\n if (denied) return denied;\n const id = c.req.param('id');\n if (!providerIdSchema.safeParse(id).success) {\n return jsonError('Invalid provider id.', 400);\n }\n\n const parsed = providerUpdateSchema.safeParse(await c.req.json());\n if (!parsed.success) {\n return jsonError('Invalid provider config.', 400);\n }\n\n const input = parsed.data;\n if (requiresExplicitBaseUrl(input.apiFormat, input.baseUrl)) {\n return jsonError('Vertex AI requires a base URL with your GCP project ID and region, e.g. https://us-central1-aiplatform.googleapis.com/v1/projects/YOUR_PROJECT_ID/locations/us-central1', 400);\n }\n\n try {\n const provider = await c.env.deps.modelRunner.updateProviderWithSecret(id, input);\n if (!provider) return jsonError('Provider not found.', 404);\n return c.json({ provider });\n } catch (error) {\n const err = error as any;\n if (err.isUniqueNameError) {\n return jsonError(`Provider ${input.name} already exists. Choose a different provider name.`, 409);\n }\n if (err.isEncryptionConfigError) {\n return jsonError(err.message || 'LLM encryption is not configured.', 400);\n }\n if (err.isKeyRequiredError) {\n return jsonError(`Provider ${input.name} needs an API key before it can be enabled.`, 400);\n }\n throw error;\n }\n });\n\n app.delete('/providers/:id', async (c) => {\n const denied = await requirePermission(c, 'models.provider.delete', { type: 'llmProvider', id: c.req.param('id') });\n if (denied) return denied;\n const id = c.req.param('id');\n if (!providerIdSchema.safeParse(id).success) {\n return jsonError('Invalid provider id.', 400);\n }\n\n const result = await c.env.deps.repositories.modelConfigs.deleteLlmProvider(c.env as any, id);\n if (!result.deleted) {\n return jsonError(result.reason ?? 'Provider not found.', result.reason ? 409 : 404);\n }\n return c.json({ ok: true });\n });\n\n app.post('/:id/test', async (c) => {\n const denied = await requirePermission(c, 'models.test', { type: 'modelConfig', id: c.req.param('id') });\n if (denied) return denied;\n const throttled = await requireQuota(c, { action: 'models.test' });\n if (throttled) return throttled;\n const modelId = readModelIdParam(c.req.param('id'));\n const parsedModelId = modelIdSchema.safeParse(modelId);\n if (!parsedModelId.success) {\n return jsonError('Invalid model id.', 400);\n }\n\n try {\n const response = await c.env.deps.modelRunner.testConnection(parsedModelId.data);\n return c.json(response);\n } catch (error) {\n const err = error as any;\n if (err.isNotFoundError) return jsonError('Model not found.', 404);\n if (err.isDisabledError || err.isMissingKeyError) return jsonError(err.message, 400);\n \n return jsonError(\n err.message || 'Connection test failed.',\n err.status || 502,\n );\n }\n });\n\n app.post('/:id', async (c) => {\n const denied = await requirePermission(c, 'models.mapping.write', { type: 'modelConfig', id: c.req.param('id') });\n if (denied) return denied;\n const modelId = readModelIdParam(c.req.param('id'));\n const parsedModelId = modelIdSchema.safeParse(modelId);\n if (!parsedModelId.success) {\n return jsonError('Invalid model id.', 400);\n }\n\n const body = await c.req.json();\n const parsed = modelConfigUpdateSchema.safeParse(body);\n if (!parsed.success) {\n return jsonError('Invalid model config.', 400);\n }\n\n const saved = await c.env.deps.repositories.modelConfigs.updateModelConfig(c.env as any, {\n modelId: parsedModelId.data,\n providerId: parsed.data.providerId,\n modelName: parsed.data.modelName,\n });\n\n if (!saved) return jsonError('Provider not found.', 404);\n return c.json({ ok: true, config: saved });\n });\n\n app.delete('/:id', async (c) => {\n const denied = await requirePermission(c, 'models.mapping.write', { type: 'modelConfig', id: c.req.param('id') });\n if (denied) return denied;\n const modelId = readModelIdParam(c.req.param('id'));\n const parsedModelId = modelIdSchema.safeParse(modelId);\n if (!parsedModelId.success) {\n return jsonError('Invalid model id.', 400);\n }\n\n const deleted = await c.env.deps.repositories.modelConfigs.deleteModelConfig(c.env as any, parsedModelId.data);\n if (!deleted) return jsonError('Model not found.', 404);\n return c.json({ ok: true });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport { z } from 'zod';\nimport type { ApiEnv } from '../../ports';\nimport { requirePermission } from '../../middleware/authorize';\nimport { jsonError } from '../../http';\nimport { reviewConcurrencyLevels, reviewMaxCommentsOptions, reviewMaxFilesRange, reviewSettingsSchema } from '@codraoss/schema';\n\nconst reviewSettingsPatchSchema = z.strictObject({\n concurrencyLevel: z.enum(reviewConcurrencyLevels).optional(),\n maxComments: z.number().int().refine(\n (value) => (reviewMaxCommentsOptions as readonly number[]).includes(value),\n 'Invalid max comments value.',\n ).optional(),\n maxFiles: z.number().int().min(reviewMaxFilesRange.min).max(reviewMaxFilesRange.max).optional(),\n}).refine(\n (settings) => Object.values(settings).some((value) => value !== undefined),\n 'At least one setting must be provided.',\n);\n\nexport function createSettingsRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/', async (c) => {\n const denied = await requirePermission(c, 'settings.read');\n if (denied) return denied;\n const settings = await c.env.deps.repositories.appSettings.getReviewSettings(c.env as any);\n return c.json({ settings });\n });\n\n app.patch('/', async (c) => {\n const denied = await requirePermission(c, 'settings.write');\n if (denied) return denied;\n const body = await c.req.json().catch(() => null);\n const parsed = reviewSettingsPatchSchema.safeParse(body);\n if (!parsed.success) {\n return jsonError('Invalid review settings.', 400);\n }\n\n const current = await c.env.deps.repositories.appSettings.getReviewSettings(c.env as any);\n const next = reviewSettingsSchema.parse({ ...current, ...parsed.data });\n await c.env.deps.repositories.appSettings.updateReviewSettings(c.env as any, next);\n return c.json({ ok: true, settings: next });\n });\n\n return app;\n}\n"],"mappings":"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","names":["Hono","createMiddleware","Hono","Hono","Hono","Hono","Hono","Hono","Hono","z","z","Hono","Hono","Hono","Hono","z","z","Hono","Hono","z","z","Hono","Hono"]}
|
|
1
|
+
{"version":3,"sources":["../src/router.ts","../src/middleware/auth.ts","../src/http.ts","../src/sessions.ts","../src/middleware/csrf.ts","../src/middleware/observability.ts","../src/routes/auth.ts","../src/routes/webhook.ts","../src/routes/api/auth.ts","../src/middleware/authorize.ts","../src/routes/api/jobs.ts","../src/routes/api/repos.ts","../src/routes/api/stats.ts","../src/routes/api/models.ts","../src/routes/api/settings.ts","../src/create-deps.ts"],"sourcesContent":["import { Hono } from 'hono';\nimport type { Context, MiddlewareHandler } from 'hono';\nimport type { ApiEnv } from './ports';\nimport { requireSession } from './middleware/auth';\nimport { requireCsrfHeader } from './middleware/csrf';\nimport { observability } from './middleware/observability';\nimport { createAuthRouter } from './routes/auth';\nimport { createWebhookRouter } from './routes/webhook';\nimport { createAuthApiRouter } from './routes/api/auth';\nimport { createJobsRouter } from './routes/api/jobs';\nimport { createReposRouter } from './routes/api/repos';\nimport { createStatsRouter } from './routes/api/stats';\nimport { createModelsRouter } from './routes/api/models';\nimport { createSettingsRouter } from './routes/api/settings';\n\nasync function serveIndex(c: Context<ApiEnv>) {\n // If the host platform passes an ASSETS binding via `c.env`, use it (e.g., Cloudflare Workers).\n const assets = (c.env as any).ASSETS;\n if (assets && typeof assets.fetch === 'function') {\n // Method call, and `/` not `/index.html`: detaching throws, and `/index.html` 307s into a loop.\n const response = await assets.fetch(new Request(new URL('/', c.req.url), c.req.raw));\n const newResponse = new Response(response.body, { status: response.status, statusText: response.statusText, headers: response.headers });\n newResponse.headers.set('Cache-Control', 'no-cache');\n return newResponse;\n }\n\n c.header('Cache-Control', 'no-cache');\n return c.text('Not Found: Please mount UI static assets handler here.', 404);\n}\n\nexport interface ApiRouterOptions {\n // Cross-cutting request middleware; also sees /webhook and /auth, which the /api/* guards skip.\n beforeAuth?: MiddlewareHandler<ApiEnv>[];\n // Runs on /api/* after the session and CSRF guards, so `sessionUser` is populated.\n afterAuth?: MiddlewareHandler<ApiEnv>[];\n pages?: string[];\n publicPages?: string[];\n // Called last, so paths added under /api/* still inherit the session, CSRF and afterAuth middleware.\n routes?: (app: Hono<ApiEnv>) => void;\n}\n\nexport function createApiRouter(options: ApiRouterOptions = {}) {\n const app = new Hono<ApiEnv>();\n\n app.use('*', observability);\n for (const middleware of options.beforeAuth ?? []) {\n app.use('*', middleware);\n }\n\n // Machine health check — no session required\n app.get('/healthz', (c) => c.json({ status: 'ok', timestamp: new Date().toISOString() }));\n\n app.use('/auth/logout', requireSession);\n app.use('/auth/logout', requireCsrfHeader);\n\n app.route('/auth', createAuthRouter());\n app.route('/webhook', createWebhookRouter());\n\n app.use('/api/*', requireSession);\n app.use('/api/*', requireCsrfHeader);\n for (const middleware of options.afterAuth ?? []) {\n app.use('/api/*', middleware);\n }\n\n app.route('/api/auth', createAuthApiRouter());\n app.route('/api/jobs', createJobsRouter());\n app.route('/api/repos', createReposRouter());\n app.route('/api/stats', createStatsRouter());\n app.route('/api/models', createModelsRouter());\n app.route('/api/settings', createSettingsRouter());\n\n app.get('/login', serveIndex);\n app.get('/', serveIndex); // Unauthenticated landing page\n app.get('/dashboard', requireSession, serveIndex);\n app.get('/jobs', requireSession, serveIndex);\n app.get('/jobs/*', requireSession, serveIndex);\n app.get('/repos', requireSession, serveIndex);\n app.get('/stats', requireSession, serveIndex);\n app.get('/health', requireSession, serveIndex);\n app.get('/settings', requireSession, serveIndex);\n app.get('/account', requireSession, serveIndex);\n\n for (const path of options.publicPages ?? []) {\n app.get(path, serveIndex);\n }\n for (const path of options.pages ?? []) {\n app.get(path, requireSession, serveIndex);\n }\n\n options.routes?.(app);\n\n return app;\n}\n","import { createMiddleware } from 'hono/factory';\nimport type { ApiEnv } from '../ports';\nimport { wantsHtml } from '../http';\nimport { readSession } from '../sessions';\n\nexport const requireSession = createMiddleware<ApiEnv>(async (c, next) => {\n const session = await readSession(c);\n if (!session) {\n if (wantsHtml(c.req.raw)) {\n return c.redirect('/');\n }\n\n return Response.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n await next();\n});\n","export function jsonError(message: string, status = 400) {\n return Response.json({ error: message }, { status });\n}\n\nexport function wantsHtml(request: Request) {\n const accept = request.headers.get('accept') ?? '';\n return accept.includes('text/html');\n}\n","import { deleteCookie, getCookie, setCookie } from 'hono/cookie';\nimport type { Context } from 'hono';\nimport type { ApiEnv } from './ports';\nimport type { DashboardSessionUser } from '@codraoss/core/ports';\n\nconst SESSION_COOKIE_NAME = 'codra_session';\nconst SESSION_TTL_SECONDS = 60 * 60 * 24 * 7;\n\ntype SessionRecord = DashboardSessionUser;\n\nexport async function createSession(c: Context<ApiEnv>, session: SessionRecord) {\n const token = await c.env.deps.sessionStore.createSession(session);\n\n setCookie(c, SESSION_COOKIE_NAME, token, {\n httpOnly: true,\n sameSite: 'Lax',\n secure: true,\n path: '/',\n maxAge: SESSION_TTL_SECONDS,\n });\n\n c.set('sessionToken', token);\n c.set('sessionUser', session);\n\n return token;\n}\n\nexport async function destroySession(c: Context<ApiEnv>) {\n const token = getCookie(c, SESSION_COOKIE_NAME);\n if (token) {\n await c.env.deps.sessionStore.destroySession(token);\n }\n\n c.set('sessionToken', null);\n c.set('sessionUser', null);\n\n deleteCookie(c, SESSION_COOKIE_NAME, {\n path: '/',\n });\n}\n\nexport async function readSession(c: Context<ApiEnv>) {\n const token = getCookie(c, SESSION_COOKIE_NAME) ?? null;\n c.set('sessionToken', token);\n\n if (!token) {\n c.set('sessionUser', null);\n return null;\n }\n\n const session = await c.env.deps.sessionStore.readSession(token);\n c.set('sessionUser', session);\n return session;\n}\n","import { createMiddleware } from 'hono/factory';\nimport type { ApiEnv } from '../ports';\n\nconst SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);\nconst REQUESTED_WITH = 'XMLHttpRequest';\n\nexport const requireCsrfHeader = createMiddleware<ApiEnv>(async (c, next) => {\n if (SAFE_METHODS.has(c.req.method.toUpperCase())) {\n await next();\n return;\n }\n\n if (c.req.header('x-requested-with') !== REQUESTED_WITH) {\n return c.json({ error: 'Forbidden' }, 403);\n }\n\n await next();\n});\n","import type { MiddlewareHandler } from 'hono';\nimport type { ApiEnv } from '../ports';\nimport { logger } from '../logger';\n\nexport const observability: MiddlewareHandler<ApiEnv> = async (c, next) => {\n const requestId = c.req.header('x-request-id') || crypto.randomUUID();\n c.set('requestId', requestId);\n\n return logger.runWithContext({\n requestId,\n method: c.req.method,\n path: c.req.path,\n }, async () => {\n logger.info(`Incoming request: ${c.req.method} ${c.req.path}`);\n\n const start = Date.now();\n await next();\n const duration = Date.now() - start;\n\n logger.info(`Request completed: ${c.req.method} ${c.req.path}`, {\n status: c.res.status,\n durationMs: duration,\n });\n });\n};\n","import { Hono } from 'hono';\nimport type { ApiEnv } from '../ports';\nimport { createSession, destroySession } from '../sessions';\n\nfunction redirectToLogin(reason: string) {\n const params = new URLSearchParams({ error: reason });\n return `/login?${params.toString()}`;\n}\n\nexport function parseAllowedUsers(input: string) {\n return new Set(\n input\n .split(',')\n .map((value) => value.trim().toLowerCase())\n .filter(Boolean),\n );\n}\n\nexport function createAuthRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/github', async (c) => {\n const state = await c.env.deps.authProvider.createOAuthState();\n const result = await c.env.deps.authProvider.beginAuthorization(c.env.AUTH_CALLBACK_URL, state);\n return c.redirect(result.url, 302);\n });\n\n app.get('/github/callback', async (c) => {\n const error = c.req.query('error');\n if (error) {\n return c.redirect(redirectToLogin(error), 302);\n }\n\n const code = c.req.query('code')?.trim();\n const state = c.req.query('state')?.trim();\n if (!code || !state) {\n return c.redirect(redirectToLogin('invalid_callback'), 302);\n }\n\n const stateMatches = await c.env.deps.authProvider.consumeOAuthState(state);\n if (!stateMatches) {\n return c.redirect(redirectToLogin('invalid_state'), 302);\n }\n\n try {\n const { identity } = await c.env.deps.authProvider.completeAuthorization(code, state, state);\n const allowedUsers = parseAllowedUsers(c.env.DASHBOARD_ALLOWED_USERS);\n\n if (!allowedUsers.has(identity.login.toLowerCase())) {\n return c.redirect(redirectToLogin('not_allowed'), 302);\n }\n\n await destroySession(c);\n await createSession(c, identity);\n\n // Best-effort: a DB hiccup must not block sign-in (the account page self-heals on next load).\n try {\n await c.env.deps.repositories.accounts.upsertAccountSettings(c.env as any, {\n githubUserId: Number(identity.providerUserId),\n githubUsername: identity.login,\n accountName: identity.name,\n accountEmail: identity.email,\n });\n } catch (err) {\n c.env.deps.platform.logger.warn('Failed to persist account settings on sign-in', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n return c.redirect('/dashboard', 302);\n } catch {\n return c.redirect(redirectToLogin('oauth_failed'), 302);\n }\n });\n\n app.post('/logout', async (c) => {\n await destroySession(c);\n return c.json({ ok: true });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { Context } from 'hono';\nimport {\n isFeedbackGitHubWebhookEvent,\n type FeedbackWebhookPayload,\n type GitHubReviewCommentPayload,\n type GitHubWebhookPayload,\n} from '@codraoss/schema/github';\nimport type { ApiEnv } from '../ports';\nimport { jsonError } from '../http';\n\n// Matches via the invisible `codra-fp` marker GitHub echoes back verbatim; comments without one are ignored. Best-effort: failures here must never surface as a webhook error GitHub retries.\nasync function handleFeedbackEvent(\n c: Context<ApiEnv>,\n input: {\n eventName: string;\n payload: FeedbackWebhookPayload;\n repositoryId: number | null;\n },\n): Promise<number> {\n const { eventName, payload, repositoryId } = input;\n // The repository has to be one we know; the FK would reject anything else.\n if (repositoryId === null) return 0;\n\n const botLogin = (c.env.BOT_USERNAME ?? '').toLowerCase();\n // GitHub fires these events for human threads too; without this filter we'd suppress our own findings based on humans deleting each other's comments.\n const isOurs = (comment: GitHubReviewCommentPayload) =>\n Boolean(botLogin) && (comment.user?.login ?? '').toLowerCase().startsWith(botLogin);\n\n const prNumber = payload.pull_request?.number ?? null;\n const entries: any[] = [];\n const reopened: number[] = [];\n\n const add = (comment: GitHubReviewCommentPayload, outcome: any) => {\n if (!isOurs(comment) || !comment?.body) return;\n \n // We need a port for parsing finding markers since it used to come from @server/services/formatter\n // We'll use a local minimal parser or expect the webhook port to provide it\n const markerMatch = (comment.body || '').match(/<!-- codra-fp: (.*?) -->/);\n if (!markerMatch) return;\n \n let fingerprint = markerMatch[1];\n let anchorHash = '';\n let fingerprintV2 = null;\n try {\n const parts = JSON.parse(fingerprint);\n if (Array.isArray(parts) && parts.length >= 2) {\n fingerprintV2 = parts[0];\n fingerprint = parts[1];\n if (parts.length >= 3) anchorHash = parts[2];\n }\n } catch {\n // old format\n }\n \n entries.push({\n repositoryId,\n prNumber,\n fingerprint,\n anchorHash,\n fingerprintV2,\n githubCommentId: comment.id,\n outcome,\n });\n };\n\n if (eventName === 'pull_request_review_comment') {\n const { action, comment } = payload as Extract<FeedbackWebhookPayload, { comment: unknown }>;\n // 'created' is how we learn the real GitHub comment id for free, with no extra request; 'deleted' is the only negative signal we act on.\n if (action === 'created') add(comment, 'posted');\n else if (action === 'deleted') add(comment, 'deleted');\n } else if (eventName === 'pull_request_review_thread') {\n const { action, thread } = payload as Extract<FeedbackWebhookPayload, { thread: unknown }>;\n for (const comment of thread?.comments ?? []) {\n if (action === 'resolved') {\n add(comment, 'resolved');\n } else if (action === 'unresolved') {\n add(comment, 'unresolved');\n if (isOurs(comment)) reopened.push(comment.id);\n }\n }\n }\n\n if (entries.length === 0) return 0;\n\n try {\n const feedbackRepo = c.env.deps.repositories.commentFeedback;\n // Reopening a thread must retract the earlier 'resolved' row, or the finding stays recorded as accepted forever.\n if (reopened.length > 0) await feedbackRepo.clearResolvedFeedback(c.env as any, repositoryId, reopened);\n return await feedbackRepo.recordCommentFeedback(c.env as any, entries);\n } catch (error) {\n c.env.deps.platform.logger.warn('Could not record comment feedback', {\n eventName,\n repositoryId,\n error: error instanceof Error ? error.message : String(error),\n });\n return 0;\n }\n}\n\nexport async function handleGitHubWebhook(c: Context<ApiEnv>) {\n const eventName = c.req.header('x-github-event');\n const deliveryId = c.req.header('x-github-delivery');\n const signature = c.req.header('x-hub-signature-256');\n const rawBody = await c.req.text();\n\n if (!eventName || !deliveryId) {\n return jsonError('Missing GitHub webhook headers.', 400);\n }\n\n const verified = await c.env.deps.webhook.verifySignature(signature ?? null, rawBody);\n if (!verified) {\n return jsonError('Invalid webhook signature.', 401);\n }\n\n let payload: GitHubWebhookPayload;\n try {\n payload = JSON.parse(rawBody) as GitHubWebhookPayload;\n } catch {\n return jsonError('Invalid webhook JSON payload.', 400);\n }\n\n // Feedback deliveries carry the whole PR object plus diff hunks per comment; skip storing the payload (row is still written, so dedup still works).\n const isFeedbackEvent = isFeedbackGitHubWebhookEvent(eventName);\n\n const delivery = await c.env.deps.repositories.webhookDeliveries.recordWebhookDelivery(c.env as any, {\n deliveryId,\n eventName,\n owner: 'repository' in payload ? (payload as any).repository.owner.login : null,\n repo: 'repository' in payload ? (payload as any).repository.name : null,\n payload: isFeedbackEvent ? null : payload,\n });\n\n if (!delivery.inserted) {\n return c.json({ ok: true, duplicate: true }, 202);\n }\n\n const installationId = String((payload as any).installation?.id ?? '');\n if (!installationId || !('repository' in payload) || !payload.repository) {\n return c.json({ ok: true, ignored: true }, 202);\n }\n\n // Handled inline before loadRepoConfig: recording feedback needs no repo config, queue message, or Workflow, so skip that KV/DB cost entirely.\n if (isFeedbackEvent) {\n const recorded = await handleFeedbackEvent(c, {\n eventName,\n payload: payload as unknown as FeedbackWebhookPayload,\n repositoryId: delivery.repositoryId,\n });\n return c.json({ ok: true, feedback: true, recorded }, 202);\n }\n\n const normalized = c.env.deps.webhook.normalizePayload(eventName, payload);\n if (!normalized) {\n return c.json({ ok: true, ignored: true, eventName }, 202);\n }\n\n const repoConfig = await c.env.deps.config.loadRepoConfig({\n installationId,\n owner: (payload as any).repository.owner.login,\n repo: (payload as any).repository.name,\n });\n\n if (repoConfig.enabled === false) {\n return c.json({ ok: true, ignored: true, reason: 'repository_disabled' }, 202);\n }\n\n const extracted = c.env.deps.webhook.extractReviewRequest({\n eventName: normalized.eventName,\n payload: normalized.payload,\n botUsername: c.env.BOT_USERNAME,\n config: repoConfig.parsedJson,\n });\n\n if (extracted?.commitSha && extracted.baseSha) {\n const jobsRepo = c.env.deps.repositories.jobs;\n const existingJob = await jobsRepo.findExistingJobForHead(c.env as any, {\n owner: extracted.owner,\n repo: extracted.repo,\n prNumber: extracted.prNumber,\n commitSha: extracted.commitSha,\n trigger: extracted.trigger,\n });\n\n if (existingJob) {\n return c.json({\n ok: true,\n duplicate: true,\n message: existingJob.status === 'queued' ? 'queued' : 'duplicate',\n job: existingJob,\n }, 202);\n }\n\n const throttled = await c.env.deps.checkQuota?.({\n action: 'reviews.enqueue',\n subject: {\n installationId: extracted.installationId,\n owner: extracted.owner,\n repo: extracted.repo,\n },\n });\n if (throttled && !throttled.allowed) {\n // Deliberately 202, not 429: GitHub redelivers failed webhooks, so 4xx causes retry storms.\n return c.json({ ok: true, ignored: true, reason: 'quota_exceeded' }, 202);\n }\n\n const job = await jobsRepo.insertJob(c.env as any, {\n installationId: extracted.installationId,\n owner: extracted.owner,\n repo: extracted.repo,\n prNumber: extracted.prNumber,\n prTitle: extracted.prTitle,\n prAuthor: extracted.prAuthor,\n commitSha: extracted.commitSha,\n baseSha: extracted.baseSha,\n trigger: extracted.trigger,\n headRef: extracted.headRef,\n baseRef: extracted.baseRef,\n configSnapshot: repoConfig.parsedJson,\n });\n\n await jobsRepo.supersedeOlderJobs(c.env as any, {\n installationId: extracted.installationId,\n owner: extracted.owner,\n repo: extracted.repo,\n prNumber: extracted.prNumber,\n newJobId: job.id,\n });\n\n await c.env.deps.platform.enqueueReviewJob({\n jobId: job.id,\n deliveryId,\n phase: 'prepare',\n requestId: c.get('requestId'),\n });\n\n return c.json({ ok: true, message: 'queued', job }, 202);\n }\n\n // Events without a concrete job (e.g. PR close cleanup, mention lookups) still get handled by the worker.\n await c.env.deps.platform.enqueueReviewJob({\n deliveryId,\n eventName,\n requestId: c.get('requestId'),\n } as any);\n\n return c.json({ ok: true, message: 'queued' }, 202);\n}\n\nexport function createWebhookRouter() {\n const app = new Hono<ApiEnv>();\n\n app.post('/', handleGitHubWebhook);\n\n return app;\n}\n","import { isSupportedTimeZone } from '@codraoss/schema/timezone';\nimport { Hono } from 'hono';\nimport { z } from 'zod';\nimport { jsonError } from '../../http';\nimport type { ApiEnv } from '../../ports';\nimport { requirePermission } from '../../middleware/authorize';\n\nconst emailSchema = z.strictObject({\n email: z.string().trim().email().max(254),\n});\n\n// Fields are independently optional (at least one required); timezone null means \"follow the browser\", else must be an Intl-known zone.\nconst accountUpdateSchema = z.strictObject({\n name: z.string().trim().min(1).max(120).optional(),\n timezone: z.string().trim().min(1).max(64).refine(isSupportedTimeZone, {\n message: 'Unknown time zone.',\n }).nullable().optional(),\n}).refine(\n (body) => body.name !== undefined || body.timezone !== undefined,\n { message: 'Nothing to update.' },\n);\n\nexport function createAuthApiRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/session', async (c) => {\n const sessionUser = c.get('sessionUser');\n if (!sessionUser) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n // Omitted when nothing is restricted, which the dashboard reads as \"every action allowed\".\n const permissions = await c.env.deps.authz?.listPermissions?.(sessionUser);\n\n return c.json(permissions ? { user: sessionUser, permissions } : { user: sessionUser });\n });\n\n app.get('/account', async (c) => {\n const sessionUser = c.get('sessionUser');\n if (!sessionUser) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n const accounts = c.env.deps.repositories.accounts;\n const githubUserId = Number(sessionUser.providerUserId);\n\n // Self-heals for sessions created before the account_settings table existed.\n let account = await accounts.getAccountSettings(c.env as any, githubUserId);\n if (!account) {\n account = await accounts.upsertAccountSettings(c.env as any, {\n githubUserId,\n githubUsername: sessionUser.login,\n accountName: sessionUser.name,\n accountEmail: sessionUser.email,\n });\n }\n\n return c.json({ account });\n });\n\n app.patch('/account', async (c) => {\n const denied = await requirePermission(c, 'account.write');\n if (denied) return denied;\n const sessionUser = c.get('sessionUser');\n if (!sessionUser) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n const body = await c.req.json().catch(() => null);\n const parsed = accountUpdateSchema.safeParse(body);\n if (!parsed.success) {\n const issue = parsed.error.issues[0]?.message;\n return jsonError(\n issue && issue !== 'Invalid input' ? issue : 'Enter a name (1-120 characters).',\n 400,\n );\n }\n\n const accounts = c.env.deps.repositories.accounts;\n const githubUserId = Number(sessionUser.providerUserId);\n\n // Ensure a row exists first (self-heal for pre-existing sessions), then update.\n const existing = await accounts.getAccountSettings(c.env as any, githubUserId);\n if (!existing) {\n await accounts.upsertAccountSettings(c.env as any, {\n githubUserId,\n githubUsername: sessionUser.login,\n accountName: sessionUser.name,\n accountEmail: sessionUser.email,\n });\n }\n\n const account = await accounts.updateAccountSettings(c.env as any, githubUserId, {\n accountName: parsed.data.name,\n timezone: parsed.data.timezone,\n });\n return c.json({ account });\n });\n\n app.get('/updates-email', async (c) => {\n const sessionUser = c.get('sessionUser');\n if (!sessionUser) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n const githubUserId = Number(sessionUser.providerUserId);\n const preference = await c.env.deps.platform.getUpdatesEmailPreference(githubUserId);\n return c.json({\n status: preference?.status ?? 'pending',\n email: preference?.email ?? null,\n updatedAt: preference?.updatedAt ?? null,\n });\n });\n\n app.post('/updates-email', async (c) => {\n const denied = await requirePermission(c, 'account.updatesEmail.write');\n if (denied) return denied;\n const sessionUser = c.get('sessionUser');\n if (!sessionUser) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n const body = await c.req.json().catch(() => null);\n const parsed = emailSchema.safeParse(body);\n if (!parsed.success) {\n return jsonError('Enter a valid email address.', 400);\n }\n\n const platform = c.env.deps.platform;\n const githubUserId = Number(sessionUser.providerUserId);\n\n const existingPreference = await platform.getUpdatesEmailPreference(githubUserId);\n if (existingPreference) {\n return c.json({\n status: existingPreference.status,\n email: existingPreference.email,\n updatedAt: existingPreference.updatedAt,\n });\n }\n\n const synced = await platform.syncUpdatesEmail(githubUserId, parsed.data.email);\n if (!synced) {\n return jsonError('Could not save updates email right now.', 502);\n }\n\n const preference = await platform.getUpdatesEmailPreference(githubUserId);\n\n return c.json({\n status: preference?.status ?? 'pending',\n email: preference?.email ?? null,\n updatedAt: preference?.updatedAt ?? null,\n });\n });\n\n return app;\n}\n","import type { Context } from 'hono';\nimport type { ApiAction } from '@codraoss/schema/api';\nimport type { ApiEnv, QuotaCheckInput } from '../ports';\n\n// Guards return a Response to short-circuit with, or null to continue.\n// Both are inert when the corresponding port is not provided.\n\nexport async function requirePermission(\n c: Context<ApiEnv>,\n action: ApiAction,\n resource?: { type: string; id?: string },\n): Promise<Response | null> {\n const authz = c.env.deps.authz;\n if (!authz) return null;\n\n const user = c.get('sessionUser');\n if (!user) {\n return c.json({ error: 'Unauthorized', code: 'unauthorized', action, reason: null }, 401);\n }\n\n const result = await authz.authorize({ user, action, resource });\n if (result.allowed) return null;\n\n return c.json(\n { error: 'Forbidden', code: 'forbidden', action, reason: result.reason ?? null },\n 403,\n );\n}\n\nexport async function requireQuota(\n c: Context<ApiEnv>,\n input: Omit<QuotaCheckInput, 'user'>,\n): Promise<Response | null> {\n const checkQuota = c.env.deps.checkQuota;\n if (!checkQuota) return null;\n\n const user = c.get('sessionUser') ?? undefined;\n const result = await checkQuota({ ...input, user });\n if (result.allowed) return null;\n\n const headers = result.retryAfterSeconds\n ? { 'Retry-After': String(result.retryAfterSeconds) }\n : undefined;\n\n return c.json(\n {\n error: 'Too many requests',\n code: 'quota_exceeded',\n action: input.action,\n reason: result.reason ?? null,\n },\n 429,\n headers,\n );\n}\n","import { Hono } from 'hono';\nimport type { Context } from 'hono';\nimport { defaultRepoConfig, findingLabelSchema, jobsQuerySchema } from '@codraoss/schema';\nimport { jsonError } from '../../http';\nimport { parseUnifiedDiff } from '@codraoss/core/diff';\nimport { buildFileReviewPrompts, changelogExcerptFromDiff, wantsFileContext } from '@codraoss/core/prompts/file-review';\nimport type { ApiEnv } from '../../ports';\nimport { requirePermission, requireQuota } from '../../middleware/authorize';\n\n// Best-effort: .get()/.terminate() throw if instance is gone/already terminal; both non-fatal.\nasync function terminateJobWorkflow(c: Context<ApiEnv>, job: { id: string; workflowInstanceId?: string | null }) {\n // Goes through platform port; handlers must not touch bindings directly.\n await c.env.deps.platform.terminateJobWorkflow(job);\n}\n\nfunction jobEtag(input: { id: string; status: string; updatedAt: string; fileCount: number; commentCount: number }) {\n return `\"job-${input.id}-${input.status}-${input.fileCount}-${input.commentCount}-${new Date(input.updatedAt).getTime()}\"`;\n}\n\n// Cloudflare's edge rewrites strong ETags to weak (W/\"...\") when it compresses the response, so the\n// client echoes back a weak validator; compare weakly or the 304 path never fires in production.\nfunction etagMatches(header: string | undefined, etag: string) {\n if (!header) return false;\n const bare = etag.replace(/^W\\//, '');\n return header.split(',').some((candidate) => candidate.trim().replace(/^W\\//, '') === bare);\n}\n\nfunction getExecutionContext(c: Context<ApiEnv>) {\n try {\n return c.executionCtx;\n } catch {\n return undefined;\n }\n}\n\nexport function createJobsRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/', async (c) => {\n const denied = await requirePermission(c, 'jobs.read');\n if (denied) return denied;\n c.env.deps.platform.scheduleBestEffortJobMaintenance(getExecutionContext(c));\n\n const rawQuery = c.req.query();\n const query = jobsQuerySchema.parse(rawQuery);\n\n const result = await c.env.deps.repositories.jobs.listJobs(c.env as any, query as any);\n return c.json(result);\n });\n\n app.get('/:id', async (c) => {\n const denied = await requirePermission(c, 'jobs.read', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n c.env.deps.platform.scheduleBestEffortJobMaintenance(getExecutionContext(c));\n\n const job = await c.env.deps.repositories.jobs.getJobDetail(c.env as any, c.req.param('id'));\n if (!job) {\n return jsonError('Job not found.', 404);\n }\n\n const etag = jobEtag(job);\n const lastModified = new Date(job.updatedAt).toUTCString();\n if (etagMatches(c.req.header('if-none-match'), etag)) {\n return new Response(null, {\n status: 304,\n headers: {\n ETag: etag,\n 'Last-Modified': lastModified,\n },\n });\n }\n\n const response = c.json({ job });\n response.headers.set('ETag', etag);\n response.headers.set('Last-Modified', lastModified);\n response.headers.set('Cache-Control', 'private, no-cache');\n return response;\n });\n\n // diff_input isn't persisted; rebuilt from the job's own base/head commits (not the live PR), via KV cache.\n app.get('/:id/diffs', async (c) => {\n const denied = await requirePermission(c, 'jobs.read', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const job = await c.env.deps.repositories.jobs.getJobDetail(c.env as any, c.req.param('id'));\n if (!job) {\n return jsonError('Job not found.', 404);\n }\n\n const config = job.configSnapshot ?? defaultRepoConfig;\n const github = c.env.deps.gitProvider.createService(job.installationId);\n\n let rawDiff: string;\n try {\n rawDiff = await c.env.deps.platform.getOrFetchRawDiffForCompletedJob(\n c.env.deps.platform.createReviewRuntime(),\n { id: job.id, owner: job.owner, repo: job.repo, baseSha: job.baseSha, commitSha: job.commitSha },\n github,\n );\n } catch (error) {\n c.env.deps.platform.logger.warn(`Could not reconstruct diff for job ${job.id}`, error instanceof Error ? error : new Error(String(error)));\n return c.json({ diffs: {} });\n }\n\n // Reconstructs the prompt the model actually saw, so it needs the PR description too.\n let prDescription: string | null = null;\n try {\n prDescription = (await github.getPullRequest(job.owner, job.repo, job.prNumber)).body ?? null;\n } catch (error) {\n // Best-effort: missing description degrades fidelity, doesn't fail the view.\n c.env.deps.platform.logger.warn(`Could not load the PR body for job ${job.id}; prompts will omit the description`,\n error instanceof Error ? error : new Error(String(error)));\n }\n\n // Full PR diff, not just reviewed files, so file count matches GitHub mid-review.\n const diffs: Record<string, string> = {};\n const parsedFiles = parseUnifiedDiff(rawDiff, config.review);\n const changelogExcerpt = changelogExcerptFromDiff(parsedFiles);\n for (const file of parsedFiles) {\n if (file.isDeleted || file.isBinary || !file.path) continue;\n const { userPrompt } = buildFileReviewPrompts({\n file,\n prTitle: job.prTitle,\n prDescription,\n changelogExcerpt,\n config: config.review,\n });\n const hadContext = wantsFileContext(file, config.review.full_file_context);\n diffs[file.path] = hadContext\n ? `${userPrompt}\\n\\n[The full file at the reviewed commit was included here at review time; it is omitted from this preview.]`\n : userPrompt;\n }\n\n const response = c.json({ diffs });\n response.headers.set('Cache-Control', 'private, max-age=60');\n return response;\n });\n\n // inherit=true links retryOfJobId and reuses done file reviews; false reviews everything.\n async function startReplacementJob(c: Context<ApiEnv>, rawSource: any, options: { inherit: boolean }) {\n const jobs = c.env.deps.repositories.jobs;\n const source = jobs.mapJob(rawSource);\n let configSnapshot;\n try {\n const currentConfig = await c.env.deps.config.loadRepoConfig({\n installationId: source.installationId,\n owner: source.owner,\n repo: source.repo,\n });\n configSnapshot = currentConfig?.parsedJson ?? defaultRepoConfig;\n } catch (e) {\n configSnapshot = defaultRepoConfig;\n }\n\n const job = await jobs.insertJob(c.env as any, {\n installationId: source.installationId,\n owner: source.owner,\n repo: source.repo,\n prNumber: source.prNumber,\n prTitle: source.prTitle,\n prAuthor: source.prAuthor,\n commitSha: source.commitSha,\n baseSha: jobs.bytesToHex(rawSource.base_sha), // base_sha is only in raw row/detail\n trigger: 'retry',\n headRef: rawSource.head_ref,\n baseRef: rawSource.base_ref,\n configSnapshot,\n ...(options.inherit ? { retryOfJobId: source.id } : {}),\n });\n\n await jobs.supersedeOlderJobs(c.env as any, {\n installationId: source.installationId,\n owner: source.owner,\n repo: source.repo,\n prNumber: source.prNumber,\n newJobId: job.id,\n });\n\n await c.env.deps.platform.enqueueReviewJob({\n jobId: job.id,\n deliveryId: crypto.randomUUID(),\n phase: 'prepare',\n requestId: c.get('requestId'),\n });\n\n return job;\n }\n\n app.post('/:id/retry', async (c) => {\n const denied = await requirePermission(c, 'jobs.retry', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const throttled = await requireQuota(c, { action: 'jobs.retry' });\n if (throttled) return throttled;\n const jobs = c.env.deps.repositories.jobs;\n const rawSource = await jobs.getJobForProcessing(c.env as any, c.req.param('id'));\n if (!rawSource) {\n return jsonError('Job not found.', 404);\n }\n const job = await startReplacementJob(c, rawSource, { inherit: true });\n return c.json({ job }, 202);\n });\n\n // No inheritance; stops the current run first so two workflows can't race.\n app.post('/:id/rerun', async (c) => {\n const denied = await requirePermission(c, 'jobs.rerun', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const throttled = await requireQuota(c, { action: 'jobs.rerun' });\n if (throttled) return throttled;\n const jobs = c.env.deps.repositories.jobs;\n const rawSource = await jobs.getJobForProcessing(c.env as any, c.req.param('id'));\n if (!rawSource) {\n return jsonError('Job not found.', 404);\n }\n const source = jobs.mapJob(rawSource);\n if (source.status === 'queued' || source.status === 'running') {\n await terminateJobWorkflow(c, source);\n }\n const job = await startReplacementJob(c, rawSource, { inherit: false });\n return c.json({ job }, 202);\n });\n\n app.post('/:id/stop', async (c) => {\n const denied = await requirePermission(c, 'jobs.stop', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const jobs = c.env.deps.repositories.jobs;\n const id = c.req.param('id');\n const raw = await jobs.getJobForProcessing(c.env as any, id);\n if (!raw) {\n return jsonError('Job not found.', 404);\n }\n const job = jobs.mapJob(raw);\n if (job.status !== 'queued' && job.status !== 'running') {\n return jsonError('Only a queued or running job can be stopped.', 409);\n }\n await terminateJobWorkflow(c, job);\n await jobs.cancelJob(c.env as any, id);\n const updated = await jobs.getJobForProcessing(c.env as any, id);\n return c.json({ job: updated ? jobs.mapJob(updated) : job }, 200);\n });\n\n // \"wrong\" suppresses this finding repo-wide; \"right\" is measurement only.\n app.put('/:id/findings/:fingerprint/label', async (c) => {\n const denied = await requirePermission(c, 'jobs.label', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const jobId = c.req.param('id');\n const fingerprint = c.req.param('fingerprint');\n\n const parsed = findingLabelSchema.safeParse(await c.req.json().catch(() => null));\n if (!parsed.success) return jsonError('Body must be {\"label\":\"right\"|\"wrong\"}.', 400);\n\n const target = await c.env.deps.repositories.fileReviews.getFindingLabelTarget(c.env as any, jobId, fingerprint);\n if (!target) return jsonError('Finding not found on this job.', 404);\n\n await c.env.deps.repositories.commentFeedback.upsertDashboardFeedback(c.env as any, {\n repositoryId: target.repository_id,\n prNumber: target.pr_number,\n fingerprint,\n anchorHash: target.anchor_hash,\n // Keeps rejection valid even if the model rewords the title.\n fingerprintV2: target.fingerprint_v2,\n jobId,\n labelledBy: c.get('sessionUser')?.providerUserId ? Number(c.get('sessionUser')?.providerUserId) : null,\n outcome: parsed.data.label === 'wrong' ? 'marked_wrong' : 'marked_right',\n });\n\n return c.json({ label: parsed.data.label }, 200);\n });\n\n // Scoped to dashboard rows; a real GitHub deletion still stays recorded.\n app.delete('/:id/findings/:fingerprint/label', async (c) => {\n const denied = await requirePermission(c, 'jobs.label', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const jobId = c.req.param('id');\n const fingerprint = c.req.param('fingerprint');\n\n const target = await c.env.deps.repositories.fileReviews.getFindingLabelTarget(c.env as any, jobId, fingerprint);\n if (!target) return jsonError('Finding not found on this job.', 404);\n\n await c.env.deps.repositories.commentFeedback.clearDashboardFeedback(c.env as any, target.repository_id, fingerprint);\n return c.body(null, 204);\n });\n\n app.delete('/:id', async (c) => {\n const denied = await requirePermission(c, 'jobs.delete', { type: 'job', id: c.req.param('id') });\n if (denied) return denied;\n const jobs = c.env.deps.repositories.jobs;\n const id = c.req.param('id');\n const raw = await jobs.getJobForProcessing(c.env as any, id);\n if (!raw) {\n return jsonError('Job not found.', 404);\n }\n const job = jobs.mapJob(raw);\n if (job.status === 'queued' || job.status === 'running') {\n await terminateJobWorkflow(c, job);\n }\n await jobs.deleteJob(c.env as any, id);\n return c.body(null, 204);\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport { z } from 'zod';\nimport type { ApiEnv } from '../../ports';\nimport { requirePermission, requireQuota } from '../../middleware/authorize';\nimport { jsonError } from '../../http';\nimport { repoConfigSchema } from '@codraoss/schema';\n\nconst repoConfigPatchSchema = z\n .strictObject({\n enabled: z.boolean().optional(),\n review: repoConfigSchema.shape.review.optional(),\n model: repoConfigSchema.shape.model.optional(),\n })\n .refine(\n (patch) => patch.enabled !== undefined || patch.review !== undefined || patch.model !== undefined,\n 'Repository config patch cannot be empty.',\n );\n\nasync function mapWithConcurrency<T, R>(\n items: T[],\n limit: number,\n mapper: (item: T) => Promise<R>,\n) {\n const results: R[] = new Array(items.length);\n let nextIndex = 0;\n\n async function worker() {\n while (nextIndex < items.length) {\n const currentIndex = nextIndex;\n nextIndex += 1;\n results[currentIndex] = await mapper(items[currentIndex]);\n }\n }\n\n await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));\n return results;\n}\n\nexport function createReposRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/', async (c) => {\n const denied = await requirePermission(c, 'repos.read');\n if (denied) return denied;\n const repos = await c.env.deps.repositories.repoConfigs.listRepoConfigs(c.env as any);\n return c.json({ repos });\n });\n\n app.get('/install', async (c) => {\n const denied = await requirePermission(c, 'repos.install');\n if (denied) return denied;\n try {\n return c.redirect(await c.env.deps.gitProvider.getAppInstallationUrl(), 302);\n } catch (error) {\n c.env.deps.platform.logger.error('Failed to resolve GitHub App installation URL:', error);\n return jsonError(`Failed to resolve GitHub App installation URL: ${error instanceof Error ? error.message : String(error)}`, 500);\n }\n });\n\n app.post('/sync', async (c) => {\n const denied = await requirePermission(c, 'repos.sync');\n if (denied) return denied;\n const throttled = await requireQuota(c, { action: 'repos.sync' });\n if (throttled) return throttled;\n try {\n const installations = await c.env.deps.gitProvider.listInstallations();\n const synced: string[] = [];\n const repoConfigs = c.env.deps.repositories.repoConfigs;\n\n for (const inst of installations) {\n const github = c.env.deps.gitProvider.createService(String(inst.id));\n const repos = await github.listRepositories();\n\n const results = await mapWithConcurrency(\n repos,\n 5,\n async (repo: any) => {\n const owner = repo.owner.login;\n const name = repo.name;\n const fullName = `${owner}/${name}`;\n try {\n await repoConfigs.syncRepoConfig(c.env as any, {\n installationId: String(inst.id),\n owner,\n repo: name,\n });\n return fullName;\n } catch (repoError) {\n c.env.deps.platform.logger.error(`Failed to sync repo: ${fullName}`, repoError);\n return null;\n }\n },\n );\n\n const installationSynced: string[] = [];\n for (const res of results) {\n if (res) {\n synced.push(res);\n installationSynced.push(res);\n }\n }\n \n await repoConfigs.deleteStaleRepoConfigs(c.env as any, String(inst.id), installationSynced);\n }\n\n return c.json({ ok: true, synced });\n } catch (error) {\n c.env.deps.platform.logger.error('Manual sync failed:', error);\n return jsonError(`Sync failed: ${error instanceof Error ? error.message : String(error)}`, 500);\n }\n });\n\n app.get('/:owner/:repo/config', async (c) => {\n const denied = await requirePermission(c, 'repos.read', { type: 'repo', id: `${c.req.param('owner')}/${c.req.param('repo')}` });\n if (denied) return denied;\n const repo = await c.env.deps.repositories.repoConfigs.getRepoConfigRecord(c.env as any, c.req.param('owner'), c.req.param('repo'));\n if (!repo) {\n return jsonError('Repository config not found.', 404);\n }\n\n return c.json({ repo });\n });\n \n app.patch('/:owner/:repo/config', async (c) => {\n const denied = await requirePermission(c, 'repos.config.write', { type: 'repo', id: `${c.req.param('owner')}/${c.req.param('repo')}` });\n if (denied) return denied;\n const { owner, repo } = c.req.param();\n const body = await c.req.json();\n const parsedPatch = repoConfigPatchSchema.safeParse(body);\n if (!parsedPatch.success) {\n return jsonError('Invalid repository config patch.', 400);\n }\n\n const repoConfigs = c.env.deps.repositories.repoConfigs;\n const existing = await repoConfigs.getRepoConfigRecord(c.env as any, owner, repo);\n \n if (!existing) {\n return jsonError('Repository config not found.', 404);\n }\n\n const patch = parsedPatch.data;\n const hasConfigPatch = patch.review !== undefined || patch.model !== undefined;\n\n if (!hasConfigPatch && patch.enabled !== undefined) {\n await repoConfigs.updateRepoConfigEnabled(c.env as any, {\n owner,\n repo,\n enabled: patch.enabled,\n });\n await c.env.deps.config.invalidateRepoConfigCache(owner, repo);\n return c.json({ ok: true });\n }\n\n const configPatch: Partial<z.infer<typeof repoConfigSchema>> = {};\n if (patch.review !== undefined) {\n configPatch.review = patch.review;\n }\n if (patch.model !== undefined) {\n configPatch.model = patch.model;\n }\n \n const updatedParsedJson = {\n ...existing.parsedJson,\n ...configPatch,\n };\n const parsedConfig = repoConfigSchema.safeParse(updatedParsedJson);\n\n if (!parsedConfig.success) {\n return jsonError('Invalid repository config.', 400);\n }\n \n await repoConfigs.upsertRepoConfig(c.env as any, {\n installationId: existing.installationId,\n owner,\n repo,\n parsedJson: parsedConfig.data,\n enabled: patch.enabled,\n });\n await c.env.deps.config.invalidateRepoConfigCache(owner, repo);\n \n return c.json({ ok: true });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { ApiEnv } from '../../ports';\nimport { requirePermission } from '../../middleware/authorize';\n\nexport function createStatsRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/', async (c) => {\n const denied = await requirePermission(c, 'stats.read');\n if (denied) return denied;\n const daysParam = c.req.query('days');\n const days = daysParam ? parseInt(daysParam, 10) : 30;\n // Grouped in the caller's display zone so the trend matches timestamps shown elsewhere; getStats falls back to UTC if invalid.\n const timeZone = c.req.query('tz') ?? 'UTC';\n const stats = await c.env.deps.repositories.stats.getStats(c.env as any, days, timeZone);\n return c.json({ stats });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport { z } from 'zod';\nimport { jsonError } from '../../http';\nimport { llmApiFormats } from '@codraoss/schema';\nimport type { ApiEnv } from '../../ports';\nimport { requirePermission, requireQuota } from '../../middleware/authorize';\n\nconst apiFormatSchema = z.enum(llmApiFormats);\nconst positiveIntegerSchema = z.number().int().positive().finite();\nconst modelIdSchema = z.string().trim().min(1);\nconst optionalUrlSchema = z.string().trim().url().nullable().optional();\nconst providerIdSchema = z.string().uuid();\n\nconst providerCreateSchema = z.strictObject({\n name: z.string().trim().min(1),\n apiFormat: apiFormatSchema,\n baseUrl: optionalUrlSchema,\n apiKey: z.string().optional(),\n enabled: z.boolean().default(true),\n});\n\n// `.extend()` carries the parent's strictness through, so no second `.strict()` is needed here.\nconst providerUpdateSchema = providerCreateSchema.extend({\n clearApiKey: z.boolean().optional(),\n});\n\nconst modelConfigUpdateSchema = z.strictObject({\n providerId: providerIdSchema,\n modelName: z.string().trim().min(1),\n});\n\nconst globalModelConfigSchema = z.strictObject({\n main: modelIdSchema.nullable().default(null),\n fallbacks: z.array(modelIdSchema).nullable().default([]),\n size_overrides: z\n .array(\n z.strictObject({\n max_lines: positiveIntegerSchema,\n model: modelIdSchema,\n fallbacks: z.array(modelIdSchema).optional(),\n }),\n )\n .nullable()\n .optional(),\n});\n\nfunction requiresExplicitBaseUrl(apiFormat: z.infer<typeof apiFormatSchema>, baseUrl: string | null | undefined) {\n return apiFormat === 'vertex' && !baseUrl;\n}\n\nfunction readModelIdParam(value: string) {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nexport function createModelsRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/', async (c) => {\n const denied = await requirePermission(c, 'models.read');\n if (denied) return denied;\n const modelConfigsRepo = c.env.deps.repositories.modelConfigs;\n const [providers, configs] = await Promise.all([\n modelConfigsRepo.listLlmProviders(c.env as any),\n modelConfigsRepo.listModelConfigs(c.env as any),\n ]);\n return c.json({ providers, configs });\n });\n\n app.post('/sync', async (c) => {\n const denied = await requirePermission(c, 'models.sync');\n if (denied) return denied;\n const modelConfigsRepo = c.env.deps.repositories.modelConfigs;\n const syncErrors = await c.env.deps.modelRunner.syncProviderModelCatalog();\n const [providers, configs] = await Promise.all([\n modelConfigsRepo.listLlmProviders(c.env as any),\n modelConfigsRepo.listModelConfigs(c.env as any),\n ]);\n return c.json({ providers, configs, syncErrors });\n });\n\n app.get('/global', async (c) => {\n const denied = await requirePermission(c, 'models.read');\n if (denied) return denied;\n const config = await c.env.deps.config.getGlobalConfig();\n return c.json({ config });\n });\n\n app.patch('/global', async (c) => {\n const denied = await requirePermission(c, 'models.global.write');\n if (denied) return denied;\n const body = await c.req.json();\n const parsed = globalModelConfigSchema.safeParse(body);\n if (!parsed.success) {\n return jsonError('Invalid global model config.', 400);\n }\n\n await c.env.deps.config.updateGlobalConfig(parsed.data);\n return c.json({ ok: true });\n });\n\n app.post('/providers', async (c) => {\n const denied = await requirePermission(c, 'models.provider.create');\n if (denied) return denied;\n const parsed = providerCreateSchema.safeParse(await c.req.json());\n if (!parsed.success) {\n return jsonError('Invalid provider config.', 400);\n }\n\n const input = parsed.data;\n if (requiresExplicitBaseUrl(input.apiFormat, input.baseUrl)) {\n return jsonError('Vertex AI requires a base URL with your GCP project ID and region, e.g. https://us-central1-aiplatform.googleapis.com/v1/projects/YOUR_PROJECT_ID/locations/us-central1', 400);\n }\n\n try {\n const provider = await c.env.deps.modelRunner.createProviderWithSecret(input);\n return c.json({ provider }, 201);\n } catch (error) {\n const err = error as any;\n if (err.isUniqueNameError) {\n return jsonError(`Provider ${input.name} already exists. Update the existing provider instead.`, 409);\n }\n if (err.isEncryptionConfigError) {\n return jsonError(err.message || 'LLM encryption is not configured.', 400);\n }\n if (err.isKeyRequiredError) {\n return jsonError(`Provider ${input.name} needs an API key before it can be enabled.`, 400);\n }\n throw error;\n }\n });\n\n app.patch('/providers/:id', async (c) => {\n const denied = await requirePermission(c, 'models.provider.update', { type: 'llmProvider', id: c.req.param('id') });\n if (denied) return denied;\n const id = c.req.param('id');\n if (!providerIdSchema.safeParse(id).success) {\n return jsonError('Invalid provider id.', 400);\n }\n\n const parsed = providerUpdateSchema.safeParse(await c.req.json());\n if (!parsed.success) {\n return jsonError('Invalid provider config.', 400);\n }\n\n const input = parsed.data;\n if (requiresExplicitBaseUrl(input.apiFormat, input.baseUrl)) {\n return jsonError('Vertex AI requires a base URL with your GCP project ID and region, e.g. https://us-central1-aiplatform.googleapis.com/v1/projects/YOUR_PROJECT_ID/locations/us-central1', 400);\n }\n\n try {\n const provider = await c.env.deps.modelRunner.updateProviderWithSecret(id, input);\n if (!provider) return jsonError('Provider not found.', 404);\n return c.json({ provider });\n } catch (error) {\n const err = error as any;\n if (err.isUniqueNameError) {\n return jsonError(`Provider ${input.name} already exists. Choose a different provider name.`, 409);\n }\n if (err.isEncryptionConfigError) {\n return jsonError(err.message || 'LLM encryption is not configured.', 400);\n }\n if (err.isKeyRequiredError) {\n return jsonError(`Provider ${input.name} needs an API key before it can be enabled.`, 400);\n }\n throw error;\n }\n });\n\n app.delete('/providers/:id', async (c) => {\n const denied = await requirePermission(c, 'models.provider.delete', { type: 'llmProvider', id: c.req.param('id') });\n if (denied) return denied;\n const id = c.req.param('id');\n if (!providerIdSchema.safeParse(id).success) {\n return jsonError('Invalid provider id.', 400);\n }\n\n const result = await c.env.deps.repositories.modelConfigs.deleteLlmProvider(c.env as any, id);\n if (!result.deleted) {\n return jsonError(result.reason ?? 'Provider not found.', result.reason ? 409 : 404);\n }\n return c.json({ ok: true });\n });\n\n app.post('/:id/test', async (c) => {\n const denied = await requirePermission(c, 'models.test', { type: 'modelConfig', id: c.req.param('id') });\n if (denied) return denied;\n const throttled = await requireQuota(c, { action: 'models.test' });\n if (throttled) return throttled;\n const modelId = readModelIdParam(c.req.param('id'));\n const parsedModelId = modelIdSchema.safeParse(modelId);\n if (!parsedModelId.success) {\n return jsonError('Invalid model id.', 400);\n }\n\n try {\n const response = await c.env.deps.modelRunner.testConnection(parsedModelId.data);\n return c.json(response);\n } catch (error) {\n const err = error as any;\n if (err.isNotFoundError) return jsonError('Model not found.', 404);\n if (err.isDisabledError || err.isMissingKeyError) return jsonError(err.message, 400);\n \n return jsonError(\n err.message || 'Connection test failed.',\n err.status || 502,\n );\n }\n });\n\n app.post('/:id', async (c) => {\n const denied = await requirePermission(c, 'models.mapping.write', { type: 'modelConfig', id: c.req.param('id') });\n if (denied) return denied;\n const modelId = readModelIdParam(c.req.param('id'));\n const parsedModelId = modelIdSchema.safeParse(modelId);\n if (!parsedModelId.success) {\n return jsonError('Invalid model id.', 400);\n }\n\n const body = await c.req.json();\n const parsed = modelConfigUpdateSchema.safeParse(body);\n if (!parsed.success) {\n return jsonError('Invalid model config.', 400);\n }\n\n const saved = await c.env.deps.repositories.modelConfigs.updateModelConfig(c.env as any, {\n modelId: parsedModelId.data,\n providerId: parsed.data.providerId,\n modelName: parsed.data.modelName,\n });\n\n if (!saved) return jsonError('Provider not found.', 404);\n return c.json({ ok: true, config: saved });\n });\n\n app.delete('/:id', async (c) => {\n const denied = await requirePermission(c, 'models.mapping.write', { type: 'modelConfig', id: c.req.param('id') });\n if (denied) return denied;\n const modelId = readModelIdParam(c.req.param('id'));\n const parsedModelId = modelIdSchema.safeParse(modelId);\n if (!parsedModelId.success) {\n return jsonError('Invalid model id.', 400);\n }\n\n const deleted = await c.env.deps.repositories.modelConfigs.deleteModelConfig(c.env as any, parsedModelId.data);\n if (!deleted) return jsonError('Model not found.', 404);\n return c.json({ ok: true });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport { z } from 'zod';\nimport type { ApiEnv } from '../../ports';\nimport { requirePermission } from '../../middleware/authorize';\nimport { jsonError } from '../../http';\nimport { reviewConcurrencyLevels, reviewMaxCommentsOptions, reviewMaxFilesRange, reviewSettingsSchema } from '@codraoss/schema';\n\nconst reviewSettingsPatchSchema = z.strictObject({\n concurrencyLevel: z.enum(reviewConcurrencyLevels).optional(),\n maxComments: z.number().int().refine(\n (value) => (reviewMaxCommentsOptions as readonly number[]).includes(value),\n 'Invalid max comments value.',\n ).optional(),\n maxFiles: z.number().int().min(reviewMaxFilesRange.min).max(reviewMaxFilesRange.max).optional(),\n}).refine(\n (settings) => Object.values(settings).some((value) => value !== undefined),\n 'At least one setting must be provided.',\n);\n\nexport function createSettingsRouter() {\n const app = new Hono<ApiEnv>();\n\n app.get('/', async (c) => {\n const denied = await requirePermission(c, 'settings.read');\n if (denied) return denied;\n const settings = await c.env.deps.repositories.appSettings.getReviewSettings(c.env as any);\n return c.json({ settings });\n });\n\n app.patch('/', async (c) => {\n const denied = await requirePermission(c, 'settings.write');\n if (denied) return denied;\n const body = await c.req.json().catch(() => null);\n const parsed = reviewSettingsPatchSchema.safeParse(body);\n if (!parsed.success) {\n return jsonError('Invalid review settings.', 400);\n }\n\n const current = await c.env.deps.repositories.appSettings.getReviewSettings(c.env as any);\n const next = reviewSettingsSchema.parse({ ...current, ...parsed.data });\n await c.env.deps.repositories.appSettings.updateReviewSettings(c.env as any, next);\n return c.json({ ok: true, settings: next });\n });\n\n return app;\n}\n","\nexport interface PlatformDeps {\n sessionStore: SessionStore;\n kv: KvCompat;\n db: DbEnv;\n identityProvider?: IdentityProvider;\n \n enqueueReviewJob: (input: any) => Promise<void>;\n terminateJobWorkflow: (job: { id: string; workflowInstanceId?: string | null }) => Promise<void>;\n scheduleBestEffortJobMaintenance: (executionContext?: any) => void;\n createReviewRuntime: () => ReviewRuntime;\n getOrFetchRawDiffForCompletedJob: (runtime: ReviewRuntime, job: any, github: any) => Promise<string>;\n \n logger: PlatformPort['logger'];\n getSecret: (key: string) => Promise<string | null>;\n \n aiBinding?: any;\n appUrl: string;\n botUsername: string;\n environment: string;\n authCallbackUrl: string;\n githubClientId: string;\n githubClientSecret: string;\n githubAppSlug?: string;\n dashboardAllowedUsers: string;\n appPrivateKey: string;\n githubAppId: string;\n githubAppWebhookSecret: string;\n llmConfigEncryptionKey: string;\n cfApiToken?: string;\n cfAccountId?: string;\n}\n\nimport type { ApiRouterDeps, PlatformPort } from './ports';\nimport type { SessionStore, ReviewRuntime, IdentityProvider } from '@codraoss/core/ports';\nimport type { KvCompat } from './platform/config';\nimport type { DbEnv } from '@codraoss/db/env';\n\n\nimport * as dbAccounts from '@codraoss/db/accounts';\nimport * as dbJobs from '@codraoss/db/jobs';\nimport * as dbFileReviews from '@codraoss/db/file-reviews';\nimport * as dbCommentFeedback from '@codraoss/db/comment-feedback';\nimport * as dbModelConfigs from '@codraoss/db/model-configs';\nimport * as dbRepoConfigs from '@codraoss/db/repo-configs';\nimport * as dbAppSettings from '@codraoss/db/app-settings';\nimport * as dbStats from '@codraoss/db/stats';\nimport * as dbWebhookDeliveries from '@codraoss/db/webhook-deliveries';\n\nimport { GitHubClient, normalizeGitHubWebhook } from '@codraoss/provider-github';\nimport { GitHubIdentityProvider } from '@codraoss/provider-github/oauth';\nimport { getGlobalConfig, updateGlobalConfig, loadRepoConfig, invalidateRepoConfigCache } from './platform/config';\n\nimport { getUpdatesEmailPreference, syncUpdatesEmail } from './platform/updates-email';\n\nimport { extractReviewRequest } from '@codraoss/core';\n\nimport { createOAuthState, consumeOAuthState } from './platform/oauth';\n\nimport { verifyGitHubWebhookSignature } from '@codraoss/core/verify';\n\n\n\n// model sync dependencies\nimport { listLlmProviderSecrets, upsertDiscoveredModelConfigs, createLlmProvider, updateLlmProvider, getResolvedModelConfig, getLlmProvider } from '@codraoss/db/model-configs';\nimport { encryptLlmApiKey, decryptLlmApiKey, listProviderModels, reviewWithCloudflare, reviewWithGoogle, reviewWithVertex, reviewWithOpenAI, reviewWithAnthropic, ProviderRequestError } from '@codraoss/models';\nimport { buildReviewResponseSchema } from '@codraoss/core/prompts/file-review';\n\nfunction toAppBindingsConfig(p: PlatformDeps) {\n return {\n APP_KV: p.kv,\n APP_PRIVATE_KEY: p.appPrivateKey,\n GITHUB_APP_ID: p.githubAppId,\n BOT_USERNAME: p.botUsername,\n GITHUB_APP_SLUG: p.githubAppSlug,\n GITHUB_CLIENT_ID: p.githubClientId,\n GITHUB_CLIENT_SECRET: p.githubClientSecret,\n AUTH_CALLBACK_URL: p.authCallbackUrl,\n };\n}\n\nfunction getSecretStore(p: PlatformDeps) {\n return { getSecret: p.getSecret };\n}\n\nfunction optionalEnv(value: () => string) {\n try {\n const resolved = value().trim();\n return resolved.length > 0 ? resolved : undefined;\n } catch {\n return undefined;\n }\n}\n\n// `IDENTITY_PROVIDER` is a test-only seam; production has no such binding.\nconst githubIdentity = new GitHubIdentityProvider();\nfunction identityProvider(p: PlatformDeps) {\n return p.identityProvider ?? githubIdentity;\n}\n\nexport function createSharedApiDeps(p: PlatformDeps): ApiRouterDeps {\n return {\n repositories: {\n accounts: dbAccounts,\n jobs: dbJobs,\n fileReviews: dbFileReviews,\n commentFeedback: dbCommentFeedback,\n modelConfigs: dbModelConfigs,\n repoConfigs: dbRepoConfigs,\n appSettings: dbAppSettings,\n stats: dbStats,\n webhookDeliveries: dbWebhookDeliveries,\n },\n gitProvider: {\n getAppInstallationUrl: async () => await GitHubClient.getAppInstallationUrl(toAppBindingsConfig(p)),\n listInstallations: async () => await GitHubClient.listInstallations(toAppBindingsConfig(p)),\n createService: (installationId?: number | string | null) => new GitHubClient(toAppBindingsConfig(p), installationId != null ? String(installationId) : undefined),\n },\n config: {\n getGlobalConfig: async () => await getGlobalConfig(p.kv),\n updateGlobalConfig: async (config: any) => await updateGlobalConfig(p.kv, config),\n loadRepoConfig: async (input: any) => await loadRepoConfig(p.kv, p.db, input),\n invalidateRepoConfigCache: async (owner: string, repo: string) => await invalidateRepoConfigCache(p.kv, owner, repo),\n },\n modelRunner: {\n syncProviderModelCatalog: async () => {\n const providers = await listLlmProviderSecrets(p.db);\n const syncErrors: Array<{ providerId: string; providerName: string; error: string }> = [];\n\n await Promise.all(providers.map(async (provider) => {\n if (!provider.enabled) return;\n if (provider.apiFormat !== 'cloudflare-workers-ai' && !provider.encryptedApiKey) return;\n\n try {\n const apiKey = provider.encryptedApiKey\n ? await decryptLlmApiKey(getSecretStore(p), provider.encryptedApiKey)\n : undefined;\n const modelNames = await listProviderModels({\n apiFormat: provider.apiFormat,\n baseUrl: provider.baseUrl,\n apiKey,\n cloudflareAccountId: optionalEnv(() => p.cfAccountId || ''),\n cloudflareApiToken: optionalEnv(() => p.cfApiToken || ''),\n });\n await upsertDiscoveredModelConfigs(p.db, {\n providerId: provider.id,\n providerName: provider.name,\n apiFormat: provider.apiFormat,\n modelNames,\n });\n } catch (error) {\n syncErrors.push({\n providerId: provider.id,\n providerName: provider.name,\n error: error instanceof Error ? error.message : 'Could not refresh provider models.',\n });\n }\n }));\n\n return syncErrors;\n },\n testConnection: async (modelId: string) => {\n const config = await getResolvedModelConfig(p.db, modelId);\n if (!config) throw { isNotFoundError: true };\n if (!config.providerEnabled) throw { isDisabledError: true, message: 'Provider is disabled.' };\n\n try {\n const input = {\n systemPrompt: 'You are validating connectivity. Return only the JSON object.',\n userPrompt: 'Return an empty review: no findings, overall_correctness \"patch is correct\".',\n responseSchema: buildReviewResponseSchema(1),\n };\n let response;\n if (config.apiFormat === 'cloudflare-workers-ai') {\n response = await reviewWithCloudflare(p.aiBinding, config.modelName, input, undefined, config.providerName);\n } else {\n if (!config.encryptedApiKey) {\n throw { isMissingKeyError: true, message: `Provider ${config.providerName} does not have a saved API key.` };\n }\n const apiKey = await decryptLlmApiKey(getSecretStore(p), config.encryptedApiKey);\n \n switch (config.apiFormat) {\n case 'gemini':\n response = await reviewWithGoogle({ apiKey, baseUrl: config.baseUrl, providerName: config.providerName, timeoutMs: 15000 }, config.modelName, input);\n break;\n case 'vertex':\n response = await reviewWithVertex({ apiKey, baseUrl: config.baseUrl, providerName: config.providerName }, config.modelName, input);\n break;\n case 'openai':\n response = await reviewWithOpenAI({ apiKey, baseUrl: config.baseUrl || 'https://api.openai.com/v1', providerName: config.providerName }, config.modelName, input);\n break;\n case 'anthropic':\n response = await reviewWithAnthropic({ apiKey, baseUrl: config.baseUrl, providerName: config.providerName }, config.modelName, input);\n break;\n default:\n throw new Error(`Unsupported API format: ${config.apiFormat}`);\n }\n }\n return {\n ok: true,\n modelUsed: response.modelUsed,\n provider: response.provider,\n inputTokens: response.inputTokens,\n outputTokens: response.outputTokens,\n ...(response.degraded === 'schema-dropped'\n ? { degraded: response.degraded, warning: 'Connected, but this endpoint rejected the response grammar. Reviews will run without constrained decoding.' }\n : {}),\n };\n } catch (error) {\n if (error instanceof ProviderRequestError) {\n throw { status: error.status >= 500 ? 502 : error.status, message: error.message, originalError: error };\n }\n throw error;\n }\n },\n createProviderWithSecret: async (input: any) => {\n let encryptedApiKey: string | null;\n try {\n encryptedApiKey = input.apiFormat === 'cloudflare-workers-ai'\n ? null\n : (input.apiKey ? await encryptLlmApiKey(getSecretStore(p), input.apiKey.trim()) : null);\n } catch (error) {\n if (error instanceof Error && error.message.includes('LLM_CONFIG_ENCRYPTION_KEY')) {\n throw { isEncryptionConfigError: true, message: error.message };\n }\n throw error;\n }\n\n if (input.enabled && input.apiFormat !== 'cloudflare-workers-ai' && !encryptedApiKey) {\n throw { isKeyRequiredError: true };\n }\n\n try {\n return await createLlmProvider(p.db, {\n name: input.name,\n apiFormat: input.apiFormat,\n baseUrl: input.apiFormat === 'cloudflare-workers-ai' ? null : (input.baseUrl ? input.baseUrl.replace(/\\/+$/, '') : null), // basic normalization\n encryptedApiKey,\n enabled: input.enabled,\n });\n } catch (error: any) {\n if (error?.code === '23505') throw { isUniqueNameError: true };\n throw error;\n }\n },\n updateProviderWithSecret: async (id: string, input: any) => {\n const existing = await getLlmProvider(p.db, id);\n if (!existing) return null;\n\n let encryptedApiKey: string | null | undefined;\n try {\nif (input.apiFormat === 'cloudflare-workers-ai') {\n encryptedApiKey = null;\n } else if (input.clearApiKey) {\n encryptedApiKey = null;\n } else if (input.apiKey) {\n encryptedApiKey = await encryptLlmApiKey(getSecretStore(p), input.apiKey.trim());\n } else {\n encryptedApiKey = undefined;\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes('LLM_CONFIG_ENCRYPTION_KEY')) {\n throw { isEncryptionConfigError: true, message: error.message };\n }\n throw error;\n }\n\n const effectiveEncryptedApiKey = encryptedApiKey !== undefined ? encryptedApiKey : existing.encryptedApiKey;\n if (input.enabled && input.apiFormat !== 'cloudflare-workers-ai' && !effectiveEncryptedApiKey) {\n throw { isKeyRequiredError: true };\n }\n\n try {\n return await updateLlmProvider(p.db, id, {\n name: input.name,\n apiFormat: input.apiFormat,\n baseUrl: input.apiFormat === 'cloudflare-workers-ai' ? null : (input.baseUrl ? input.baseUrl.replace(/\\/+$/, '') : null),\n ...(encryptedApiKey !== undefined ? { encryptedApiKey } : {}),\n enabled: input.enabled,\n });\n } catch (error: any) {\n if (error?.code === '23505') throw { isUniqueNameError: true };\n throw error;\n }\n },\n },\n sessionStore: p.sessionStore,\n platform: {\n scheduleBestEffortJobMaintenance: p.scheduleBestEffortJobMaintenance,\n createReviewRuntime: p.createReviewRuntime,\n getUpdatesEmailPreference: async (githubUserId: number) => await getUpdatesEmailPreference(p.kv, githubUserId),\n syncUpdatesEmail: async (githubUserId: number, email: string | null | undefined) => await syncUpdatesEmail(p.kv, githubUserId, email),\n terminateJobWorkflow: p.terminateJobWorkflow,\n enqueueReviewJob: p.enqueueReviewJob,\n getOrFetchRawDiffForCompletedJob: p.getOrFetchRawDiffForCompletedJob,\n logger: p.logger,\n },\n authProvider: {\n createOAuthState: async () => await createOAuthState(p.kv),\n consumeOAuthState: async (state: string) => await consumeOAuthState(p.kv, state),\n beginAuthorization: async (callbackUrl: string, state: string) =>\n await identityProvider(p).beginAuthorization(callbackUrl, state, toAppBindingsConfig(p) as any),\n completeAuthorization: async (code: string, state: string, expectedState: string) =>\n await identityProvider(p).completeAuthorization(code, state, expectedState, toAppBindingsConfig(p) as any),\n },\n webhook: {\n verifySignature: async (signature: string | null, body: string) => await verifyGitHubWebhookSignature(p.githubAppWebhookSecret, signature, body),\n normalizePayload: (eventName: string, payload: any) => normalizeGitHubWebhook(eventName, payload),\n extractReviewRequest: (input: any) => extractReviewRequest(input),\n },\n };\n}\n\n\n\n\n\n\n\n\n"],"mappings":"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","names":["Hono","createMiddleware","Hono","Hono","Hono","Hono","Hono","Hono","Hono","z","z","Hono","Hono","Hono","Hono","z","z","Hono","Hono","z","z","Hono","Hono"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface KvCompat {
|
|
2
|
+
put(key: string, value: string, options?: {
|
|
3
|
+
expirationTtl?: number;
|
|
4
|
+
}): Promise<void>;
|
|
5
|
+
get(key: string, type: 'json'): Promise<unknown>;
|
|
6
|
+
get(key: string, type?: 'text'): Promise<string | null>;
|
|
7
|
+
delete(key: string): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type { KvCompat as K };
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
declare class Logger {
|
|
2
|
+
private context;
|
|
3
|
+
constructor(context?: Record<string, any>);
|
|
4
|
+
withContext(newContext: Record<string, any>): Logger;
|
|
5
|
+
private log;
|
|
6
|
+
runWithContext<T>(context: Record<string, any>, fn: () => T): T;
|
|
7
|
+
info(message: string, data?: any): void;
|
|
8
|
+
error(message: string, data?: any): void;
|
|
9
|
+
warn(message: string, data?: any): void;
|
|
10
|
+
debug(message: string, data?: any): void;
|
|
11
|
+
}
|
|
12
|
+
declare const logger: Logger;
|
|
13
|
+
|
|
14
|
+
export { logger };
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { K as KvCompat } from '../kv-ByAbDUqn.js';
|
|
2
|
+
import { RepoConfig } from '@codraoss/schema';
|
|
3
|
+
import { DbEnv } from '@codraoss/db/env';
|
|
4
|
+
|
|
5
|
+
type CachedConfig = {
|
|
6
|
+
parsedJson: RepoConfig;
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare function getGlobalConfig(kv: KvCompat): Promise<RepoConfig['model']>;
|
|
10
|
+
declare function updateGlobalConfig(kv: KvCompat, config: RepoConfig['model']): Promise<void>;
|
|
11
|
+
declare function invalidateRepoConfigCache(kv: KvCompat, owner: string, repo: string): Promise<void>;
|
|
12
|
+
declare function loadRepoConfig(kv: KvCompat, db: DbEnv, input: {
|
|
13
|
+
installationId: string;
|
|
14
|
+
owner: string;
|
|
15
|
+
repo: string;
|
|
16
|
+
}): Promise<CachedConfig>;
|
|
17
|
+
|
|
18
|
+
declare function parseAllowedUsers(input: string): Set<string>;
|
|
19
|
+
declare function createOAuthState(kv: KvCompat): Promise<string>;
|
|
20
|
+
declare function consumeOAuthState(kv: KvCompat, state: string): Promise<boolean>;
|
|
21
|
+
|
|
22
|
+
type UpdatesEmailRecord = {
|
|
23
|
+
status: 'subscribed';
|
|
24
|
+
email: string;
|
|
25
|
+
updatedAt: string;
|
|
26
|
+
};
|
|
27
|
+
declare function getUpdatesEmailPreference(kv: KvCompat, githubUserId: number): Promise<UpdatesEmailRecord | null>;
|
|
28
|
+
declare function syncUpdatesEmail(kv: KvCompat, githubUserId: number, email: string | null | undefined): Promise<boolean>;
|
|
29
|
+
|
|
30
|
+
export { KvCompat, consumeOAuthState, createOAuthState, getGlobalConfig, getUpdatesEmailPreference, invalidateRepoConfigCache, loadRepoConfig, parseAllowedUsers, syncUpdatesEmail, updateGlobalConfig };
|