import { v as resolveStateDir } from "./paths-CmLVBCTa.js";
import "./json-files-DfheW2NW.js";
import { t as safeEqualSecret } from "./secret-equal-fE0gJd7s.js";
import path from "node:path";
import { stat } from "node:fs/promises";
import { randomBytes } from "node:crypto";
//#region src/shared/operator-scope-compat.ts
const OPERATOR_ROLE = "operator";
const OPERATOR_ADMIN_SCOPE = "operator.admin";
const OPERATOR_READ_SCOPE = "operator.read";
const OPERATOR_WRITE_SCOPE = "operator.write";
const OPERATOR_SCOPE_PREFIX = "operator.";
function normalizeScopeList(scopes) {
	const out = /* @__PURE__ */ new Set();
	for (const scope of scopes) {
		const trimmed = scope.trim();
		if (trimmed) out.add(trimmed);
	}
	return [...out];
}
function operatorScopeSatisfied(requestedScope, granted) {
	if (!requestedScope.startsWith(OPERATOR_SCOPE_PREFIX)) return false;
	if (granted.has(OPERATOR_ADMIN_SCOPE)) return true;
	if (requestedScope === OPERATOR_READ_SCOPE) return granted.has(OPERATOR_READ_SCOPE) || granted.has(OPERATOR_WRITE_SCOPE);
	if (requestedScope === OPERATOR_WRITE_SCOPE) return granted.has(OPERATOR_WRITE_SCOPE);
	return granted.has(requestedScope);
}
function roleScopesAllow(params) {
	const requested = normalizeScopeList(params.requestedScopes);
	if (requested.length === 0) return true;
	const allowed = normalizeScopeList(params.allowedScopes);
	if (allowed.length === 0) return false;
	const allowedSet = new Set(allowed);
	if (params.role.trim() !== OPERATOR_ROLE) {
		const prefix = `${params.role.trim()}.`;
		return requested.every((scope) => scope.startsWith(prefix) && allowedSet.has(scope));
	}
	return requested.every((scope) => operatorScopeSatisfied(scope, allowedSet));
}
function resolveMissingRequestedScope(params) {
	for (const scope of params.requestedScopes) if (!roleScopesAllow({
		role: params.role,
		requestedScopes: [scope],
		allowedScopes: params.allowedScopes
	})) return scope;
	return null;
}
function resolveScopeOutsideRequestedRoles(params) {
	for (const scope of params.requestedScopes) if (!params.requestedRoles.some((role) => roleScopesAllow({
		role,
		requestedScopes: [scope],
		allowedScopes: [scope]
	}))) return scope;
	return null;
}
//#endregion
//#region src/infra/pairing-files.ts
async function readPairingFileSignature(filePath) {
	try {
		const info = await stat(filePath, { bigint: true });
		return {
			mtimeNs: info.mtimeNs,
			size: info.size,
			exists: true
		};
	} catch {
		return {
			mtimeNs: -1n,
			size: -1n,
			exists: false
		};
	}
}
async function readPairingStateSignature(pendingPath, pairedPath) {
	const [pending, paired] = await Promise.all([readPairingFileSignature(pendingPath), readPairingFileSignature(pairedPath)]);
	return {
		pending,
		paired
	};
}
function pairingFileSignaturesEqual(a, b) {
	return a.exists === b.exists && a.mtimeNs === b.mtimeNs && a.size === b.size;
}
function pairingStateSignaturesEqual(a, b) {
	return pairingFileSignaturesEqual(a.pending, b.pending) && pairingFileSignaturesEqual(a.paired, b.paired);
}
function createPairingReadCache(params) {
	let cached = null;
	async function loadStateForRead(baseDir) {
		const { pendingPath, pairedPath } = params.resolvePaths(baseDir);
		const signature = await readPairingStateSignature(pendingPath, pairedPath);
		if (cached && cached.baseDir === baseDir && pairingStateSignaturesEqual(cached.signature, signature)) return cached.state;
		const state = await params.load(baseDir);
		cached = {
			baseDir,
			signature,
			state
		};
		return state;
	}
	function invalidate() {
		cached = null;
	}
	return {
		loadStateForRead,
		invalidate
	};
}
function resolvePairingPaths(baseDir, subdir) {
	const root = baseDir ?? resolveStateDir();
	const dir = path.join(root, subdir);
	return {
		dir,
		pendingPath: path.join(dir, "pending.json"),
		pairedPath: path.join(dir, "paired.json")
	};
}
function coercePairingStateRecord(value) {
	if (!value || typeof value !== "object" || Array.isArray(value)) return {};
	return value;
}
function pruneExpiredPending(pendingById, nowMs, ttlMs) {
	for (const [id, req] of Object.entries(pendingById)) if (nowMs - req.ts > ttlMs) delete pendingById[id];
}
async function reconcilePendingPairingRequests(params) {
	if (params.existing.length === 1 && params.canRefreshSingle(params.existing[0], params.incoming)) {
		const refreshed = params.refreshSingle(params.existing[0], params.incoming);
		params.pendingById[refreshed.requestId] = refreshed;
		await params.persist();
		return {
			status: "pending",
			request: refreshed,
			created: false
		};
	}
	for (const existing of params.existing) delete params.pendingById[existing.requestId];
	const request = params.buildReplacement({
		existing: params.existing,
		incoming: params.incoming
	});
	params.pendingById[request.requestId] = request;
	await params.persist();
	return {
		status: "pending",
		request,
		created: true
	};
}
function generatePairingToken() {
	return randomBytes(32).toString("base64url");
}
function verifyPairingToken(provided, expected) {
	if (provided.trim().length === 0 || expected.trim().length === 0) return false;
	return safeEqualSecret(provided, expected);
}
//#endregion
export { pruneExpiredPending as a, resolveMissingRequestedScope as c, createPairingReadCache as i, resolveScopeOutsideRequestedRoles as l, verifyPairingToken as n, reconcilePendingPairingRequests as o, coercePairingStateRecord as r, resolvePairingPaths as s, generatePairingToken as t, roleScopesAllow as u };
