import { emptyPluginConfigSchema } from "minion/plugin-sdk";
import { DEFAULT_ACCOUNT_ID, buildBaseChannelStatusSummary, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk";
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, normalizeAccountId } from "minion/plugin-sdk/account-id";

//#region \0rolldown/runtime.js
var __defProp = Object.defineProperty;
var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
var __exportAll = (all, no_symbols) => {
	let target = {};
	for (var name in all) {
		__defProp(target, name, {
			get: all[name],
			enumerable: true
		});
	}
	if (!no_symbols) {
		__defProp(target, Symbol.toStringTag, { value: "Module" });
	}
	return target;
};

//#endregion
//#region extensions/weixin/src/accounts.ts
/**
* List all configured account IDs from the accounts field.
*/
function listConfiguredAccountIds(cfg) {
	const accounts = (cfg.channels?.weixin)?.accounts;
	if (!accounts || typeof accounts !== "object") return [];
	return Object.keys(accounts).filter(Boolean);
}
/**
* List all Weixin account IDs.
* Returns [DEFAULT_ACCOUNT_ID] if no named accounts are configured.
*/
function listWeixinAccountIds(cfg) {
	const ids = listConfiguredAccountIds(cfg);
	if (ids.length === 0) return [DEFAULT_ACCOUNT_ID$1];
	return [...ids].toSorted((a, b) => a.localeCompare(b));
}
/**
* Resolve the default account ID.
*/
function resolveDefaultWeixinAccountId(cfg) {
	const ids = listWeixinAccountIds(cfg);
	if (ids.includes(DEFAULT_ACCOUNT_ID$1)) return DEFAULT_ACCOUNT_ID$1;
	return ids[0] ?? DEFAULT_ACCOUNT_ID$1;
}
/**
* Get the raw account-specific config.
*/
function resolveAccountConfig(cfg, accountId) {
	const accounts = (cfg.channels?.weixin)?.accounts;
	if (!accounts || typeof accounts !== "object") return;
	return accounts[accountId];
}
/**
* Merge top-level config with account-specific overrides.
*/
function mergeWeixinAccountConfig(cfg, accountId) {
	const { accounts: _ignored, ...base } = cfg.channels?.weixin ?? {};
	const account = resolveAccountConfig(cfg, accountId) ?? {};
	return {
		...base,
		...account
	};
}
/**
* Resolve a complete Weixin account with merged config.
*/
function resolveWeixinAccount(params) {
	const accountId = normalizeAccountId(params.accountId);
	const baseEnabled = (params.cfg.channels?.weixin)?.enabled !== false;
	const merged = mergeWeixinAccountConfig(params.cfg, accountId);
	const accountEnabled = merged.enabled !== false;
	const enabled = baseEnabled && accountEnabled;
	const botToken = merged.botToken?.trim() || void 0;
	return {
		accountId,
		enabled,
		configured: Boolean(botToken),
		name: merged.name?.trim() || void 0,
		botToken,
		baseUrl: merged.baseUrl?.trim() || DEFAULT_BASE_URL,
		pollTimeoutSec: merged.pollTimeoutSec ?? DEFAULT_POLL_TIMEOUT_SEC,
		config: merged
	};
}
var DEFAULT_BASE_URL, DEFAULT_POLL_TIMEOUT_SEC;
var init_accounts = __esmMin((() => {
	DEFAULT_BASE_URL = "https://ilinkai.weixin.qq.com";
	DEFAULT_POLL_TIMEOUT_SEC = 35;
}));

//#endregion
//#region extensions/weixin/src/client.ts
var client_exports = /* @__PURE__ */ __exportAll({
	weixinCheck: () => weixinCheck,
	weixinGetLoginQrCode: () => weixinGetLoginQrCode,
	weixinGetQrCodeStatus: () => weixinGetQrCodeStatus,
	weixinGetUpdates: () => weixinGetUpdates,
	weixinSendMessage: () => weixinSendMessage
});
/**
* Generate a random UIN-style anti-replay nonce for the X-WECHAT-UIN header.
* The iLink API requires a base64-encoded random uint32 per request.
*/
function generateWechatUin() {
	const buf = new Uint8Array(4);
	crypto.getRandomValues(buf);
	return btoa(String.fromCharCode(...buf));
}
/**
* Make an authenticated request to the iLink Bot API.
*/
async function ilinkRequest(params) {
	const { baseUrl, botToken, path, method = "POST", body, timeoutMs = 6e4 } = params;
	const url = `${baseUrl}${path}`;
	const controller = new AbortController();
	const timer = setTimeout(() => controller.abort(), timeoutMs);
	try {
		const response = await fetch(url, {
			method,
			headers: {
				"Content-Type": "application/json",
				AuthorizationType: "ilink_bot_token",
				Authorization: `Bearer ${botToken}`,
				"X-WECHAT-UIN": generateWechatUin()
			},
			body: body ? JSON.stringify(body) : void 0,
			signal: controller.signal
		});
		if (!response.ok) throw new Error(`iLink API ${path} returned ${response.status}: ${response.statusText}`);
		return await response.json();
	} finally {
		clearTimeout(timer);
	}
}
/**
* Long-poll for new messages via iLink getupdates endpoint.
* Holds connection for up to pollTimeoutSec (default 35s).
*/
async function weixinGetUpdates(params) {
	const { baseUrl, botToken, cursor, pollTimeoutSec = 35 } = params;
	const timeoutMs = (pollTimeoutSec + 10) * 1e3;
	return ilinkRequest({
		baseUrl,
		botToken,
		path: "/ilink/bot/getupdates",
		body: {
			timeout: pollTimeoutSec,
			...cursor ? { get_updates_buf: cursor } : {}
		},
		timeoutMs
	});
}
/**
* Send a message via iLink Bot API.
*/
async function weixinSendMessage(params) {
	const { baseUrl, botToken, request } = params;
	const result = await ilinkRequest({
		baseUrl,
		botToken,
		path: "/ilink/bot/sendmessage",
		body: request
	});
	if (result.errcode && result.errcode !== 0) return {
		ok: false,
		error: result.errmsg ?? `errcode ${result.errcode}`
	};
	return { ok: true };
}
/**
* Health check: verify bot token is valid by attempting a lightweight API call.
*/
async function weixinCheck(params) {
	const { baseUrl, botToken, timeoutMs = 1e4 } = params;
	try {
		const result = await ilinkRequest({
			baseUrl,
			botToken,
			path: "/ilink/bot/getbotinfo",
			timeoutMs
		});
		if (result.errcode && result.errcode !== 0) return {
			ok: false,
			error: result.errmsg ?? `errcode ${result.errcode}`
		};
		return {
			ok: true,
			botUin: result.bot_uin,
			botNickname: result.bot_nickname
		};
	} catch (err) {
		return {
			ok: false,
			error: err instanceof Error ? err.message : String(err)
		};
	}
}
/**
* Initiate QR code login flow.
* Returns base64-encoded QR code image data.
*/
async function weixinGetLoginQrCode(params) {
	const { baseUrl } = params;
	try {
		const result = await ilinkRequest({
			baseUrl,
			botToken: "",
			path: "/ilink/bot/get_bot_qrcode?bot_type=3",
			method: "GET"
		});
		if (result.errcode && result.errcode !== 0) return { error: result.errmsg ?? `errcode ${result.errcode}` };
		return { qrcode: result.qrcode };
	} catch (err) {
		return { error: err instanceof Error ? err.message : String(err) };
	}
}
/**
* Poll QR code status until login is confirmed.
*/
async function weixinGetQrCodeStatus(params) {
	const { baseUrl, qrcode } = params;
	try {
		const result = await ilinkRequest({
			baseUrl,
			botToken: "",
			path: `/ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(qrcode)}`,
			method: "GET"
		});
		if (result.status === "confirmed" && result.bot_token) return {
			confirmed: true,
			botToken: result.bot_token,
			baseurl: result.baseurl
		};
		return { confirmed: false };
	} catch (err) {
		return {
			confirmed: false,
			error: err instanceof Error ? err.message : String(err)
		};
	}
}
var init_client = __esmMin((() => {}));

//#endregion
//#region extensions/weixin/src/targets.ts
init_client();
init_accounts();
/**
* Normalize a raw target string into a Weixin recipient identifier.
*
* Supported formats:
* - `weixin:<uin>` → `<uin>` (explicit channel prefix)
* - `user:<uin>` → `<uin>` (user DM target)
* - `group:<chatId>` → `<chatId>` (group target)
* - bare numeric string → treated as UIN
*/
function normalizeWeixinTarget(raw) {
	const trimmed = raw.trim();
	if (!trimmed) return null;
	const lowered = trimmed.toLowerCase();
	if (lowered.startsWith("weixin:")) return trimmed.slice(7).trim() || null;
	if (lowered.startsWith("wechat:")) return trimmed.slice(7).trim() || null;
	if (lowered.startsWith("user:")) return trimmed.slice(5).trim() || null;
	if (lowered.startsWith("group:")) return trimmed.slice(6).trim() || null;
	return trimmed;
}
/**
* Format a target identifier with an appropriate prefix.
*/
function formatWeixinTarget(id, isGroup) {
	const trimmed = id.trim();
	if (isGroup) return `group:${trimmed}`;
	return `user:${trimmed}`;
}
/**
* Check if a raw string looks like a Weixin target identifier.
*/
function looksLikeWeixinId(raw) {
	const trimmed = raw.trim();
	if (!trimmed) return false;
	if (/^(weixin|wechat|user|group):/i.test(trimmed)) return true;
	if (/^\d{6,}$/.test(trimmed)) return true;
	return false;
}

//#endregion
//#region extensions/weixin/src/send.ts
/**
* Send a text message to a Weixin user or group via the iLink Bot API.
*/
async function sendMessageWeixin(params) {
	const { cfg, to, text, accountId, contextToken } = params;
	const account = resolveWeixinAccount({
		cfg,
		accountId
	});
	if (!account.configured || !account.botToken) return {
		ok: false,
		error: `Weixin account "${account.accountId}" not configured (missing bot token)`
	};
	const target = normalizeWeixinTarget(to);
	if (!target) return {
		ok: false,
		error: `invalid target: ${to}`
	};
	return weixinSendMessage({
		baseUrl: account.baseUrl,
		botToken: account.botToken,
		request: {
			type: 1,
			to_uin: target,
			text,
			context_token: contextToken
		}
	});
}

//#endregion
//#region extensions/weixin/src/outbound.ts
const weixinOutbound = {
	deliveryMode: "direct",
	textChunkLimit: 4e3,
	sendText: async ({ cfg, to, text, accountId }) => {
		const result = await sendMessageWeixin({
			cfg,
			to,
			text,
			accountId: accountId ?? void 0
		});
		if (!result.ok) throw new Error(`weixin sendText failed: ${result.error}`);
		return {
			channel: "weixin",
			messageId: `weixin:${Date.now()}`
		};
	},
	sendMedia: async ({ cfg, to, text, mediaUrl, accountId }) => {
		const result = await sendMessageWeixin({
			cfg,
			to,
			text: (text?.trim() ? `${text}\n\n${mediaUrl ?? ""}` : mediaUrl ?? "").trim(),
			accountId: accountId ?? void 0
		});
		if (!result.ok) throw new Error(`weixin sendMedia failed: ${result.error}`);
		return {
			channel: "weixin",
			messageId: `weixin:${Date.now()}`
		};
	}
};

//#endregion
//#region extensions/weixin/src/probe.ts
/**
* Health-check probe for a Weixin account.
* Verifies the bot token is valid and the API is reachable.
*/
async function probeWeixin(account) {
	if (!account.botToken) return {
		ok: false,
		error: "missing bot token — run QR login first"
	};
	const start = Date.now();
	const result = await weixinCheck({
		baseUrl: account.baseUrl,
		botToken: account.botToken,
		timeoutMs: 1e4
	});
	const elapsedMs = Date.now() - start;
	if (!result.ok) return {
		ok: false,
		error: result.error,
		elapsedMs
	};
	return {
		ok: true,
		botUin: result.botUin,
		botNickname: result.botNickname,
		status: "connected",
		elapsedMs
	};
}
var init_probe = __esmMin((() => {
	init_client();
}));

//#endregion
//#region extensions/weixin/src/types.ts
var WeixinMessageType;
var init_types = __esmMin((() => {
	WeixinMessageType = {
		TEXT: 1,
		IMAGE: 2,
		VOICE: 3,
		FILE: 4,
		VIDEO: 5
	};
}));

//#endregion
//#region extensions/weixin/src/normalize.ts
/**
* Normalize a raw iLink Bot API inbound message into a standard context object.
*/
function normalizeWeixinMessage(msg, botUin) {
	const isGroup = Boolean(msg.chatId);
	const body = msg.text ?? "";
	return {
		body,
		rawBody: body,
		from: msg.fromUin,
		to: botUin,
		senderName: msg.fromNickname ?? msg.fromUin,
		senderId: msg.fromUin,
		chatType: isGroup ? "group" : "direct",
		chatId: msg.chatId,
		chatName: msg.chatName,
		provider: "weixin",
		surface: "weixin",
		timestamp: msg.timestamp,
		contextToken: msg.contextToken,
		mediaKey: msg.mediaKey,
		mediaAesKey: msg.mediaAesKey,
		mediaType: MESSAGE_TYPE_TO_MEDIA[msg.type]
	};
}
/**
* Resolve the outbound target for replying to a normalized context.
* For group messages, replies go to the group. For DMs, replies go to the sender.
*/
function resolveOutboundTarget(ctx) {
	if (ctx.chatType === "group" && ctx.chatId) return `group:${ctx.chatId}`;
	return `user:${ctx.from}`;
}
var MESSAGE_TYPE_TO_MEDIA;
var init_normalize = __esmMin((() => {
	init_types();
	MESSAGE_TYPE_TO_MEDIA = {
		[WeixinMessageType.IMAGE]: "image",
		[WeixinMessageType.VOICE]: "voice",
		[WeixinMessageType.FILE]: "file",
		[WeixinMessageType.VIDEO]: "video"
	};
}));

//#endregion
//#region extensions/weixin/src/monitor.ts
var monitor_exports = /* @__PURE__ */ __exportAll({ monitorWeixinProvider: () => monitorWeixinProvider });
/**
* Long-poll monitor for the Weixin iLink Bot API.
* Continuously polls /ilink/bot/getupdates and dispatches
* normalized messages to the onMessage callback.
*/
async function monitorWeixinProvider(opts) {
	const { config, runtime, abortSignal, accountId } = opts;
	if (!config) throw new Error("monitorWeixinProvider requires config");
	const account = resolveWeixinAccount({
		cfg: config,
		accountId
	});
	if (!account.configured || !account.botToken) throw new Error(`Weixin account "${account.accountId}" not configured`);
	const log = runtime?.log ?? console.log;
	const error = runtime?.error ?? console.error;
	const probeResult = await probeWeixin(account);
	const botUin = probeResult.botUin ?? "unknown";
	if (probeResult.ok) log(`[weixin] bot connected: ${probeResult.botNickname ?? botUin}`);
	else error(`[weixin] probe failed: ${probeResult.error} — continuing with polling`);
	let cursor;
	while (!abortSignal?.aborted) try {
		const response = await weixinGetUpdates({
			baseUrl: account.baseUrl,
			botToken: account.botToken,
			cursor,
			pollTimeoutSec: account.pollTimeoutSec
		});
		if (response.get_updates_buf) cursor = response.get_updates_buf;
		if (response.updates?.length) for (const msg of response.updates) {
			if (abortSignal?.aborted) break;
			try {
				const normalized = normalizeWeixinMessage(msg, botUin);
				const replyTo = resolveOutboundTarget(normalized);
				if (opts.onMessage) await opts.onMessage(normalized, replyTo);
			} catch (msgErr) {
				error(`[weixin] error processing message: ${msgErr instanceof Error ? msgErr.message : String(msgErr)}`);
			}
		}
		if (response.errcode && response.errcode !== 0) {
			error(`[weixin] getupdates error: ${response.errmsg ?? `code ${response.errcode}`}`);
			await new Promise((resolve) => setTimeout(resolve, 5e3));
		}
	} catch (pollErr) {
		if (abortSignal?.aborted) break;
		error(`[weixin] poll error: ${pollErr instanceof Error ? pollErr.message : String(pollErr)}`);
		await new Promise((resolve) => setTimeout(resolve, 1e4));
	}
	log("[weixin] monitor stopped");
}
var init_monitor = __esmMin((() => {
	init_accounts();
	init_client();
	init_normalize();
	init_probe();
}));

//#endregion
//#region extensions/weixin/src/channel.ts
init_accounts();
init_probe();
const meta = {
	id: "weixin",
	label: "Weixin",
	selectionLabel: "Weixin/WeChat (微信)",
	docsPath: "/channels/weixin",
	docsLabel: "weixin",
	blurb: "Personal WeChat messaging via iLink Bot API.",
	aliases: ["wechat"],
	order: 75
};
const weixinPlugin = {
	id: "weixin",
	meta: { ...meta },
	capabilities: {
		chatTypes: ["direct", "group"],
		polls: false,
		threads: false,
		media: false,
		reactions: false,
		edit: false,
		reply: true
	},
	agentPrompt: { messageToolHints: () => ["- Weixin targeting: omit `target` to reply to the current conversation. Explicit targets: `user:<uin>` or `group:<chatId>`.", "- Weixin supports text messages only in Phase 1. Media support (images, voice, video) requires AES-128-ECB encryption and will be added later."] },
	reload: { configPrefixes: ["channels.weixin"] },
	configSchema: { schema: {
		type: "object",
		additionalProperties: false,
		properties: {
			enabled: { type: "boolean" },
			botToken: { type: "string" },
			tokenFile: { type: "string" },
			baseUrl: {
				type: "string",
				format: "uri",
				pattern: "^https://"
			},
			pollTimeoutSec: {
				type: "integer",
				minimum: 5,
				maximum: 60
			},
			dmPolicy: {
				type: "string",
				enum: [
					"open",
					"pairing",
					"allowlist"
				]
			},
			allowFrom: {
				type: "array",
				items: { oneOf: [{ type: "string" }, { type: "number" }] }
			},
			groupPolicy: {
				type: "string",
				enum: [
					"open",
					"allowlist",
					"disabled"
				]
			},
			groupAllowFrom: {
				type: "array",
				items: { oneOf: [{ type: "string" }, { type: "number" }] }
			},
			requireMention: { type: "boolean" },
			accounts: {
				type: "object",
				additionalProperties: {
					type: "object",
					properties: {
						enabled: { type: "boolean" },
						name: { type: "string" },
						botToken: { type: "string" },
						tokenFile: { type: "string" },
						baseUrl: {
							type: "string",
							format: "uri"
						}
					}
				}
			}
		}
	} },
	config: {
		listAccountIds: (cfg) => listWeixinAccountIds(cfg),
		resolveAccount: (cfg, accountId) => resolveWeixinAccount({
			cfg,
			accountId
		}),
		defaultAccountId: (cfg) => resolveDefaultWeixinAccountId(cfg),
		setAccountEnabled: ({ cfg, accountId, enabled }) => {
			if (accountId === DEFAULT_ACCOUNT_ID) return {
				...cfg,
				channels: {
					...cfg.channels,
					weixin: {
						...cfg.channels?.weixin,
						enabled
					}
				}
			};
			const weixinCfg = cfg.channels?.weixin;
			return {
				...cfg,
				channels: {
					...cfg.channels,
					weixin: {
						...weixinCfg,
						accounts: {
							...weixinCfg?.accounts,
							[accountId]: {
								...weixinCfg?.accounts?.[accountId],
								enabled
							}
						}
					}
				}
			};
		},
		deleteAccount: ({ cfg, accountId }) => {
			if (accountId === DEFAULT_ACCOUNT_ID) {
				const next = { ...cfg };
				const nextChannels = { ...cfg.channels };
				delete nextChannels.weixin;
				if (Object.keys(nextChannels).length > 0) next.channels = nextChannels;
				else delete next.channels;
				return next;
			}
			const weixinCfg = cfg.channels?.weixin;
			const accounts = { ...weixinCfg?.accounts };
			delete accounts[accountId];
			return {
				...cfg,
				channels: {
					...cfg.channels,
					weixin: {
						...weixinCfg,
						accounts: Object.keys(accounts).length > 0 ? accounts : void 0
					}
				}
			};
		},
		isConfigured: (account) => account.configured,
		describeAccount: (account) => ({
			accountId: account.accountId,
			enabled: account.enabled,
			configured: account.configured,
			name: account.name
		}),
		resolveAllowFrom: ({ cfg, accountId }) => {
			return (resolveWeixinAccount({
				cfg,
				accountId
			}).config?.allowFrom ?? []).map((entry) => String(entry));
		},
		formatAllowFrom: ({ allowFrom }) => allowFrom.map((entry) => String(entry).trim()).filter(Boolean)
	},
	security: { collectWarnings: ({ cfg, accountId }) => {
		const account = resolveWeixinAccount({
			cfg,
			accountId
		});
		const weixinCfg = account.config;
		const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
		if ((weixinCfg?.groupPolicy ?? defaultGroupPolicy ?? "allowlist") !== "open") return [];
		return [`- Weixin[${account.accountId}] groups: groupPolicy="open" allows any group member to trigger the bot. Set channels.weixin.groupPolicy="allowlist" + channels.weixin.groupAllowFrom to restrict senders.`];
	} },
	setup: {
		resolveAccountId: () => DEFAULT_ACCOUNT_ID,
		applyAccountConfig: ({ cfg, accountId }) => {
			if (!accountId || accountId === DEFAULT_ACCOUNT_ID) return {
				...cfg,
				channels: {
					...cfg.channels,
					weixin: {
						...cfg.channels?.weixin,
						enabled: true
					}
				}
			};
			const weixinCfg = cfg.channels?.weixin;
			return {
				...cfg,
				channels: {
					...cfg.channels,
					weixin: {
						...weixinCfg,
						accounts: {
							...weixinCfg?.accounts,
							[accountId]: {
								...weixinCfg?.accounts?.[accountId],
								enabled: true
							}
						}
					}
				}
			};
		}
	},
	messaging: {
		normalizeTarget: (raw) => normalizeWeixinTarget(raw) ?? void 0,
		targetResolver: {
			looksLikeId: looksLikeWeixinId,
			hint: "<uin|user:uin|group:chatId>"
		}
	},
	outbound: weixinOutbound,
	status: {
		defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID),
		buildChannelSummary: ({ snapshot }) => ({
			...buildBaseChannelStatusSummary(snapshot),
			probe: snapshot.probe,
			lastProbeAt: snapshot.lastProbeAt ?? null
		}),
		probeAccount: async ({ account }) => await probeWeixin(account),
		buildAccountSnapshot: ({ account, runtime, probe }) => ({
			accountId: account.accountId,
			enabled: account.enabled,
			configured: account.configured,
			name: account.name,
			running: runtime?.running ?? false,
			lastStartAt: runtime?.lastStartAt ?? null,
			lastStopAt: runtime?.lastStopAt ?? null,
			lastError: runtime?.lastError ?? null,
			probe
		})
	},
	gateway: {
		startAccount: async (ctx) => {
			const { monitorWeixinProvider } = await Promise.resolve().then(() => (init_monitor(), monitor_exports));
			ctx.log?.info(`starting weixin[${ctx.accountId}]`);
			return monitorWeixinProvider({
				config: ctx.cfg,
				runtime: ctx.runtime,
				abortSignal: ctx.abortSignal,
				accountId: ctx.accountId
			});
		},
		loginWithQrStart: async () => {
			const { weixinGetLoginQrCode } = await Promise.resolve().then(() => (init_client(), client_exports));
			const result = await weixinGetLoginQrCode({ baseUrl: "https://ilinkai.weixin.qq.com" });
			if (result.error) return { message: `QR login failed: ${result.error}` };
			return {
				qrDataUrl: result.qrcode ? `data:image/png;base64,${result.qrcode}` : void 0,
				message: "Scan the QR code with your WeChat app to log in."
			};
		},
		loginWithQrWait: async (params) => {
			return {
				connected: false,
				message: "QR login confirmation polling not yet implemented in Phase 1."
			};
		}
	}
};

//#endregion
//#region extensions/weixin/src/runtime.ts
let _runtime;
function setWeixinRuntime(runtime) {
	_runtime = runtime;
}

//#endregion
//#region extensions/weixin/index.ts
init_monitor();
init_probe();
init_normalize();
const plugin = {
	id: "weixin",
	name: "Weixin",
	description: "Weixin/WeChat channel plugin via iLink Bot API",
	configSchema: emptyPluginConfigSchema(),
	register(api) {
		setWeixinRuntime(api.runtime);
		api.registerChannel({ plugin: weixinPlugin });
	}
};

//#endregion
export { plugin as default, formatWeixinTarget, looksLikeWeixinId, monitorWeixinProvider, normalizeWeixinMessage, normalizeWeixinTarget, probeWeixin, resolveOutboundTarget, sendMessageWeixin, weixinPlugin };