import { expect, it } from "vitest"; import type { ChannelPlugin } from "../../../src/channels/plugins/types.js"; export function installChannelSurfaceContractSuite(params: { plugin: Pick< ChannelPlugin, | "id" | "actions" | "setup" | "status" | "outbound" | "messaging" | "threading" | "directory" | "gateway" >; surface: | "actions" | "setup" | "status" | "outbound" | "messaging" | "threading" | "directory" | "gateway"; }) { const { plugin, surface } = params; it(`exposes the ${surface} surface contract`, () => { if (surface === "actions") { expect(plugin.actions).toBeDefined(); expect(typeof plugin.actions?.describeMessageTool).toBe("function"); return; } if (surface === "setup") { expect(plugin.setup).toBeDefined(); expect(typeof plugin.setup?.applyAccountConfig).toBe("function"); return; } if (surface === "status") { expect(plugin.status).toBeDefined(); expect(typeof plugin.status?.buildAccountSnapshot).toBe("function"); return; } if (surface === "outbound") { const outbound = plugin.outbound; expect(outbound).toBeDefined(); expect(["direct", "gateway", "hybrid"]).toContain(outbound?.deliveryMode); expect( [ outbound?.sendPayload, outbound?.sendFormattedText, outbound?.sendFormattedMedia, outbound?.sendText, outbound?.sendMedia, outbound?.sendPoll, ].some((value) => typeof value === "function"), ).toBe(true); return; } if (surface === "messaging") { const messaging = plugin.messaging; expect(messaging).toBeDefined(); expect( [ messaging?.normalizeTarget, messaging?.parseExplicitTarget, messaging?.inferTargetChatType, messaging?.buildCrossContextComponents, messaging?.enableInteractiveReplies, messaging?.hasStructuredReplyPayload, messaging?.formatTargetDisplay, messaging?.resolveOutboundSessionRoute, ].some((value) => typeof value === "function"), ).toBe(true); if (messaging?.targetResolver) { if (messaging.targetResolver.looksLikeId) { expect(typeof messaging.targetResolver.looksLikeId).toBe("function"); } if (messaging.targetResolver.hint !== undefined) { expect(typeof messaging.targetResolver.hint).toBe("string"); expect(messaging.targetResolver.hint.trim()).not.toBe(""); } if (messaging.targetResolver.resolveTarget) { expect(typeof messaging.targetResolver.resolveTarget).toBe("function"); } } return; } if (surface === "threading") { const threading = plugin.threading; expect(threading).toBeDefined(); expect( [ threading?.resolveReplyToMode, threading?.buildToolContext, threading?.resolveAutoThreadId, threading?.resolveReplyTransport, threading?.resolveFocusedBinding, ].some((value) => typeof value === "function"), ).toBe(true); return; } if (surface === "directory") { const directory = plugin.directory; expect(directory).toBeDefined(); expect( [ directory?.self, directory?.listPeers, directory?.listPeersLive, directory?.listGroups, directory?.listGroupsLive, directory?.listGroupMembers, ].some((value) => typeof value === "function"), ).toBe(true); return; } const gateway = plugin.gateway; expect(gateway).toBeDefined(); expect( [ gateway?.startAccount, gateway?.stopAccount, gateway?.loginWithQrStart, gateway?.loginWithQrWait, gateway?.logoutAccount, ].some((value) => typeof value === "function"), ).toBe(true); }); }