import { verifyMirrorHook } from "./hook-auth";
import { enforceRateLimit, requestIp } from "../limits";
import { env } from "cloudflare:workers";
import { mirrorFlagKey, mirrorStub } from "./mirror-do";
export const MIRROR_HOOK_PATH = /^mirror\/([A-Za-z0-9_-]{1,64})$/;
const MAX_HOOK_BYTES = 1024 * 1024;
const HTTP_ACCEPTED = 202;
const HTTP_UNAUTHORIZED = 401;
const HTTP_TOO_LARGE = 413;
async function readCapped(request: Request): Promise<string | null> {
if (Number(request.headers.get("content-length") ?? "0") > MAX_HOOK_BYTES) return null;
if (!request.body) return "";
const reader = request.body.getReader();
const chunks: Uint8Array[] = [];
let size = 0;
for (;;) {
const { value, done } = await reader.read();
if (done) break;
size += value.byteLength;
if (size > MAX_HOOK_BYTES) {
await reader.cancel().catch(() => undefined);
return null;
}
chunks.push(value);
}
const merged = new Uint8Array(size);
let offset = 0;
for (const chunk of chunks) {
merged.set(chunk, offset);
offset += chunk.byteLength;
}
return new TextDecoder().decode(merged);
}
/** `POST /integrations/hooks/mirror/<repoId>`: a push on the remote queues a coalesced mirror sync. */
export async function handleMirrorHook(request: Request, repoId: string): Promise<Response> {
await enforceRateLimit("GIT_LIMITER", `mirror-hook:${repoId}:${requestIp(request)}`);