import { p as finiteSecondsToTimerSafeMilliseconds } from "./number-coercion-CJQ8TR--.js";
import { r as fetchWithSsrFGuard } from "./fetch-guard-B9YUBy5O.js";
import "./media-runtime-D2Zh1jmf.js";
import { t as renderQrTerminal } from "./qr-terminal-zFHurnm4.js";
import "./number-runtime-DBLVDypr.js";
import "./ssrf-runtime-Ca9EhZRd.js";
//#region extensions/feishu/src/app-registration.ts
/**
* Feishu app registration via OAuth device-code flow.
*
* Migrated from feishu-plugin-cli's `feishu-auth.ts` and `install-prompts.ts`.
* Replaces axios with native fetch, removes inquirer/ora/chalk in favor of
* the openclaw WizardPrompter surface.
*/
const FEISHU_ACCOUNTS_URL = "https://accounts.feishu.cn";
const LARK_ACCOUNTS_URL = "https://accounts.larksuite.com";
const REGISTRATION_PATH = "/oauth/v1/app/registration";
const REQUEST_TIMEOUT_MS = 1e4;
const DEFAULT_REGISTRATION_POLL_INTERVAL_SECONDS = 5;
const DEFAULT_REGISTRATION_EXPIRE_SECONDS = 600;
function accountsBaseUrl(domain) {
	return domain === "lark" ? LARK_ACCOUNTS_URL : FEISHU_ACCOUNTS_URL;
}
async function postRegistration(baseUrl, body) {
	return await fetchFeishuJson({
		url: `${baseUrl}${REGISTRATION_PATH}`,
		init: {
			method: "POST",
			headers: { "Content-Type": "application/x-www-form-urlencoded" },
			body: new URLSearchParams(body).toString(),
			signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
		},
		auditContext: "feishu.app-registration.post"
	});
}
async function fetchFeishuJson(params) {
	const { response, release } = await fetchWithSsrFGuard({
		url: params.url,
		init: params.init,
		policy: { allowedHostnames: [new URL(params.url).hostname] },
		auditContext: params.auditContext
	});
	try {
		return await response.json();
	} finally {
		await release();
	}
}
/**
* Step 1: Initialize registration and verify the environment supports
* `client_secret` auth.
*
* @throws If the environment does not support `client_secret`.
*/
async function initAppRegistration(domain = "feishu") {
	if (!(await postRegistration(accountsBaseUrl(domain), { action: "init" })).supported_auth_methods?.includes("client_secret")) throw new Error("Current environment does not support client_secret auth method");
}
/**
* Step 2: Begin the device-code flow. Returns a device code and a QR URL
* that the user should scan with Feishu/Lark mobile app.
*/
async function beginAppRegistration(domain = "feishu") {
	const res = await postRegistration(accountsBaseUrl(domain), {
		action: "begin",
		archetype: "PersonalAgent",
		auth_method: "client_secret",
		request_user_info: "open_id"
	});
	const qrUrl = new URL(res.verification_uri_complete);
	qrUrl.searchParams.set("from", "oc_onboard");
	qrUrl.searchParams.set("tp", "ob_cli_app");
	return {
		deviceCode: res.device_code,
		qrUrl: qrUrl.toString(),
		userCode: res.user_code,
		interval: finiteSecondsToTimerSafeMilliseconds(res.interval) === void 0 ? DEFAULT_REGISTRATION_POLL_INTERVAL_SECONDS : res.interval,
		expireIn: finiteSecondsToTimerSafeMilliseconds(res.expire_in) === void 0 ? DEFAULT_REGISTRATION_EXPIRE_SECONDS : res.expire_in
	};
}
/**
* Step 3: Poll for authorization result until success, denial, expiry, or
* timeout. Automatically handles domain switching when `tenant_brand` is
* detected as "lark".
*/
async function pollAppRegistration(params) {
	const { deviceCode, expireIn, initialDomain = "feishu", abortSignal, tp } = params;
	let currentInterval = params.interval;
	let domain = initialDomain;
	let domainSwitched = false;
	const expireInMs = finiteSecondsToTimerSafeMilliseconds(expireIn) ?? finiteSecondsToTimerSafeMilliseconds(DEFAULT_REGISTRATION_EXPIRE_SECONDS) ?? REQUEST_TIMEOUT_MS;
	const deadline = Date.now() + expireInMs;
	while (Date.now() < deadline) {
		if (abortSignal?.aborted) return { status: "timeout" };
		const baseUrl = accountsBaseUrl(domain);
		let pollRes;
		try {
			pollRes = await postRegistration(baseUrl, {
				action: "poll",
				device_code: deviceCode,
				...tp ? { tp } : {}
			});
		} catch {
			await sleepRegistrationPollInterval(currentInterval);
			continue;
		}
		if (pollRes.user_info?.tenant_brand) {
			const isLark = pollRes.user_info.tenant_brand === "lark";
			if (!domainSwitched && isLark) {
				domain = "lark";
				domainSwitched = true;
				continue;
			}
		}
		if (pollRes.client_id && pollRes.client_secret) return {
			status: "success",
			result: {
				appId: pollRes.client_id,
				appSecret: pollRes.client_secret,
				domain,
				openId: pollRes.user_info?.open_id
			}
		};
		if (pollRes.error) if (pollRes.error === "authorization_pending") {} else if (pollRes.error === "slow_down") currentInterval += 5;
		else if (pollRes.error === "access_denied") return { status: "access_denied" };
		else if (pollRes.error === "expired_token") return { status: "expired" };
		else return {
			status: "error",
			message: `${pollRes.error}: ${pollRes.error_description ?? "unknown"}`
		};
		await sleepRegistrationPollInterval(currentInterval);
	}
	return { status: "timeout" };
}
/**
* Print QR code directly to stdout.
*
* QR codes must be printed without any surrounding box/border decoration,
* otherwise the pattern is corrupted and cannot be scanned.
*/
async function printQrCode(url) {
	const output = await renderQrTerminal(url);
	process.stdout.write(output.endsWith("\n") ? output : `${output}\n`);
}
/**
* Fetch the app owner's open_id using the application.v6.application.get API.
*
* Used during setup to auto-populate security policy allowlists.
* Returns undefined on any failure (fail-open).
*/
async function getAppOwnerOpenId(params) {
	const baseUrl = params.domain === "lark" ? "https://open.larksuite.com" : "https://open.feishu.cn";
	try {
		const tokenData = await fetchFeishuJson({
			url: `${baseUrl}/open-apis/auth/v3/tenant_access_token/internal`,
			init: {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({
					app_id: params.appId,
					app_secret: params.appSecret
				}),
				signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
			},
			auditContext: "feishu.app-registration.owner-token"
		});
		if (!tokenData.tenant_access_token) return;
		const appData = await fetchFeishuJson({
			url: `${baseUrl}/open-apis/application/v6/applications/${params.appId}?user_id_type=open_id`,
			init: {
				method: "GET",
				headers: {
					Authorization: `Bearer ${tokenData.tenant_access_token}`,
					"Content-Type": "application/json"
				},
				signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
			},
			auditContext: "feishu.app-registration.owner-app"
		});
		if (appData.code !== 0) return;
		const app = appData.data?.app;
		const owner = app?.owner;
		return (owner?.owner_type ?? owner?.type) === 2 && owner?.owner_id ? owner.owner_id : app?.creator_id ?? owner?.owner_id;
	} catch {
		return;
	}
}
function sleep(ms) {
	return new Promise((resolve) => {
		setTimeout(resolve, ms);
	});
}
function sleepRegistrationPollInterval(intervalSeconds) {
	return sleep(finiteSecondsToTimerSafeMilliseconds(intervalSeconds) ?? finiteSecondsToTimerSafeMilliseconds(DEFAULT_REGISTRATION_POLL_INTERVAL_SECONDS) ?? REQUEST_TIMEOUT_MS);
}
//#endregion
export { beginAppRegistration, getAppOwnerOpenId, initAppRegistration, pollAppRegistration, printQrCode };
