const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
const require_helpers = require('./helpers.cjs');
const require_router = require('./router.cjs');
const require_sse_writer = require('./sse-writer.cjs');
const require_chaos = require('./chaos.cjs');
const require_url = require('./url.cjs');
const require_recorder = require('./recorder.cjs');
const require_fal = require('./fal.cjs');
const require_video_proxy_shared = require('./video-proxy-shared.cjs');
let node_crypto = require("node:crypto");
node_crypto = require_runtime.__toESM(node_crypto);

//#region src/veo-video.ts
/**
* Google Veo async video lifecycle mock. Submit
* `POST /v1beta/models/{model}:predictLongRunning` returns
* `{ name: "operations/..." }`; status `GET /v1beta/operations/{name}` polls
* `done:false → done:true`. The Files-API `uri` is served AS-IS — aimock does
* NOT proxy or capture video bytes. With `record.providers.veo` configured an
* unmatched submit becomes a live interactive proxy (submit + poll forwarded
* 1:1, eager fixture capture on terminal status). Strict mode still wins.
*
* ASSUMED Veo create body shape (the `@google/genai` :predictLongRunning
* envelope from issue #278): `{ instances: [{ prompt, image? }], parameters }`.
* Match surface is `instances[0].prompt` only.
*/
/** Files-API-shaped placeholder served when a completed fixture omits a uri. */
const DEFAULT_VEO_FILES_URI = "https://generativelanguage.googleapis.com/v1beta/files/placeholder";
const VEO_VIDEO_MAX_ENTRIES = 1e4;
const VEO_VIDEO_TTL_MS = 36e5;
/**
* Per-testId job state for the Veo video handler. Mirrors OpenRouterVideoJobMap
* (openrouter-video.ts): lazy TTL eviction on `get`, FIFO eviction of the
* oldest entries on `set` when over capacity, delete-before-set TTL refresh,
* monotonic world-generation counter for reset-mid-flight detection, no
* background sweep timer. Keys are `${testId}:${operationName}`.
*/
var VeoVideoJobMap = class {
	entries = /* @__PURE__ */ new Map();
	worldGeneration = 0;
	get generation() {
		return this.worldGeneration;
	}
	get(key) {
		const entry = this.entries.get(key);
		if (!entry) return void 0;
		if (Date.now() - entry.createdAt > VEO_VIDEO_TTL_MS) {
			this.entries.delete(key);
			return;
		}
		return entry.job;
	}
	set(key, job) {
		this.entries.delete(key);
		this.entries.set(key, {
			job,
			createdAt: Date.now()
		});
		if (this.entries.size > VEO_VIDEO_MAX_ENTRIES) {
			const excess = this.entries.size - VEO_VIDEO_MAX_ENTRIES;
			const iter = this.entries.keys();
			for (let i = 0; i < excess; i++) {
				const next = iter.next();
				if (!next.done) this.entries.delete(next.value);
			}
		}
	}
	delete(key) {
		return this.entries.delete(key);
	}
	clear() {
		this.entries.clear();
		this.worldGeneration++;
	}
	get size() {
		return this.entries.size;
	}
};
/**
* Maps the fixture's terminal video status onto the job lifecycle. Anything
* that is not "failed" — including a fixture authored as "processing" — is
* treated as completed, since this surface always drives jobs to a terminal
* state.
*/
function terminalStatus(job) {
	return job.video.status === "failed" ? "failed" : "completed";
}
/**
* Mutates a job in place to advance its state on a status poll.
* `pending → in_progress → completed | failed` based on poll-count thresholds.
* No-op once terminal. The in_progress threshold is checked first so a job
* whose thresholds are equal still spends one poll in in_progress instead of
* jumping straight to the terminal status (fal advanceJob semantics). The wire
* value is derived from this internal status (pending/in_progress → done:false,
* completed/failed → done:true).
*/
function advanceVeoJob(job) {
	if (job.status === "completed" || job.status === "failed") return;
	job.pollCount += 1;
	if (job.status === "pending" && job.pollCount >= job.pollsBeforeInProgress) job.status = "in_progress";
	else if (job.pollCount >= job.pollsBeforeCompleted) job.status = terminalStatus(job);
}
/** Gemini-style error envelope used by every Veo error response. */
function geminiError(code, message, status) {
	return JSON.stringify({ error: {
		code,
		message,
		status
	} });
}
/**
* The done:true operation body for a completed replay job — the Files-API uri
* is served as-is (the fixture's stored `video.url`, or the documented
* placeholder when omitted).
*/
function completedOperationBody(operationName, uri) {
	return {
		name: operationName,
		done: true,
		response: { generateVideoResponse: { generatedSamples: [{ video: { uri } }] } }
	};
}
async function handleVeoVideoCreate(req, res, raw, model, fixtures, journal, defaults, setCorsHeaders, jobs) {
	setCorsHeaders(res);
	const path = req.url ?? `/v1beta/models/${model}:predictLongRunning`;
	const method = req.method ?? "POST";
	let videoReq;
	try {
		videoReq = JSON.parse(raw);
	} catch (parseErr) {
		const detail = parseErr instanceof Error ? parseErr.message : "unknown";
		journal.add({
			method,
			path,
			headers: require_helpers.flattenHeaders(req.headers),
			body: null,
			response: {
				status: 400,
				fixture: null
			}
		});
		require_sse_writer.writeErrorResponse(res, 400, geminiError(400, `Malformed JSON: ${detail}`, "INVALID_ARGUMENT"));
		return;
	}
	if (videoReq === null || typeof videoReq !== "object" || Array.isArray(videoReq)) {
		journal.add({
			method,
			path,
			headers: require_helpers.flattenHeaders(req.headers),
			body: null,
			response: {
				status: 400,
				fixture: null
			}
		});
		require_sse_writer.writeErrorResponse(res, 400, geminiError(400, "Request body must be a JSON object", "INVALID_ARGUMENT"));
		return;
	}
	const prompt = (Array.isArray(videoReq.instances) ? videoReq.instances[0] : void 0)?.prompt;
	const parsedBody = {
		...Object.fromEntries(Object.entries(videoReq).filter(([key]) => !key.startsWith("_"))),
		model,
		messages: []
	};
	if (typeof prompt !== "string" || !prompt) {
		journal.add({
			method,
			path,
			headers: require_helpers.flattenHeaders(req.headers),
			body: parsedBody,
			response: {
				status: 400,
				fixture: null
			}
		});
		require_sse_writer.writeErrorResponse(res, 400, geminiError(400, prompt === void 0 ? "Missing required parameter: 'instances[0].prompt'" : "Invalid type for parameter: 'instances[0].prompt' must be a non-empty string", "INVALID_ARGUMENT"));
		return;
	}
	const syntheticReq = {
		model,
		messages: [{
			role: "user",
			content: prompt
		}],
		_endpointType: "video",
		_videoProvider: "veo",
		_context: require_helpers.getContext(req)
	};
	const testId = require_helpers.getTestId(req);
	const { fixture, skippedBySequenceOrTurn } = require_router.matchFixtureDiagnostic(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
	if (fixture) {
		journal.incrementFixtureMatchCount(fixture, fixtures, testId);
		defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
	} else defaults.logger.debug(`No fixture matched for Veo request (model=${model}, msg="${prompt.slice(0, 80)}")`);
	if (require_chaos.applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
		method,
		path,
		headers: require_helpers.flattenHeaders(req.headers),
		body: syntheticReq
	}, fixture ? "fixture" : require_helpers.resolveStrictMode(defaults.strict, req.headers) ? "internal" : defaults.record?.providers.veo ? "proxy" : "internal", defaults.registry, defaults.logger)) return;
	if (!fixture) {
		if (require_helpers.resolveStrictMode(defaults.strict, req.headers)) {
			const strictMessage = require_helpers.strictNoMatchMessage(skippedBySequenceOrTurn);
			defaults.logger.error(require_helpers.strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));
			journal.add({
				method,
				path,
				headers: require_helpers.flattenHeaders(req.headers),
				body: syntheticReq,
				response: {
					status: 503,
					fixture: null,
					...require_helpers.strictOverrideField(defaults.strict, req.headers)
				}
			});
			require_sse_writer.writeErrorResponse(res, 503, geminiError(503, strictMessage, "UNAVAILABLE"));
			return;
		}
		if (defaults.record) {
			if (await proxyVeoVideoSubmit({
				req,
				res,
				raw,
				syntheticReq,
				record: defaults.record,
				journal,
				defaults,
				jobs,
				method,
				path
			}) === "handled") return;
		}
		journal.add({
			method,
			path,
			headers: require_helpers.flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status: 404,
				fixture: null,
				...require_helpers.strictOverrideField(defaults.strict, req.headers)
			}
		});
		require_sse_writer.writeErrorResponse(res, 404, geminiError(404, "No fixture matched", "NOT_FOUND"));
		return;
	}
	const worldGeneration = jobs.generation;
	const response = await require_helpers.resolveResponse(fixture, syntheticReq);
	if (require_helpers.isErrorResponse(response)) {
		if (res.destroyed || res.writableEnded) return;
		const status = response.status ?? 500;
		journal.add({
			method,
			path,
			headers: require_helpers.flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status,
				fixture
			}
		});
		require_sse_writer.writeErrorResponse(res, status, require_helpers.serializeErrorResponse(response), { retryAfter: response.retryAfter });
		return;
	}
	if (!require_helpers.isVideoResponse(response)) {
		if (res.destroyed || res.writableEnded) return;
		journal.add({
			method,
			path,
			headers: require_helpers.flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status: 500,
				fixture
			}
		});
		require_sse_writer.writeErrorResponse(res, 500, geminiError(500, "Fixture response is not a video type", "INTERNAL"));
		return;
	}
	if (res.destroyed || res.writableEnded) return;
	journal.add({
		method,
		path,
		headers: require_helpers.flattenHeaders(req.headers),
		body: syntheticReq,
		response: {
			status: 200,
			fixture
		}
	});
	const fixtureStatus = response.video.status;
	if (fixtureStatus === "processing") defaults.logger.warn(`Veo video fixture has status "processing" — treated as completed for the operations lifecycle`);
	else if (fixtureStatus !== "completed" && fixtureStatus !== "failed") defaults.logger.warn(`Veo video fixture has unknown status "${fixtureStatus}" — treating as completed`);
	const operationName = `operations/${node_crypto.default.randomUUID()}`;
	const progression = require_fal.resolveProgression(defaults.veoVideo);
	const job = {
		kind: "replay",
		operationName,
		status: "pending",
		pollCount: 0,
		pollsBeforeInProgress: progression.pollsBeforeInProgress,
		pollsBeforeCompleted: progression.pollsBeforeCompleted,
		video: { ...response.video }
	};
	if (progression.pollsBeforeCompleted === 0) job.status = terminalStatus(job);
	if (jobs.generation === worldGeneration) jobs.set(`${testId}:${operationName}`, job);
	else defaults.logger.warn(`Veo video submit resolved after a fixtures reset — not inserting operation ${operationName} into the new world (its polls will 404)`);
	res.writeHead(200, { "Content-Type": "application/json" });
	res.end(JSON.stringify({ name: operationName + require_video_proxy_shared.testIdSuffix(testId, "?") }));
}
async function handleVeoVideoStatus(req, res, operationName, fixtures, journal, defaults, setCorsHeaders, jobs) {
	setCorsHeaders(res);
	const path = req.url ?? `/v1beta/${operationName}`;
	const method = req.method ?? "GET";
	if (require_chaos.applyChaos(res, null, defaults.chaos, req.headers, journal, {
		method,
		path,
		headers: require_helpers.flattenHeaders(req.headers),
		body: null
	}, "internal", defaults.registry, defaults.logger)) return;
	const testId = require_helpers.getTestId(req);
	const key = `${testId}:${operationName}`;
	const job = jobs.get(key);
	if (!job) {
		journal.add({
			method,
			path,
			headers: require_helpers.flattenHeaders(req.headers),
			body: null,
			response: {
				status: 404,
				fixture: null
			}
		});
		require_sse_writer.writeErrorResponse(res, 404, geminiError(404, `Operation ${operationName} not found`, "NOT_FOUND"));
		return;
	}
	if (job.kind === "record") {
		if (require_helpers.resolveStrictMode(defaults.strict, req.headers)) {
			defaults.logger.error(`STRICT: Veo operation ${operationName} is proxied live upstream (record mode) — refusing the upstream poll`);
			journal.add({
				method,
				path,
				headers: require_helpers.flattenHeaders(req.headers),
				body: null,
				response: {
					status: 503,
					fixture: null,
					...require_helpers.strictOverrideField(defaults.strict, req.headers)
				}
			});
			require_sse_writer.writeErrorResponse(res, 503, geminiError(503, `Strict mode: Veo operation ${operationName} is proxied live upstream (record mode) — nothing reaches an upstream under strict mode`, "UNAVAILABLE"));
			return;
		}
		await proxyVeoVideoRecordPoll({
			req,
			res,
			job,
			key,
			testId,
			fixtures,
			journal,
			defaults,
			jobs,
			method,
			path
		});
		return;
	}
	if (res.destroyed || res.writableEnded) return;
	advanceVeoJob(job);
	jobs.set(key, job);
	journal.add({
		method,
		path,
		headers: require_helpers.flattenHeaders(req.headers),
		body: null,
		response: {
			status: 200,
			fixture: null
		}
	});
	let body;
	if (job.status === "completed") {
		const rawUrl = job.video.url;
		body = completedOperationBody(operationName, typeof rawUrl === "string" && rawUrl ? rawUrl : DEFAULT_VEO_FILES_URI);
	} else if (job.status === "failed") {
		if (job.video.error === "" && !job.emptyErrorWarned) {
			job.emptyErrorWarned = true;
			defaults.logger.warn(`Veo video fixture for operation ${operationName} has an empty error message — using the default`);
		}
		body = {
			name: operationName,
			done: true,
			error: {
				code: 3,
				message: job.video.error || "Video generation failed"
			}
		};
	} else body = {
		name: operationName,
		done: false
	};
	res.writeHead(200, { "Content-Type": "application/json" });
	res.end(JSON.stringify(body));
}
/**
* Proxy an unmatched Veo submit to the configured upstream and answer the
* client with a mock-rewritten envelope: a fresh aimock operation name. The
* upstream lifecycle is driven interactively by the client's own polls.
*
* Returns "no_upstream" when record mode has no veo provider URL — the caller
* falls through to its 404 branch (fal convention).
*/
async function proxyVeoVideoSubmit(args) {
	const { req, res, raw, syntheticReq, record, journal, defaults, jobs, method, path } = args;
	const upstreamBase = record.providers.veo;
	if (!upstreamBase) {
		defaults.logger.warn(`No upstream URL configured for provider "veo" — cannot proxy`);
		return "no_upstream";
	}
	const proxyError = (msg) => {
		defaults.logger.error(`Veo video submit proxy failed: ${msg}`);
		if (res.destroyed || res.writableEnded) return "handled";
		journal.add({
			method,
			path,
			headers: require_helpers.flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status: 502,
				fixture: null,
				source: "proxy",
				...require_helpers.strictOverrideField(defaults.strict, req.headers)
			}
		});
		require_sse_writer.writeErrorResponse(res, 502, JSON.stringify({ error: {
			message: `Proxy to upstream failed: ${msg}`,
			type: "proxy_error"
		} }));
		return "handled";
	};
	const submitPath = `/v1beta/models/${syntheticReq.model}:predictLongRunning`;
	let submitUrl;
	let upstreamOrigin;
	try {
		submitUrl = require_url.resolveUpstreamUrl(upstreamBase, submitPath);
		upstreamOrigin = new URL(upstreamBase).origin;
	} catch (err) {
		return proxyError(`Invalid upstream URL: ${upstreamBase} (${err instanceof Error ? err.message : String(err)})`);
	}
	defaults.logger.warn(`NO FIXTURE MATCH — proxying Veo video submit to ${upstreamBase}${submitPath}`);
	const worldGeneration = jobs.generation;
	let fetched;
	try {
		const upstreamRes = await fetch(submitUrl, {
			method: "POST",
			headers: require_recorder.buildForwardHeaders(req),
			body: raw,
			signal: require_video_proxy_shared.upstreamTimeoutSignal(record)
		});
		fetched = {
			status: upstreamRes.status,
			contentType: upstreamRes.headers.get("content-type"),
			text: await require_video_proxy_shared.readEnvelopeText(upstreamRes, record)
		};
	} catch (err) {
		return proxyError(err instanceof Error ? err.message : "Unknown proxy error");
	}
	if (fetched.status === 401 || fetched.status === 403) {
		defaults.logger.warn(`Upstream rejected the Veo video submit (${fetched.status}) — relaying the upstream status`);
		if (res.destroyed || res.writableEnded) return "handled";
		journal.add({
			method,
			path,
			headers: require_helpers.flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status: fetched.status,
				fixture: null,
				source: "proxy",
				...require_helpers.strictOverrideField(defaults.strict, req.headers)
			}
		});
		res.writeHead(fetched.status, { "Content-Type": fetched.contentType ?? "application/json" });
		res.end(fetched.text);
		return "handled";
	}
	let upstreamOperationName;
	{
		if (fetched.status < 200 || fetched.status >= 300) return proxyError(`Submit ${fetched.status}: ${fetched.text.slice(0, 200)}`);
		let parsed;
		try {
			parsed = JSON.parse(fetched.text);
		} catch {
			return proxyError(`Submit returned non-JSON: ${fetched.text.slice(0, 200)}`);
		}
		if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return proxyError("Submit response is not a JSON object");
		upstreamOperationName = String(parsed.name ?? "").trim();
		if (!upstreamOperationName) return proxyError("Submit response missing name");
	}
	let upstreamPollingUrl;
	try {
		const constructed = require_url.resolveUpstreamUrl(upstreamBase, `/v1beta/${upstreamOperationName.replace(/^\/+/, "")}`);
		if (constructed.origin === upstreamOrigin) upstreamPollingUrl = constructed.toString();
		else {
			defaults.logger.warn(`Constructed Veo poll URL origin ${constructed.origin} differs from the configured provider origin ${upstreamOrigin} — using the provider-origin URL`);
			upstreamPollingUrl = `${upstreamOrigin}/v1beta/${upstreamOperationName.replace(/^\/+/, "")}`;
		}
	} catch {
		defaults.logger.warn(`Could not construct the Veo poll URL for ${upstreamOperationName} — using the provider-origin URL`);
		upstreamPollingUrl = `${upstreamOrigin}/v1beta/${upstreamOperationName.replace(/^\/+/, "")}`;
	}
	const testId = require_helpers.getTestId(req);
	const matchRequest = defaults.requestTransform ? defaults.requestTransform(syntheticReq) : syntheticReq;
	const operationName = `operations/${node_crypto.default.randomUUID()}`;
	const job = {
		kind: "record",
		operationName,
		status: "pending",
		upstreamOperationName,
		upstreamPollingUrl,
		match: require_recorder.buildFixtureMatch(matchRequest, record)
	};
	if (jobs.generation === worldGeneration) jobs.set(`${testId}:${operationName}`, job);
	else defaults.logger.warn(`Veo video submit for upstream operation ${upstreamOperationName} completed after a fixtures reset — not inserting the job into the new world (its polls will 404)`);
	if (res.destroyed || res.writableEnded) return "handled";
	journal.add({
		method,
		path,
		headers: require_helpers.flattenHeaders(req.headers),
		body: syntheticReq,
		response: {
			status: 200,
			fixture: null,
			source: "proxy",
			...require_helpers.strictOverrideField(defaults.strict, req.headers)
		}
	});
	res.writeHead(200, { "Content-Type": "application/json" });
	res.end(JSON.stringify({ name: operationName + require_video_proxy_shared.testIdSuffix(testId, "?") }));
	return "handled";
}
/**
* Proxy a status poll for a record-mode Veo job 1:1 to the upstream and relay
* the result with the operation name rewritten to the mock operation (the
* Files-API uri inside `response` passes through verbatim — aimock never
* downloads bytes). When the upstream reports `done:true` with a `response`,
* the rewritten body is relayed IMMEDIATELY and the eager capture (persist the
* uri as a fixture, mutate to a terminal replay job) runs DETACHED. A
* `done:true` with an `error` persists a failed fixture synchronously. Under
* `record.proxyOnly` nothing is captured, persisted, or mutated. Every
* post-await map mutation is identity-guarded.
*/
async function proxyVeoVideoRecordPoll(args) {
	const { req, res, job, key, testId, fixtures, journal, defaults, jobs, method, path } = args;
	const logger = defaults.logger;
	const journalProxy = (status) => {
		journal.add({
			method,
			path,
			headers: require_helpers.flattenHeaders(req.headers),
			body: null,
			response: {
				status,
				fixture: null,
				source: "proxy",
				...require_helpers.strictOverrideField(defaults.strict, req.headers)
			}
		});
	};
	const proxyError = (msg) => {
		logger.error(`Veo video poll proxy failed: ${msg}`);
		if (res.destroyed || res.writableEnded) return;
		journalProxy(502);
		require_sse_writer.writeErrorResponse(res, 502, JSON.stringify({ error: {
			message: `Proxy to upstream failed: ${msg}`,
			type: "proxy_error"
		} }));
	};
	const record = defaults.record;
	if (!record) {
		proxyError("record mode is no longer configured for an in-flight record job");
		return;
	}
	let fetched;
	try {
		const upstreamRes = await fetch(job.upstreamPollingUrl, {
			headers: require_recorder.buildForwardHeaders(req),
			signal: require_video_proxy_shared.upstreamTimeoutSignal(record)
		});
		fetched = {
			status: upstreamRes.status,
			contentType: upstreamRes.headers.get("content-type"),
			text: await require_video_proxy_shared.readEnvelopeText(upstreamRes, record)
		};
	} catch (err) {
		proxyError(err instanceof Error ? err.message : "Unknown proxy error");
		return;
	}
	if (fetched.status === 401 || fetched.status === 403) {
		logger.warn(`Upstream rejected the Veo status poll for operation ${job.upstreamOperationName} (${fetched.status}) — relaying the upstream status`);
		if (res.destroyed || res.writableEnded) return;
		journalProxy(fetched.status);
		res.writeHead(fetched.status, { "Content-Type": fetched.contentType ?? "application/json" });
		res.end(fetched.text);
		return;
	}
	let upstreamBody;
	{
		if (fetched.status < 200 || fetched.status >= 300) {
			proxyError(`Status ${fetched.status}: ${fetched.text.slice(0, 200)}`);
			return;
		}
		let parsed;
		try {
			parsed = JSON.parse(fetched.text);
		} catch {
			proxyError(`Status returned non-JSON: ${fetched.text.slice(0, 200)}`);
			return;
		}
		if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
			proxyError("Status response is not a JSON object");
			return;
		}
		upstreamBody = parsed;
	}
	const relayBody = {
		...upstreamBody,
		name: job.operationName
	};
	const relayJson = () => {
		if (res.destroyed || res.writableEnded) return;
		journalProxy(200);
		res.writeHead(200, { "Content-Type": "application/json" });
		res.end(JSON.stringify(relayBody));
	};
	const done = upstreamBody.done === true;
	const upstreamError = upstreamBody.error;
	const hasError = upstreamError !== void 0 && upstreamError !== null && typeof upstreamError === "object";
	if (!done) {
		if (jobs.get(key) === job) {
			if (!job.capturing && job.status !== "completed" && job.status !== "failed") job.status = "in_progress";
			jobs.set(key, job);
		}
		relayJson();
		return;
	}
	if (hasError) {
		if (record.proxyOnly) {
			if (jobs.get(key) === job) {
				job.status = "failed";
				jobs.set(key, job);
			}
			relayJson();
			return;
		}
		if (jobs.get(key) !== job) {
			relayJson();
			return;
		}
		const rawMessage = upstreamError.message;
		const error = typeof rawMessage === "string" && rawMessage ? rawMessage : void 0;
		const video = {
			id: job.upstreamOperationName,
			status: "failed",
			...error !== void 0 ? { error } : {}
		};
		const persistResult = require_recorder.persistFixture({
			record,
			providerKey: "veo",
			testId,
			fixture: {
				match: job.match,
				response: { video }
			},
			fixtures,
			logger
		});
		if (persistResult.kind === "failed" && !res.headersSent) res.setHeader("X-AIMock-Record-Error", require_recorder.sanitizeHeaderValue(persistResult.error));
		jobs.set(key, {
			kind: "replay",
			operationName: job.operationName,
			status: "failed",
			pollCount: 0,
			pollsBeforeInProgress: 0,
			pollsBeforeCompleted: 0,
			video: { ...video }
		});
		relayJson();
		return;
	}
	if (record.proxyOnly) {
		if (jobs.get(key) === job) {
			job.status = "completed";
			jobs.set(key, job);
		}
		relayJson();
		return;
	}
	if (job.capturing || jobs.get(key) !== job) {
		if (jobs.get(key) === job) jobs.set(key, job);
		relayJson();
		return;
	}
	job.capturing = true;
	job.status = "completed";
	jobs.set(key, job);
	relayJson();
	captureVeoVideoRecordFixture({
		job,
		key,
		testId,
		fixtures,
		defaults,
		jobs,
		record,
		upstreamBody
	});
}
/**
* Detached eager-capture for a completed Veo record job. Extracts the
* Files-API uri from the terminal poll body (NO download), persists a
* fixture, and mutates the map entry into a terminal replay job. Every failure
* is handled internally; the returned promise NEVER rejects. World-generation
* guarded immediately before persist.
*/
async function captureVeoVideoRecordFixture(args) {
	const { job, key, testId, fixtures, defaults, jobs, record, upstreamBody } = args;
	const logger = defaults.logger;
	try {
		let uri;
		const response = upstreamBody.response;
		if (response !== null && typeof response === "object" && !Array.isArray(response)) {
			const gvr = response.generateVideoResponse;
			if (gvr !== null && typeof gvr === "object" && !Array.isArray(gvr)) {
				const samples = gvr.generatedSamples;
				const first = Array.isArray(samples) ? samples[0] : void 0;
				if (first !== null && typeof first === "object" && !Array.isArray(first)) {
					const video = first.video;
					if (video !== null && typeof video === "object" && !Array.isArray(video)) {
						const rawUri = video.uri;
						if (typeof rawUri === "string" && rawUri) uri = rawUri;
					}
				}
			}
		}
		if (!uri) {
			logger.warn(`Upstream Veo operation ${job.upstreamOperationName} completed without a usable Files-API uri — capture skipped, nothing persisted; the next completed poll retries`);
			return;
		}
		const video = {
			id: job.upstreamOperationName,
			status: "completed",
			url: uri
		};
		if (jobs.get(key) !== job) {
			logger.warn(`Veo video capture for operation ${job.upstreamOperationName} discarded: the job map no longer holds this job (fixtures reset or TTL eviction) — nothing persisted`);
			return;
		}
		require_recorder.persistFixture({
			record,
			providerKey: "veo",
			testId,
			fixture: {
				match: job.match,
				response: { video }
			},
			fixtures,
			logger
		});
		if (jobs.get(key) === job) jobs.set(key, {
			kind: "replay",
			operationName: job.operationName,
			status: "completed",
			pollCount: 0,
			pollsBeforeInProgress: 0,
			pollsBeforeCompleted: 0,
			video: { ...video }
		});
	} catch (err) {
		const msg = err instanceof Error ? err.message : String(err);
		logger.error(`Veo video capture for operation ${job.upstreamOperationName} failed unexpectedly (${msg}) — fixture not persisted; the job keeps proxying live`);
	} finally {
		if (jobs.get(key) === job) job.capturing = false;
	}
}

//#endregion
exports.VEO_VIDEO_MAX_ENTRIES = VEO_VIDEO_MAX_ENTRIES;
exports.VeoVideoJobMap = VeoVideoJobMap;
exports.handleVeoVideoCreate = handleVeoVideoCreate;
exports.handleVeoVideoStatus = handleVeoVideoStatus;
//# sourceMappingURL=veo-video.cjs.map