import { waitUntil } from "cloudflare:workers";
import { accountDb } from "../scoped-db";
import { randomId } from "../crypto";
import { HttpError } from "../errors";
import { enforceRateLimit, limitHeavy } from "../limits";
import { RPC, RpcError } from "./protocol";
import type { McpCaller } from "./protocol";
import { recordToolUsage } from "./usage";
const MAX_AUDIT_STRING = 200;
const MAX_AUDIT_JSON = 4000;
const MAX_AUDIT_DEPTH = 4;
/**
* Argument keys whose values are user content or credentials: logged as a length and hash, never verbatim.
* Covers file bodies, commit messages, CI `inputs` (often secrets), scratch-site `files` and claim notes.
*/
const REDACTED_KEYS = new Set([
"content",
"token",
"resolutions",
"body",
"inputs",
"files",
"message",
"note",
"title",
"description",
"text",
"secret",
"value",
"env",
]);
function redact(value: unknown, depth = 0): unknown {
if (depth > MAX_AUDIT_DEPTH) return "…";
if (typeof value === "string") return value.length > MAX_AUDIT_STRING ? `<${value.length} chars>` : value;
if (Array.isArray(value)) return value.slice(0, 20).map((item) => redact(item, depth + 1));
if (typeof value !== "object" || value === null) return value;
const out: Record<string, unknown> = {};
for (const [key, item] of Object.entries(value)) {