//#region src/index.ts
var AIError = class extends Error {};
var RateLimitError = class extends AIError {
	provider;
	cause;
	name = "RateLimitError";
	retryable = true;
	constructor(message, provider, cause) {
		super(message);
		this.provider = provider;
		this.cause = cause;
	}
};
var TransientError = class extends AIError {
	provider;
	cause;
	name = "TransientError";
	retryable = true;
	constructor(message, provider, cause) {
		super(message);
		this.provider = provider;
		this.cause = cause;
	}
};
var QuotaExhaustedError = class extends AIError {
	provider;
	cause;
	name = "QuotaExhaustedError";
	retryable = true;
	constructor(message, provider, cause) {
		super(message);
		this.provider = provider;
		this.cause = cause;
	}
};
var AuthError = class extends AIError {
	provider;
	cause;
	name = "AuthError";
	retryable = false;
	constructor(message, provider, cause) {
		super(message);
		this.provider = provider;
		this.cause = cause;
	}
};
var FatalError = class extends AIError {
	provider;
	cause;
	name = "FatalError";
	retryable = false;
	constructor(message, provider, cause) {
		super(message);
		this.provider = provider;
		this.cause = cause;
	}
};
var AllModelsFailedError = class extends FatalError {
	lastError;
	constructor(message, lastError) {
		super(message);
		this.lastError = lastError;
	}
};
let adapterFactories = {};
/** Wire adapter subpath makers without importing them from core (tree-shake safe). */
function setAdapterFactories(factories) {
	adapterFactories = {
		...adapterFactories,
		...factories
	};
}
function getAdapter(provider, creds) {
	const factory = adapterFactories[provider];
	if (!factory) throw new FatalError(`No adapter factory registered for "${provider}". Import @platform-modules/ai/${provider} and register its maker via setAdapterFactories.`, provider);
	return factory(creds);
}
function withTimeout(promise, ms) {
	let timeoutId;
	const timeoutPromise = new Promise((_, reject) => {
		timeoutId = setTimeout(() => {
			reject(new TransientError(`Request timed out after ${ms}ms`));
		}, ms);
	});
	return Promise.race([promise, timeoutPromise]).finally(() => {
		if (timeoutId !== void 0) clearTimeout(timeoutId);
	});
}
function isRetryableError(err) {
	return err instanceof AIError && err.retryable;
}
const ALLOWED_USAGE_KEYS = /* @__PURE__ */ new Set(["promptTokens", "completionTokens"]);
/**
* Runtime boundary guard — usage must carry token counts and NOTHING else.
* Allowlist (not a denylist): the spec mandates `{ promptTokens, completionTokens }`
* exactly, so any extra key — cost/price/credits, a novel currency name, or a nested
* accounting object — is a host-domain leak and is rejected. Cost is host-domain.
*/
function assertUsageBoundary(usage) {
	const record = usage;
	for (const key of Object.keys(record)) if (!ALLOWED_USAGE_KEYS.has(key)) throw new FatalError(`AIResponse.usage must carry only promptTokens/completionTokens — found host-domain field "${key}"`);
	if (typeof usage.promptTokens !== "number" || typeof usage.completionTokens !== "number") throw new FatalError("AIResponse.usage requires promptTokens and completionTokens");
	if (!Number.isFinite(usage.promptTokens) || usage.promptTokens < 0 || !Number.isFinite(usage.completionTokens) || usage.completionTokens < 0) throw new FatalError("AIResponse.usage token counts must be finite non-negative numbers");
}
async function executeWithFallback(req, chain, opts) {
	if (chain.length === 0) throw new AllModelsFailedError("All models failed");
	const timeoutMs = opts?.timeoutMs ?? 3e4;
	let lastError;
	for (const entry of chain) {
		const callReq = entry.model !== void 0 && entry.model !== req.model ? {
			...req,
			model: entry.model
		} : req;
		try {
			const response = await withTimeout(entry.adapter.call(callReq), timeoutMs);
			assertUsageBoundary(response.usage);
			return response;
		} catch (err) {
			if (isRetryableError(err) || opts?.continueOnNonRetryable === true && err instanceof AIError) {
				lastError = err;
				continue;
			}
			throw err;
		}
	}
	throw new AllModelsFailedError(`All models failed${lastError ? `: ${lastError.message}` : ""}`, lastError);
}
//#endregion
export { AIError, AllModelsFailedError, AuthError, FatalError, QuotaExhaustedError, RateLimitError, TransientError, assertUsageBoundary, executeWithFallback, getAdapter, setAdapterFactories, withTimeout };
