import { env } from "cloudflare:workers";
import { all, first, run } from "../db";
import { hmacSha256Hex, randomId } from "../crypto";
import { issueParticipants } from "../issues";
import { CAPS } from "../limits";
import type { NotifyMessage, QueueMessage, WebhookEvent } from "./emit";
const DELIVERY_TIMEOUT_MS = 10_000;
const MAX_RESPONSE_BODY = 4096;
const BASE_RETRY_SECONDS = 15;
const MAX_RETRY_SECONDS = 3600;
const HTTP_OK_MIN = 200;
const HTTP_OK_MAX = 300;
const MENTION = /(?:^|[^\w@])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,38}))/g;
type WebhookRow = { id: string; repo_id: string; url: string; secret: string | null; events: string; active: number };
async function dispatch(message: Extract<QueueMessage, { kind: "webhook.dispatch" }>): Promise<void> {
const hooks = await all<WebhookRow>("SELECT * FROM webhooks WHERE repo_id = ? AND active = 1", message.repoId);
const deliveries: QueueMessage[] = [];
for (const hook of hooks) {
const events: string[] = JSON.parse(hook.events);
if (!events.includes("*") && !events.includes(message.event)) continue;
deliveries.push({
kind: "webhook.deliver",
webhookId: hook.id,
event: message.event,
deliveryId: randomId(),
payload: message.payload,
});
}
if (deliveries.length > 0) await env.EVENTS.sendBatch(deliveries.map((body) => ({ body })));
}
async function readPrefix(response: Response, limit: number): Promise<string> {
if (!response.body) return "";
const reader = response.body.getReader();
const decoder = new TextDecoder();
let text = "";
while (text.length < limit) {