import { z } from "zod";
import { all, batch, first, placeholders, run, stmt } from "./db";
import { randomId } from "./crypto";
import { badRequest, conflict, forbidden, notFoundError } from "./errors";
import { emitNotification, emitWebhook } from "./events/emit";
import { kickBranch, kickMergeAutomation } from "./merge-automation";
import { pullUrl } from "./pull-access";
import { addIssueEvent } from "./pulls";
import type { PullRow } from "./pulls";
import { rerequestReview } from "./review-requests";
import { markdownBody } from "~/lib/validation";
import type { Permission, RepoRow, Viewer } from "~/lib/types";
/** A resolved pull plus the caller's effective permission on its repo (already capped by any token scope). */
export type PullAccess = { repo: RepoRow; permission: Permission; pull: PullRow };
export const reviewCommentInput = z
.object({
path: z.string().min(1),
line: z.number().int().positive(),
side: z.enum(["LEFT", "RIGHT"]),
startLine: z.number().int().positive().nullish(),
startSide: z.enum(["LEFT", "RIGHT"]).nullish(),
body: markdownBody.min(1),
})
.refine((comment) => !comment.startLine || comment.startLine < comment.line, "Start line must precede the end line");
export type ReviewCommentInput = z.infer<typeof reviewCommentInput>;
export type ReviewEvent = "approve" | "request_changes" | "comment";
async function insertReviewComments(
pull: PullRow,
viewer: Viewer,
reviewId: string | null,
comments: ReviewCommentInput[],
inReplyTo: string | null,
) {
const now = Date.now();
await batch(
comments.map((comment) =>