import { DurableObject, env } from "cloudflare:workers";
import { loadActiveUserById, toViewer } from "../auth";
import { hasPermission, loadRepoById, repoPermission } from "../repos";
import { decryptRepoSecret, encryptRepoSecret } from "../secrets";
import { randomToken } from "../crypto";
import { HttpError } from "../errors";
import { advertisement } from "../git/relay";
import { billingSettings } from "../metering/settings";
import { stripeEnabled } from "../billing/config";
import { eventBudget, isMirroredRef, nextEventRunAt, scheduleIntervalMs, utcDay } from "./plan";
import { runMirrorSync } from "./sync";
import type { MirrorSettings } from "./sync";
import type { MirrorRun, MirrorStatus, MirrorTrigger } from "~/lib/mirror";
import type { RepoRow } from "~/lib/types";
const MAX_RUNS = 30;
const MAX_ERROR_LENGTH = 400;
const FIRST_RUN_DELAY_MS = 5_000;
const RUNNING_RETRY_MS = 30_000;
type Sealed = { ciphertext: string; iv: string };
type Config = MirrorSettings & {
repoId: string;
enabled: boolean;
token: Sealed | null;
webhookSecret: Sealed;
};
type State = {
/** Ref → sha both sides agreed on after the last sync; tells a deletion apart from a new ref. */
synced: Record<string, string>;
/** Ref → sha this mirror last wrote into the forge repo, so its own pushes don't trigger another run. */
written: Record<string, string>;
runs: MirrorRun[];
lastRunAt: number | null;
nextScheduledAt: number | null;
pendingAt: number | null;
pendingTrigger: MirrorTrigger | null;
eventDay: string;