import { env } from "cloudflare:workers";
import { all } from "../db";
import { isArtifactsError } from "./artifacts";
import { artifactsCall } from "./artifacts-call";
import { allShards, shardOfName } from "./artifacts-shards";
/** Artifacts repos that `createRepository` creates before inserting their row can be younger than this. */
const GRACE_MS = 24 * 60 * 60 * 1000;
const PAGE_SIZE = 200;
const PAGES_PER_RUN = 2;
const CURSOR_TTL_SECONDS = 7 * 24 * 60 * 60;
/** D1 binds at most 100 parameters per statement. */
const D1_MAX_PARAMS = 90;
const OWN_NAME = /^r\d*-[A-Za-z0-9_-]+$/;
type SweepMode = "off" | "report" | "delete";
function isLocalUrl(raw: string | undefined): boolean {
try {
const host = new URL(raw ?? "").hostname;
return host === "localhost" || host === "127.0.0.1" || host === "[::1]" || host.endsWith(".localhost");
} catch {
return true;
}
}
/**
* `delete` also needs ARTIFACTS_NAMESPACE_EXCLUSIVE=true and a non-local PUBLIC_URL: a namespace shared with
* another deployment (or a local dev database) would make every repository of the other side look orphaned.
*/
export function sweepMode(vars: { mode?: string; exclusive?: string; publicUrl?: string }): SweepMode {
if (vars.mode === "off") return "off";
if (vars.mode !== "delete") return "report";
if (vars.exclusive !== "true" || isLocalUrl(vars.publicUrl)) {
console.error(
"ARTIFACTS_ORPHAN_SWEEP=delete ignored: it requires ARTIFACTS_NAMESPACE_EXCLUSIVE=true and a non-local PUBLIC_URL; reporting only",
);
return "report";
}
return "delete";