import { MAX_SKILL_ZIP_BYTES, isValidSkillId } from "../../../managed-store.js";
import { MAX_EXTENSION_STORE_ZIP_BYTES } from "../../../../../extensions/store-zip-limits.js";
//#region src/agent/skills/marketplace/adapters/store/store-api-client.ts
const DEFAULT_STORE_BASE = "https://store.xopc.ai";
function resolveSkillsStoreBaseUrl(config) {
	const env = process.env.XOPC_SKILLS_STORE_URL?.trim();
	if (env) try {
		return normalizeBaseUrl(new URL(env).toString());
	} catch {}
	const fromConfig = config.gateway?.skillsStoreBaseUrl?.trim();
	if (fromConfig) try {
		return normalizeBaseUrl(new URL(fromConfig).toString());
	} catch {
		return DEFAULT_STORE_BASE;
	}
	return DEFAULT_STORE_BASE;
}
/**
* Base URL for extension downloads (defaults to skills store host — usually store.xopc.ai).
* Override with `XOPC_EXTENSIONS_STORE_URL`.
*/
function resolveExtensionsStoreBaseUrl(config) {
	const env = process.env.XOPC_EXTENSIONS_STORE_URL?.trim();
	if (env) try {
		return normalizeBaseUrl(new URL(env).toString());
	} catch {}
	return resolveSkillsStoreBaseUrl(config);
}
function normalizeBaseUrl(url) {
	return url.replace(/\/$/, "");
}
function getStoreOrigin(baseUrl) {
	const u = new URL(baseUrl);
	return `${u.protocol}//${u.host}`;
}
/**
* Allow download URLs whose origin matches the configured store base (SSRF guard).
* Production store is HTTPS-only; local dev (`http://localhost` / `127.0.0.1`) may use HTTP.
*/
function assertDownloadUrlAllowed(downloadUrl, storeBaseUrl) {
	let u;
	try {
		u = new URL(downloadUrl);
	} catch {
		throw new Error("Invalid download URL from store");
	}
	const allowed = new URL(storeBaseUrl);
	if (allowed.protocol === "http:" && (allowed.hostname === "localhost" || allowed.hostname === "127.0.0.1")) {
		if (u.protocol !== "http:" && u.protocol !== "https:") throw new Error("Download URL must use HTTP or HTTPS");
	} else if (u.protocol !== "https:") throw new Error("Download URL must use HTTPS");
	if (u.host !== allowed.host) throw new Error("Download URL host does not match configured store host");
	return u;
}
async function fetchJson(url, init) {
	const res = await fetch(url, {
		...init,
		headers: {
			Accept: "application/json",
			...init?.headers
		}
	});
	const text = await res.text();
	if (!res.ok) {
		let msg = `Store request failed (${res.status})`;
		try {
			const j = JSON.parse(text);
			if (j.error?.message) msg = j.error.message;
		} catch {
			if (text) msg = text.slice(0, 200);
		}
		throw new Error(msg);
	}
	try {
		return JSON.parse(text);
	} catch {
		throw new Error("Store returned invalid JSON");
	}
}
async function listSkillPackages(storeBaseUrl, params) {
	const base = normalizeBaseUrl(storeBaseUrl);
	const sp = new URLSearchParams();
	sp.set("type", "skill");
	if (params.q?.trim()) sp.set("q", params.q.trim());
	if (params.page != null) sp.set("page", String(params.page));
	if (params.pageSize != null) sp.set("pageSize", String(params.pageSize));
	if (params.sort) sp.set("sort", params.sort);
	if (params.category?.trim()) sp.set("category", params.category.trim());
	return fetchJson(`${base}/api/v1/packages?${sp.toString()}`);
}
async function fetchMarketplacePackageDetail(storeBaseUrl, packageName) {
	return fetchJson(`${normalizeBaseUrl(storeBaseUrl)}/api/v1/packages/${encodeURIComponent(packageName.trim())}`);
}
async function resolveSkillZipDownloadUrl(storeBaseUrl, packageName, version) {
	const base = normalizeBaseUrl(storeBaseUrl);
	const enc = encodeURIComponent(packageName);
	if (version?.trim()) {
		const detail = await fetchJson(`${base}/api/v1/packages/${enc}/versions/${encodeURIComponent(version.trim())}`);
		if (!detail.downloadUrl) throw new Error("Store version has no download URL");
		assertDownloadUrlAllowed(detail.downloadUrl, base);
		return {
			downloadUrl: detail.downloadUrl,
			version: detail.version
		};
	}
	const pkg = await fetchJson(`${base}/api/v1/packages/${enc}`);
	if (!pkg.latestVersion?.downloadUrl) throw new Error("Package has no published version");
	assertDownloadUrlAllowed(pkg.latestVersion.downloadUrl, base);
	return {
		downloadUrl: pkg.latestVersion.downloadUrl,
		version: pkg.latestVersion.version
	};
}
async function downloadSkillZipBuffer(storeBaseUrl, downloadUrl) {
	assertDownloadUrlAllowed(downloadUrl, normalizeBaseUrl(storeBaseUrl));
	const res = await fetch(downloadUrl, { redirect: "follow" });
	if (!res.ok) throw new Error(`Failed to download skill archive (${res.status})`);
	const len = res.headers.get("content-length");
	if (len) {
		const n = Number(len);
		if (Number.isFinite(n) && n > 15728640) throw new Error(`Zip exceeds maximum size (${MAX_SKILL_ZIP_BYTES} bytes)`);
	}
	const ab = await res.arrayBuffer();
	const buf = Buffer.from(ab);
	if (buf.length > 15728640) throw new Error(`Zip exceeds maximum size (${MAX_SKILL_ZIP_BYTES} bytes)`);
	return buf;
}
async function resolveExtensionZipDownloadUrl(storeBaseUrl, packageName, version) {
	const base = normalizeBaseUrl(storeBaseUrl);
	const enc = encodeURIComponent(packageName.trim());
	const meta = await fetchJson(`${base}/api/v1/packages/${enc}`);
	if (meta.type !== "extension") throw new Error(`Package "${packageName}" has type "${meta.type}" (expected extension). Use \`xopc skills install\` for skills.`);
	if (version?.trim()) {
		const detail = await fetchJson(`${base}/api/v1/packages/${enc}/versions/${encodeURIComponent(version.trim())}`);
		if (!detail.downloadUrl) throw new Error("Store version has no download URL");
		assertDownloadUrlAllowed(detail.downloadUrl, base);
		return {
			downloadUrl: detail.downloadUrl,
			version: detail.version
		};
	}
	const lv = meta.latestVersion;
	if (!lv?.downloadUrl) throw new Error("Package has no published version");
	assertDownloadUrlAllowed(lv.downloadUrl, base);
	return {
		downloadUrl: lv.downloadUrl,
		version: lv.version
	};
}
async function downloadExtensionStoreZipBuffer(storeBaseUrl, downloadUrl) {
	assertDownloadUrlAllowed(downloadUrl, normalizeBaseUrl(storeBaseUrl));
	const res = await fetch(downloadUrl, { redirect: "follow" });
	if (!res.ok) throw new Error(`Failed to download extension archive (${res.status})`);
	const len = res.headers.get("content-length");
	if (len) {
		const n = Number(len);
		if (Number.isFinite(n) && n > 10485760) throw new Error(`Zip exceeds maximum size (${MAX_EXTENSION_STORE_ZIP_BYTES} bytes)`);
	}
	const ab = await res.arrayBuffer();
	const buf = Buffer.from(ab);
	if (buf.length > 10485760) throw new Error(`Zip exceeds maximum size (${MAX_EXTENSION_STORE_ZIP_BYTES} bytes)`);
	return buf;
}
function skillIdForMarketplaceInstall(packageName) {
	const trimmed = packageName.trim();
	if (!trimmed) return void 0;
	return isValidSkillId(trimmed) ? trimmed : void 0;
}
//#endregion
export { MAX_EXTENSION_STORE_ZIP_BYTES, assertDownloadUrlAllowed, downloadExtensionStoreZipBuffer, downloadSkillZipBuffer, fetchMarketplacePackageDetail, getStoreOrigin, listSkillPackages, resolveExtensionZipDownloadUrl, resolveExtensionsStoreBaseUrl, resolveSkillZipDownloadUrl, resolveSkillsStoreBaseUrl, skillIdForMarketplaceInstall };

//# sourceMappingURL=store-api-client.js.map