import { c as kindFromMime } from "./mime-C8mVE2Bw.js";
import { r as stripInlineDirectiveTagsForDelivery } from "./directive-tags-CcNbnqII.js";
import { i as createActionGate } from "./common-Bg0gj4mC.js";
import { t as createMessageReceiptFromOutboundResults } from "./receipt-B3SXxhHV.js";
import { n as resolveOutboundAttachmentFromUrl } from "./outbound-attachment-Bl0dXppU.js";
import "./media-runtime-D2Zh1jmf.js";
import { t as convertMarkdownTables } from "./tables-CNojwOtD.js";
import "./text-chunking-B61JF88o.js";
import { t as resolveMarkdownTableMode } from "./markdown-tables-BK5fqc40.js";
import { t as requireRuntimeConfig } from "./plugin-config-runtime-KEzHMfVG.js";
import "./channel-outbound-CPipAH4X.js";
import "./markdown-table-runtime-BixxlQ89.js";
import "./channel-actions-xRh4Go2j.js";
import { a as resolveIMessageAccount } from "./accounts-Bx5royFK.js";
import { t as createIMessageRpcClient } from "./client-D95ZgyFW.js";
import { c as parseIMessageTarget, o as normalizeIMessageHandle, t as formatIMessageChatTarget } from "./targets-CfBWfz9c.js";
import { s as rememberIMessageReplyCache } from "./monitor-reply-cache-ROMrYdRl.js";
import { a as extractIMessageApprovalPromptBinding, i as appendIMessageApprovalReactionHintForOutboundMessage, u as registerIMessageApprovalReactionTargetForOutboundMessage } from "./normalize-BTW8zymF.js";
import { a as rememberPersistedIMessageEcho, r as forgetPersistedIMessageEchoKey } from "./persisted-echo-cache-BxW7NiEe.js";
import { n as appendIMessageCliStderrTail, r as appendIMessageCliStdout, t as extractMarkdownFormatRuns } from "./markdown-format-41-kk349.js";
import { createRequire } from "node:module";
import { accessSync, constants, readFileSync } from "node:fs";
import path from "node:path";
import os from "node:os";
import { spawn } from "node:child_process";
//#region extensions/imessage/src/send.ts
const require = createRequire(import.meta.url);
const MIN_PENDING_PERSISTED_ECHO_TTL_MS = 6e4;
const PENDING_PERSISTED_ECHO_GRACE_MS = 5e3;
const MAX_REPLY_TO_ID_LENGTH = 256;
const sshWrapperCliPathCache = /* @__PURE__ */ new Map();
function safeHomeDir() {
	const home = process.env.HOME?.trim();
	if (home) return home;
	try {
		return os.homedir().trim() || void 0;
	} catch {
		return;
	}
}
function expandCliPathForInspection(cliPath) {
	if (!cliPath.startsWith("~")) return cliPath;
	const home = safeHomeDir();
	return home ? cliPath.replace(/^~(?=$|[\\/])/, home) : cliPath;
}
function isSshIMessageCliWrapper(cliPath) {
	if (cliPath === "imsg") return false;
	const cached = sshWrapperCliPathCache.get(cliPath);
	if (cached !== void 0) return cached;
	let detected;
	try {
		const content = readFileSync(expandCliPathForInspection(cliPath), "utf8");
		detected = /\bssh\b[\s\S]*\bimsg\b/u.test(content);
	} catch {
		detected = false;
	}
	sshWrapperCliPathCache.set(cliPath, detected);
	return detected;
}
function isLocalIMessageCliPath(params) {
	const cliPath = params.cliPath.trim();
	if (params.remoteHost?.trim() || isSshIMessageCliWrapper(cliPath)) return false;
	return cliPath === "imsg" || path.basename(cliPath) === "imsg";
}
function resolveChatDbLookupPath(params) {
	const configured = params.dbPath?.trim();
	if (configured) return configured;
	if (!isLocalIMessageCliPath({
		cliPath: params.cliPath,
		remoteHost: params.remoteHost
	})) return;
	const home = safeHomeDir();
	return home ? path.join(home, "Library", "Messages", "chat.db") : void 0;
}
function stripUnsafeReplyTagChars(value) {
	let next = "";
	for (const ch of value) {
		const code = ch.charCodeAt(0);
		if (code >= 0 && code <= 31 || code === 127 || ch === "[" || ch === "]") continue;
		next += ch;
	}
	return next;
}
function sanitizeReplyToId(rawReplyToId) {
	const trimmed = rawReplyToId?.trim();
	if (!trimmed) return;
	const sanitized = stripUnsafeReplyTagChars(trimmed).trim();
	if (!sanitized) return;
	if (sanitized.length > MAX_REPLY_TO_ID_LENGTH) return sanitized.slice(0, MAX_REPLY_TO_ID_LENGTH);
	return sanitized;
}
function resolveMessageId(result) {
	if (!result) return null;
	const raw = typeof result.messageId === "string" && result.messageId.trim() || typeof result.message_id === "string" && result.message_id.trim() || typeof result.id === "string" && result.id.trim() || typeof result.guid === "string" && result.guid.trim() || (typeof result.message_id === "number" ? String(result.message_id) : null) || (typeof result.id === "number" ? String(result.id) : null);
	return raw ? raw.trim() : null;
}
function resolveOutboundMessageGuid(result) {
	if (!result) return null;
	const candidates = [
		result.guid,
		result.messageId,
		result.message_id,
		result.id
	];
	for (const value of candidates) {
		if (typeof value !== "string") continue;
		const trimmed = value.trim();
		if (trimmed && !/^\d+$/.test(trimmed)) return trimmed;
	}
	return null;
}
function isNumericMessageRowId(value) {
	return typeof value === "string" && /^\d+$/.test(value.trim());
}
function resolveTargetService(target) {
	if (target.kind !== "handle") return;
	if (target.serviceExplicit || target.service !== "auto") return target.service;
}
function normalizeResolvedMessageGuid(value) {
	if (typeof value !== "string") return null;
	const trimmed = value.trim();
	return trimmed && !isNumericMessageRowId(trimmed) ? trimmed : null;
}
function loadNodeSqlite() {
	try {
		return require("node:sqlite");
	} catch {
		return null;
	}
}
function resolveMessageGuidFromChatDb(params) {
	const dbPath = params.dbPath?.trim();
	const messageId = params.messageId.trim();
	if (!dbPath || !isNumericMessageRowId(messageId)) return null;
	const sqlite = loadNodeSqlite();
	if (!sqlite) return null;
	let db = null;
	try {
		db = new sqlite.DatabaseSync(dbPath, { readOnly: true });
		return normalizeResolvedMessageGuid(db.prepare("SELECT guid FROM message WHERE ROWID = ?").get(messageId)?.guid);
	} catch {
		return null;
	} finally {
		try {
			db?.close();
		} catch {}
	}
}
function getStringRowValue(row, key) {
	return normalizeResolvedMessageGuid(row?.[key]);
}
function appleMessageDateLowerBoundMs(sentAfterMs) {
	if (!Number.isFinite(sentAfterMs)) return null;
	return Math.max(0, Math.floor((sentAfterMs - 9783072e5 - 5e3) * 1e6));
}
function resolveLatestSentMessageGuidFromChatDb(params) {
	const dbPath = params.dbPath?.trim();
	if (!dbPath) return null;
	const sqlite = loadNodeSqlite();
	if (!sqlite) return null;
	let db = null;
	try {
		db = new sqlite.DatabaseSync(dbPath, { readOnly: true });
		const targetClauses = [];
		const targetParams = [];
		const lowerBound = appleMessageDateLowerBoundMs(params.sentAfterMs);
		if (params.text) {
			targetClauses.push("m.text = ?");
			targetParams.push(params.text);
		}
		if (lowerBound !== null) {
			targetClauses.push("m.date >= ?");
			targetParams.push(lowerBound);
		}
		if (params.target.kind === "chat_id") {
			targetClauses.push("cmj.chat_id = ?");
			targetParams.push(params.target.chatId);
		} else if (params.target.kind === "chat_guid") {
			targetClauses.push("c.guid = ?");
			targetParams.push(params.target.chatGuid);
		} else if (params.target.kind === "chat_identifier") {
			targetClauses.push("c.chat_identifier = ?");
			targetParams.push(params.target.chatIdentifier);
		} else {
			const normalizedHandle = normalizeIMessageHandle(params.target.to);
			targetClauses.push("(h.id = ? OR h.uncanonicalized_id = ?)");
			targetParams.push(normalizedHandle, params.target.to);
		}
		const selectSql = `
      SELECT m.guid
      FROM message m
      LEFT JOIN chat_message_join cmj ON cmj.message_id = m.ROWID
      LEFT JOIN chat c ON c.ROWID = cmj.chat_id
      LEFT JOIN handle h ON h.ROWID = m.handle_id
      WHERE m.is_from_me = 1
      ${targetClauses.length ? `AND ${targetClauses.join(" AND ")}` : ""}
      ORDER BY m.date DESC, m.ROWID DESC
      LIMIT 10
    `;
		return getStringRowValue(db.prepare(selectSql).all(...targetParams)[0], "guid");
	} catch {
		return null;
	} finally {
		try {
			db?.close();
		} catch {}
	}
}
function canResolveLatestSentMessageGuidFromChatDb(dbPath) {
	const normalizedDbPath = dbPath?.trim();
	if (!normalizedDbPath || !loadNodeSqlite()) return false;
	try {
		accessSync(normalizedDbPath, constants.R_OK);
		return true;
	} catch {
		return false;
	}
}
async function resolveApprovalBindingMessageGuid(params) {
	const immediateGuid = resolveOutboundMessageGuid(params.result);
	if (immediateGuid) return immediateGuid;
	const messageId = params.messageId?.trim();
	if (!messageId || !isNumericMessageRowId(messageId)) return null;
	return normalizeResolvedMessageGuid(await (params.resolveMessageGuidImpl ?? resolveMessageGuidFromChatDb)({
		dbPath: params.dbPath,
		messageId
	}));
}
function delay(ms) {
	return new Promise((resolve) => {
		setTimeout(resolve, ms);
	});
}
async function resolveFallbackSentMessageGuid(params) {
	const resolver = params.resolveSentMessageGuidImpl ?? resolveLatestSentMessageGuidFromChatDb;
	if (!params.resolveSentMessageGuidImpl && !canResolveLatestSentMessageGuidFromChatDb(params.dbPath)) return null;
	const deadlineMs = Date.now() + 5e3;
	while (Date.now() <= deadlineMs) {
		const resolved = normalizeResolvedMessageGuid(await resolver({
			dbPath: params.dbPath,
			target: params.target,
			text: params.text,
			sentAfterMs: params.sentAfterMs
		}));
		if (resolved) return resolved;
		if (Date.now() >= deadlineMs) return null;
		await delay(250);
	}
	return null;
}
function shouldRecoverApprovalPromptGuid(params) {
	return !params.filePath && !params.replyToId && Boolean(params.message.trim()) && Boolean(extractIMessageApprovalPromptBinding(params.message));
}
function canCheckSentMessageAfterRpcTimeout(params) {
	return Boolean(params.resolveSentMessageGuidImpl) || canResolveLatestSentMessageGuidFromChatDb(params.dbPath);
}
function resolveOutboundEchoText(text, mediaContentType) {
	if (text.trim()) return text;
	const kind = kindFromMime(mediaContentType ?? void 0);
	if (!kind) return;
	return kind === "image" ? "<media:image>" : `<media:${kind}>`;
}
function createIMessageSendReceipt(params) {
	const messageId = params.messageId.trim();
	const results = messageId && messageId !== "unknown" && messageId !== "ok" ? [{
		channel: "imessage",
		messageId,
		meta: { targetKind: params.target.kind }
	}] : [];
	if (results[0]) {
		if (params.target.kind === "chat_id") results[0].chatId = String(params.target.chatId);
		else if (params.target.kind === "chat_guid") results[0].conversationId = params.target.chatGuid;
		else if (params.target.kind === "chat_identifier") results[0].conversationId = params.target.chatIdentifier;
	}
	const receiptParams = {
		results,
		kind: params.kind
	};
	if (params.replyToId) receiptParams.replyToId = params.replyToId;
	return createMessageReceiptFromOutboundResults(receiptParams);
}
function isConcreteIMessageMessageId(messageId) {
	const trimmed = messageId?.trim();
	return Boolean(trimmed && trimmed !== "unknown" && trimmed !== "ok");
}
function canSynthesizeAttachmentChatHandle(raw) {
	const trimmed = raw.trim();
	return trimmed.includes("@") || trimmed.startsWith("+");
}
function resolveOutboundEchoScope(params) {
	if (params.target.kind === "chat_id") return `${params.accountId}:${formatIMessageChatTarget(params.target.chatId)}`;
	if (params.target.kind === "chat_guid") return `${params.accountId}:chat_guid:${params.target.chatGuid}`;
	if (params.target.kind === "chat_identifier") return `${params.accountId}:chat_identifier:${params.target.chatIdentifier}`;
	return `${params.accountId}:imessage:${params.target.to}`;
}
function buildIMessageCliJsonArgs(args, dbPath) {
	const trimmedDbPath = dbPath?.trim();
	return [
		...args,
		...trimmedDbPath ? ["--db", trimmedDbPath] : [],
		"--json"
	];
}
function resolveIMessageCliFailure(result) {
	if (result.success !== false) return null;
	return typeof result.error === "string" && result.error.trim() ? result.error.trim() : "iMessage action failed";
}
function isIMessageRpcSendTimeout(error) {
	const message = error instanceof Error ? error.message : String(error);
	return /imsg rpc timeout \(send\)/i.test(message);
}
async function runIMessageCliJson(cliPath, dbPath, args, timeoutMs) {
	return await new Promise((resolve, reject) => {
		const child = spawn(cliPath, buildIMessageCliJsonArgs(args, dbPath), { stdio: [
			"ignore",
			"pipe",
			"pipe"
		] });
		let stdout = "";
		let stderr = "";
		let killEscalation = null;
		let settled = false;
		const clearTimers = (options = {}) => {
			if (timer) clearTimeout(timer);
			if (killEscalation && !options.keepKillEscalation) clearTimeout(killEscalation);
		};
		const fail = (error, options = {}) => {
			if (settled) return;
			settled = true;
			clearTimers(options);
			reject(error);
		};
		const succeed = (value) => {
			if (settled) return;
			settled = true;
			clearTimers();
			resolve(value);
		};
		const timer = timeoutMs && timeoutMs > 0 ? setTimeout(() => {
			child.kill("SIGTERM");
			killEscalation = setTimeout(() => {
				try {
					child.kill("SIGKILL");
				} catch {}
			}, 2e3);
			fail(/* @__PURE__ */ new Error(`iMessage action timed out after ${timeoutMs}ms`), { keepKillEscalation: true });
		}, timeoutMs) : null;
		child.stdout.setEncoding("utf8");
		child.stderr.setEncoding("utf8");
		child.stdout.on("data", (chunk) => {
			if (settled) return;
			const appended = appendIMessageCliStdout(stdout, chunk);
			if (!appended.ok) {
				try {
					child.kill("SIGKILL");
				} catch {}
				fail(new Error(appended.message));
				return;
			}
			stdout = appended.value;
		});
		child.stderr.on("data", (chunk) => {
			stderr = appendIMessageCliStderrTail(stderr, chunk);
		});
		child.on("error", (error) => {
			if (settled) {
				clearTimers();
				return;
			}
			fail(error);
		});
		child.on("close", (code) => {
			if (settled) {
				clearTimers();
				return;
			}
			const last = stdout.split(/\r?\n/u).map((line) => line.trim()).filter(Boolean).at(-1);
			let parsed = null;
			if (last) try {
				const json = JSON.parse(last);
				if (json && typeof json === "object" && !Array.isArray(json)) parsed = json;
			} catch {}
			if (code === 0 && parsed) {
				const failure = resolveIMessageCliFailure(parsed);
				if (failure) {
					fail(new Error(failure));
					return;
				}
				succeed(parsed);
				return;
			}
			if (parsed && typeof parsed.error === "string" && parsed.error.trim()) {
				fail(new Error(parsed.error.trim()));
				return;
			}
			const detail = stderr.trim() || stdout.trim() || `imsg exited with code ${code}`;
			fail(new Error(detail));
		});
	});
}
function stringValue(value) {
	return typeof value === "string" && value.trim() ? value.trim() : void 0;
}
function resolvePendingPersistedEchoTtlMs(timeoutMs) {
	return Math.max(MIN_PENDING_PERSISTED_ECHO_TTL_MS, Math.max(0, timeoutMs) + PENDING_PERSISTED_ECHO_GRACE_MS);
}
function isAttachmentCommandFallbackError(error) {
	const message = error instanceof Error ? error.message : String(error);
	return /(?:unknown|unrecognized|invalid|unsupported)\s+(?:command|subcommand)|not a recognized command|send-attachment.*(?:not found|unsupported|unavailable)|private api bridge.*unavailable|requires the imsg private api bridge|run imsg launch/iu.test(message);
}
async function resolveAttachmentChatTarget(params) {
	if (params.target.kind === "chat_guid") return params.target.chatGuid;
	if (params.target.kind === "handle") {
		if (!canSynthesizeAttachmentChatHandle(params.target.to)) return null;
		const normalizedHandle = normalizeIMessageHandle(params.target.to);
		if (!normalizedHandle) return null;
		const service = params.target.service !== "auto" ? params.target.service : params.service;
		if (service === "sms") return `SMS;-;${normalizedHandle}`;
		if (service === "imessage") return `iMessage;-;${normalizedHandle}`;
		return `any;-;${normalizedHandle}`;
	}
	if (params.target.kind !== "chat_id") return null;
	const result = await params.runCliJson([
		"group",
		"--chat-id",
		String(params.target.chatId)
	]);
	return stringValue(result.guid) ?? stringValue(result.chat_guid) ?? null;
}
async function trySendAttachmentForTarget(params) {
	let attachmentChatTarget;
	try {
		attachmentChatTarget = await resolveAttachmentChatTarget({
			target: params.target,
			service: params.service,
			runCliJson: params.runCliJson
		});
	} catch (error) {
		if (isAttachmentCommandFallbackError(error)) return null;
		throw error;
	}
	if (!attachmentChatTarget) return null;
	const echoScope = resolveOutboundEchoScope({
		accountId: params.accountId,
		target: params.target
	});
	let result;
	let pendingEchoKey;
	try {
		if (echoScope) pendingEchoKey = rememberPersistedIMessageEcho({
			scope: echoScope,
			text: params.echoText,
			ttlMs: params.pendingEchoTtlMs,
			pending: true
		});
		result = await params.runCliJson([
			"send-attachment",
			"--chat",
			attachmentChatTarget,
			"--file",
			params.filePath,
			...params.audioAsVoice ? ["--audio"] : [],
			...params.replyToId ? ["--reply-to", params.replyToId] : [],
			"--transport",
			"auto"
		]);
	} catch (error) {
		forgetPersistedIMessageEchoKey(pendingEchoKey);
		if (isAttachmentCommandFallbackError(error)) return null;
		throw error;
	}
	const failure = resolveIMessageCliFailure(result);
	if (failure) {
		const error = new Error(failure);
		forgetPersistedIMessageEchoKey(pendingEchoKey);
		if (isAttachmentCommandFallbackError(error)) return null;
		throw error;
	}
	const resolvedId = resolveMessageId(result);
	const approvalBindingMessageId = await resolveApprovalBindingMessageGuid({
		dbPath: params.dbPath,
		messageId: resolvedId,
		result,
		resolveMessageGuidImpl: params.resolveMessageGuidImpl
	});
	const messageId = resolvedId ?? (result.ok || result.success ? "ok" : "unknown");
	if (echoScope) rememberPersistedIMessageEcho({
		scope: echoScope,
		text: params.echoText,
		messageId: resolvedId ?? void 0
	});
	if (resolvedId) rememberIMessageReplyCache({
		accountId: params.accountId,
		messageId: resolvedId,
		chatGuid: params.target.kind === "chat_guid" ? params.target.chatGuid : params.target.kind === "chat_id" ? attachmentChatTarget : void 0,
		chatIdentifier: params.target.kind === "chat_identifier" || params.target.kind === "handle" ? attachmentChatTarget : void 0,
		chatId: params.target.kind === "chat_id" ? params.target.chatId : void 0,
		timestamp: Date.now(),
		isFromMe: true
	});
	return {
		messageId,
		...approvalBindingMessageId ? { guid: approvalBindingMessageId } : {},
		sentText: "",
		...params.echoText ? { echoText: params.echoText } : {},
		receipt: createIMessageSendReceipt({
			messageId,
			target: params.target,
			kind: params.audioAsVoice ? "voice" : "media",
			...params.replyToId ? { replyToId: params.replyToId } : {}
		})
	};
}
async function sendMessageIMessage(to, text, opts) {
	const cfg = requireRuntimeConfig(opts.config, "iMessage send");
	const account = opts.account ?? resolveIMessageAccount({
		cfg,
		accountId: opts.accountId
	});
	const cliPath = opts.cliPath?.trim() || account.config.cliPath?.trim() || "imsg";
	const dbPath = opts.dbPath?.trim() || account.config.dbPath?.trim();
	const chatDbLookupPath = resolveChatDbLookupPath({
		cliPath,
		dbPath,
		remoteHost: account.config.remoteHost
	});
	const target = parseIMessageTarget(opts.chatId ? formatIMessageChatTarget(opts.chatId) : to);
	const service = opts.service ?? resolveTargetService(target) ?? account.config.service;
	const sendTransport = account.config.sendTransport ?? "auto";
	const timeoutMs = opts.timeoutMs ?? account.config.probeTimeoutMs ?? 15e4;
	const pendingEchoTtlMs = resolvePendingPersistedEchoTtlMs(timeoutMs);
	const region = opts.region?.trim() || account.config.region?.trim() || "US";
	const maxBytes = typeof opts.maxBytes === "number" ? opts.maxBytes : typeof account.config.mediaMaxMb === "number" ? account.config.mediaMaxMb * 1024 * 1024 : 16 * 1024 * 1024;
	let message = text ? appendIMessageApprovalReactionHintForOutboundMessage(text) : "";
	let filePath;
	let mediaContentType;
	if (opts.mediaUrl?.trim()) {
		const resolved = await (opts.resolveAttachmentImpl ?? resolveOutboundAttachmentFromUrl)(opts.mediaUrl.trim(), maxBytes, {
			localRoots: opts.mediaLocalRoots,
			readFile: opts.mediaReadFile
		});
		filePath = resolved.path;
		mediaContentType = resolved.contentType ?? void 0;
	}
	if (!message.trim() && !filePath) throw new Error("iMessage send requires text or media");
	if (message.trim()) {
		const tableMode = resolveMarkdownTableMode({
			cfg,
			channel: "imessage",
			accountId: account.accountId
		});
		message = convertMarkdownTables(message, tableMode);
	}
	message = stripInlineDirectiveTagsForDelivery(message).text;
	if (!message.trim() && !filePath) throw new Error("iMessage send requires text or media");
	const formatted = message.trim() ? extractMarkdownFormatRuns(message) : {
		text: message,
		ranges: []
	};
	message = formatted.text;
	if (!message.trim() && !filePath) throw new Error("iMessage send requires text or media");
	const echoText = resolveOutboundEchoText(message, filePath ? mediaContentType : void 0);
	const resolvedReplyToId = createActionGate(account.config.actions)("reply") ? sanitizeReplyToId(opts.replyToId) : void 0;
	const runCliJson = opts.runCliJson ?? ((args) => runIMessageCliJson(cliPath, dbPath, args, timeoutMs));
	if (filePath && (!resolvedReplyToId || opts.audioAsVoice)) {
		const attachmentEchoText = message.trim() ? resolveOutboundEchoText("", mediaContentType) : echoText;
		const attachmentResult = await trySendAttachmentForTarget({
			accountId: account.accountId,
			dbPath: chatDbLookupPath,
			target,
			service,
			filePath,
			audioAsVoice: opts.audioAsVoice,
			...resolvedReplyToId ? { replyToId: resolvedReplyToId } : {},
			echoText: attachmentEchoText,
			pendingEchoTtlMs,
			runCliJson,
			resolveMessageGuidImpl: opts.resolveMessageGuidImpl
		});
		if (attachmentResult) {
			if (!message.trim()) return attachmentResult;
			const captionResult = await sendMessageIMessage(to, text, {
				...opts,
				...opts.client ? { client: opts.client } : {},
				mediaUrl: void 0
			});
			return {
				messageId: isConcreteIMessageMessageId(attachmentResult.messageId) ? attachmentResult.messageId : captionResult.messageId,
				...captionResult.guid ?? attachmentResult.guid ? { guid: captionResult.guid ?? attachmentResult.guid } : {},
				sentText: captionResult.sentText,
				...captionResult.echoText ?? attachmentResult.echoText ? { echoText: captionResult.echoText ?? attachmentResult.echoText } : {},
				receipt: createMessageReceiptFromOutboundResults({
					results: [{ receipt: attachmentResult.receipt }, { receipt: captionResult.receipt }],
					sentAt: Math.max(attachmentResult.receipt.sentAt, captionResult.receipt.sentAt)
				})
			};
		}
	}
	const params = {
		text: message,
		service: service || "auto",
		region,
		transport: sendTransport
	};
	if (resolvedReplyToId) params.reply_to = resolvedReplyToId;
	if (formatted.ranges.length > 0) params.formatting = formatted.ranges;
	if (filePath) params.file = filePath;
	if (target.kind === "chat_id") params.chat_id = target.chatId;
	else if (target.kind === "chat_guid") params.chat_guid = target.chatGuid;
	else if (target.kind === "chat_identifier") params.chat_identifier = target.chatIdentifier;
	else params.to = target.to;
	const echoScope = resolveOutboundEchoScope({
		accountId: account.accountId,
		target
	});
	const client = opts.client ?? (opts.createClient ? await opts.createClient({
		cliPath,
		dbPath
	}) : await createIMessageRpcClient({
		cliPath,
		dbPath
	}));
	const shouldClose = !opts.client;
	let closedClient = false;
	const stopOwnedClient = async () => {
		if (!shouldClose || closedClient) return;
		closedClient = true;
		await client.stop();
	};
	let result;
	const sendStartedAtMs = Date.now();
	let pendingEchoKey;
	try {
		try {
			if (echoScope) pendingEchoKey = rememberPersistedIMessageEcho({
				scope: echoScope,
				text: echoText,
				ttlMs: pendingEchoTtlMs,
				pending: true
			});
			result = await client.request("send", params, { timeoutMs });
		} catch (error) {
			if (filePath || !isIMessageRpcSendTimeout(error)) throw error;
			if (!shouldRecoverApprovalPromptGuid({
				message,
				filePath,
				replyToId: resolvedReplyToId
			}) || !canCheckSentMessageAfterRpcTimeout({
				dbPath: chatDbLookupPath,
				resolveSentMessageGuidImpl: opts.resolveSentMessageGuidImpl
			})) throw error;
			const recoveredGuid = await resolveFallbackSentMessageGuid({
				dbPath: chatDbLookupPath,
				target,
				text: message,
				sentAfterMs: sendStartedAtMs,
				resolveSentMessageGuidImpl: opts.resolveSentMessageGuidImpl
			});
			if (recoveredGuid) result = {
				guid: recoveredGuid,
				status: "sent"
			};
			else throw error;
		}
		const resolvedId = resolveMessageId(result);
		const messageId = resolvedId ?? (result?.ok || result?.success || result?.status === "sent" ? "ok" : "unknown");
		let approvalBindingMessageId = await resolveApprovalBindingMessageGuid({
			dbPath: chatDbLookupPath,
			messageId: resolvedId,
			result,
			resolveMessageGuidImpl: opts.resolveMessageGuidImpl
		});
		if (!approvalBindingMessageId && shouldRecoverApprovalPromptGuid({
			message,
			filePath,
			replyToId: resolvedReplyToId
		})) approvalBindingMessageId = await resolveFallbackSentMessageGuid({
			dbPath: chatDbLookupPath,
			target,
			text: message,
			sentAfterMs: sendStartedAtMs,
			resolveSentMessageGuidImpl: opts.resolveSentMessageGuidImpl
		});
		if (echoScope) rememberPersistedIMessageEcho({
			scope: echoScope,
			text: echoText,
			messageId: resolvedId ?? void 0
		});
		if (resolvedId) rememberIMessageReplyCache({
			accountId: account.accountId,
			messageId: resolvedId,
			chatGuid: target.kind === "chat_guid" ? target.chatGuid : void 0,
			chatIdentifier: target.kind === "chat_identifier" ? target.chatIdentifier : target.kind === "handle" ? `${target.service === "sms" ? "SMS" : "iMessage"};-;${target.to}` : void 0,
			chatId: target.kind === "chat_id" ? target.chatId : void 0,
			timestamp: Date.now(),
			isFromMe: true
		});
		if (message && approvalBindingMessageId) {
			const handleForKey = target.kind === "handle" ? normalizeIMessageHandle(target.to) : void 0;
			const conversation = {
				...target.kind === "chat_guid" ? { chatGuid: target.chatGuid } : {},
				...target.kind === "chat_identifier" ? { chatIdentifier: target.chatIdentifier } : {},
				...target.kind === "chat_id" ? { chatId: target.chatId } : {},
				...handleForKey ? { handle: handleForKey } : {}
			};
			registerIMessageApprovalReactionTargetForOutboundMessage({
				accountId: account.accountId,
				conversation,
				messageId: approvalBindingMessageId,
				text: message
			});
		}
		return {
			messageId,
			...approvalBindingMessageId ? { guid: approvalBindingMessageId } : {},
			sentText: message,
			...echoText ? { echoText } : {},
			receipt: createIMessageSendReceipt({
				messageId,
				target,
				kind: filePath ? "media" : "text",
				...resolvedReplyToId ? { replyToId: resolvedReplyToId } : {}
			})
		};
	} catch (error) {
		forgetPersistedIMessageEchoKey(pendingEchoKey);
		throw error;
	} finally {
		await stopOwnedClient();
	}
}
//#endregion
export { sendMessageIMessage as t };
