mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-04 14:40:25 +00:00
refactor: tighten plugin sdk channel seams
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
// Shim: re-exports from extension
|
||||
// Public entrypoint for the Discord channel action adapter.
|
||||
export * from "../../../../extensions/discord/src/channel-actions.js";
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
// Public entrypoint for the Telegram channel action adapter.
|
||||
export * from "../../../../extensions/telegram/src/channel-actions.js";
|
||||
|
||||
88
src/channels/plugins/bundled.ts
Normal file
88
src/channels/plugins/bundled.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { bluebubblesPlugin } from "../../../extensions/bluebubbles/src/channel.js";
|
||||
import { discordPlugin } from "../../../extensions/discord/src/channel.js";
|
||||
import { discordSetupPlugin } from "../../../extensions/discord/src/channel.setup.js";
|
||||
import { setDiscordRuntime } from "../../../extensions/discord/src/runtime.js";
|
||||
import { feishuPlugin } from "../../../extensions/feishu/src/channel.js";
|
||||
import { googlechatPlugin } from "../../../extensions/googlechat/src/channel.js";
|
||||
import { imessagePlugin } from "../../../extensions/imessage/src/channel.js";
|
||||
import { imessageSetupPlugin } from "../../../extensions/imessage/src/channel.setup.js";
|
||||
import { ircPlugin } from "../../../extensions/irc/src/channel.js";
|
||||
import { linePlugin } from "../../../extensions/line/src/channel.js";
|
||||
import { lineSetupPlugin } from "../../../extensions/line/src/channel.setup.js";
|
||||
import { setLineRuntime } from "../../../extensions/line/src/runtime.js";
|
||||
import { matrixPlugin } from "../../../extensions/matrix/src/channel.js";
|
||||
import { mattermostPlugin } from "../../../extensions/mattermost/src/channel.js";
|
||||
import { msteamsPlugin } from "../../../extensions/msteams/src/channel.js";
|
||||
import { nextcloudTalkPlugin } from "../../../extensions/nextcloud-talk/src/channel.js";
|
||||
import { nostrPlugin } from "../../../extensions/nostr/src/channel.js";
|
||||
import { signalPlugin } from "../../../extensions/signal/src/channel.js";
|
||||
import { signalSetupPlugin } from "../../../extensions/signal/src/channel.setup.js";
|
||||
import { slackPlugin } from "../../../extensions/slack/src/channel.js";
|
||||
import { slackSetupPlugin } from "../../../extensions/slack/src/channel.setup.js";
|
||||
import { synologyChatPlugin } from "../../../extensions/synology-chat/src/channel.js";
|
||||
import { telegramPlugin } from "../../../extensions/telegram/src/channel.js";
|
||||
import { telegramSetupPlugin } from "../../../extensions/telegram/src/channel.setup.js";
|
||||
import { setTelegramRuntime } from "../../../extensions/telegram/src/runtime.js";
|
||||
import { tlonPlugin } from "../../../extensions/tlon/src/channel.js";
|
||||
import { whatsappPlugin } from "../../../extensions/whatsapp/src/channel.js";
|
||||
import { whatsappSetupPlugin } from "../../../extensions/whatsapp/src/channel.setup.js";
|
||||
import { zaloPlugin } from "../../../extensions/zalo/src/channel.js";
|
||||
import { zalouserPlugin } from "../../../extensions/zalouser/src/channel.js";
|
||||
import type { ChannelId, ChannelPlugin } from "./types.js";
|
||||
|
||||
export const bundledChannelPlugins = [
|
||||
bluebubblesPlugin,
|
||||
discordPlugin,
|
||||
feishuPlugin,
|
||||
googlechatPlugin,
|
||||
imessagePlugin,
|
||||
ircPlugin,
|
||||
linePlugin,
|
||||
matrixPlugin,
|
||||
mattermostPlugin,
|
||||
msteamsPlugin,
|
||||
nextcloudTalkPlugin,
|
||||
nostrPlugin,
|
||||
signalPlugin,
|
||||
slackPlugin,
|
||||
synologyChatPlugin,
|
||||
telegramPlugin,
|
||||
tlonPlugin,
|
||||
whatsappPlugin,
|
||||
zaloPlugin,
|
||||
zalouserPlugin,
|
||||
] as ChannelPlugin[];
|
||||
|
||||
export const bundledChannelSetupPlugins = [
|
||||
telegramSetupPlugin,
|
||||
whatsappSetupPlugin,
|
||||
discordSetupPlugin,
|
||||
ircPlugin,
|
||||
googlechatPlugin,
|
||||
slackSetupPlugin,
|
||||
signalSetupPlugin,
|
||||
imessageSetupPlugin,
|
||||
lineSetupPlugin,
|
||||
] as ChannelPlugin[];
|
||||
|
||||
const bundledChannelPluginsById = new Map(
|
||||
bundledChannelPlugins.map((plugin) => [plugin.id, plugin] as const),
|
||||
);
|
||||
|
||||
export function getBundledChannelPlugin(id: ChannelId): ChannelPlugin | undefined {
|
||||
return bundledChannelPluginsById.get(id);
|
||||
}
|
||||
|
||||
export function requireBundledChannelPlugin(id: ChannelId): ChannelPlugin {
|
||||
const plugin = getBundledChannelPlugin(id);
|
||||
if (!plugin) {
|
||||
throw new Error(`missing bundled channel plugin: ${id}`);
|
||||
}
|
||||
return plugin;
|
||||
}
|
||||
|
||||
export const bundledChannelRuntimeSetters = {
|
||||
setDiscordRuntime,
|
||||
setLineRuntime,
|
||||
setTelegramRuntime,
|
||||
};
|
||||
@@ -1,33 +1,11 @@
|
||||
import { expect, vi } from "vitest";
|
||||
import { bluebubblesPlugin } from "../../../../extensions/bluebubbles/src/channel.js";
|
||||
import { discordPlugin } from "../../../../extensions/discord/src/channel.js";
|
||||
import { setDiscordRuntime } from "../../../../extensions/discord/src/runtime.js";
|
||||
import { feishuPlugin } from "../../../../extensions/feishu/src/channel.js";
|
||||
import { googlechatPlugin } from "../../../../extensions/googlechat/src/channel.js";
|
||||
import { imessagePlugin } from "../../../../extensions/imessage/src/channel.js";
|
||||
import { ircPlugin } from "../../../../extensions/irc/src/channel.js";
|
||||
import { linePlugin } from "../../../../extensions/line/src/channel.js";
|
||||
import { setLineRuntime } from "../../../../extensions/line/src/runtime.js";
|
||||
import { matrixPlugin } from "../../../../extensions/matrix/src/channel.js";
|
||||
import { mattermostPlugin } from "../../../../extensions/mattermost/src/channel.js";
|
||||
import { msteamsPlugin } from "../../../../extensions/msteams/src/channel.js";
|
||||
import { nextcloudTalkPlugin } from "../../../../extensions/nextcloud-talk/src/channel.js";
|
||||
import { nostrPlugin } from "../../../../extensions/nostr/src/channel.js";
|
||||
import { signalPlugin } from "../../../../extensions/signal/src/channel.js";
|
||||
import { slackPlugin } from "../../../../extensions/slack/src/channel.js";
|
||||
import { synologyChatPlugin } from "../../../../extensions/synology-chat/src/channel.js";
|
||||
import { telegramPlugin } from "../../../../extensions/telegram/src/channel.js";
|
||||
import { setTelegramRuntime } from "../../../../extensions/telegram/src/runtime.js";
|
||||
import { tlonPlugin } from "../../../../extensions/tlon/src/channel.js";
|
||||
import { whatsappPlugin } from "../../../../extensions/whatsapp/src/channel.js";
|
||||
import { zaloPlugin } from "../../../../extensions/zalo/src/channel.js";
|
||||
import { zalouserPlugin } from "../../../../extensions/zalouser/src/channel.js";
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import {
|
||||
resolveDefaultLineAccountId,
|
||||
resolveLineAccount,
|
||||
listLineAccountIds,
|
||||
} from "../../../line/accounts.js";
|
||||
import { bundledChannelRuntimeSetters, requireBundledChannelPlugin } from "../bundled.js";
|
||||
import type { ChannelPlugin } from "../types.js";
|
||||
|
||||
type PluginContractEntry = {
|
||||
@@ -84,7 +62,7 @@ const telegramGetCapabilitiesMock = vi.fn();
|
||||
const discordListActionsMock = vi.fn();
|
||||
const discordGetCapabilitiesMock = vi.fn();
|
||||
|
||||
setTelegramRuntime({
|
||||
bundledChannelRuntimeSetters.setTelegramRuntime({
|
||||
channel: {
|
||||
telegram: {
|
||||
messageActions: {
|
||||
@@ -95,7 +73,7 @@ setTelegramRuntime({
|
||||
},
|
||||
} as never);
|
||||
|
||||
setDiscordRuntime({
|
||||
bundledChannelRuntimeSetters.setDiscordRuntime({
|
||||
channel: {
|
||||
discord: {
|
||||
messageActions: {
|
||||
@@ -106,7 +84,7 @@ setDiscordRuntime({
|
||||
},
|
||||
} as never);
|
||||
|
||||
setLineRuntime({
|
||||
bundledChannelRuntimeSetters.setLineRuntime({
|
||||
channel: {
|
||||
line: {
|
||||
listLineAccountIds,
|
||||
@@ -118,32 +96,32 @@ setLineRuntime({
|
||||
} as never);
|
||||
|
||||
export const pluginContractRegistry: PluginContractEntry[] = [
|
||||
{ id: "bluebubbles", plugin: bluebubblesPlugin },
|
||||
{ id: "discord", plugin: discordPlugin },
|
||||
{ id: "feishu", plugin: feishuPlugin },
|
||||
{ id: "googlechat", plugin: googlechatPlugin },
|
||||
{ id: "imessage", plugin: imessagePlugin },
|
||||
{ id: "irc", plugin: ircPlugin },
|
||||
{ id: "line", plugin: linePlugin },
|
||||
{ id: "matrix", plugin: matrixPlugin },
|
||||
{ id: "mattermost", plugin: mattermostPlugin },
|
||||
{ id: "msteams", plugin: msteamsPlugin },
|
||||
{ id: "nextcloud-talk", plugin: nextcloudTalkPlugin },
|
||||
{ id: "nostr", plugin: nostrPlugin },
|
||||
{ id: "signal", plugin: signalPlugin },
|
||||
{ id: "slack", plugin: slackPlugin },
|
||||
{ id: "synology-chat", plugin: synologyChatPlugin },
|
||||
{ id: "telegram", plugin: telegramPlugin },
|
||||
{ id: "tlon", plugin: tlonPlugin },
|
||||
{ id: "whatsapp", plugin: whatsappPlugin },
|
||||
{ id: "zalo", plugin: zaloPlugin },
|
||||
{ id: "zalouser", plugin: zalouserPlugin },
|
||||
{ id: "bluebubbles", plugin: requireBundledChannelPlugin("bluebubbles") },
|
||||
{ id: "discord", plugin: requireBundledChannelPlugin("discord") },
|
||||
{ id: "feishu", plugin: requireBundledChannelPlugin("feishu") },
|
||||
{ id: "googlechat", plugin: requireBundledChannelPlugin("googlechat") },
|
||||
{ id: "imessage", plugin: requireBundledChannelPlugin("imessage") },
|
||||
{ id: "irc", plugin: requireBundledChannelPlugin("irc") },
|
||||
{ id: "line", plugin: requireBundledChannelPlugin("line") },
|
||||
{ id: "matrix", plugin: requireBundledChannelPlugin("matrix") },
|
||||
{ id: "mattermost", plugin: requireBundledChannelPlugin("mattermost") },
|
||||
{ id: "msteams", plugin: requireBundledChannelPlugin("msteams") },
|
||||
{ id: "nextcloud-talk", plugin: requireBundledChannelPlugin("nextcloud-talk") },
|
||||
{ id: "nostr", plugin: requireBundledChannelPlugin("nostr") },
|
||||
{ id: "signal", plugin: requireBundledChannelPlugin("signal") },
|
||||
{ id: "slack", plugin: requireBundledChannelPlugin("slack") },
|
||||
{ id: "synology-chat", plugin: requireBundledChannelPlugin("synology-chat") },
|
||||
{ id: "telegram", plugin: requireBundledChannelPlugin("telegram") },
|
||||
{ id: "tlon", plugin: requireBundledChannelPlugin("tlon") },
|
||||
{ id: "whatsapp", plugin: requireBundledChannelPlugin("whatsapp") },
|
||||
{ id: "zalo", plugin: requireBundledChannelPlugin("zalo") },
|
||||
{ id: "zalouser", plugin: requireBundledChannelPlugin("zalouser") },
|
||||
];
|
||||
|
||||
export const actionContractRegistry: ActionsContractEntry[] = [
|
||||
{
|
||||
id: "slack",
|
||||
plugin: slackPlugin,
|
||||
plugin: requireBundledChannelPlugin("slack"),
|
||||
unsupportedAction: "poll",
|
||||
cases: [
|
||||
{
|
||||
@@ -217,7 +195,7 @@ export const actionContractRegistry: ActionsContractEntry[] = [
|
||||
},
|
||||
{
|
||||
id: "mattermost",
|
||||
plugin: mattermostPlugin,
|
||||
plugin: requireBundledChannelPlugin("mattermost"),
|
||||
unsupportedAction: "poll",
|
||||
cases: [
|
||||
{
|
||||
@@ -265,7 +243,7 @@ export const actionContractRegistry: ActionsContractEntry[] = [
|
||||
},
|
||||
{
|
||||
id: "telegram",
|
||||
plugin: telegramPlugin,
|
||||
plugin: requireBundledChannelPlugin("telegram"),
|
||||
cases: [
|
||||
{
|
||||
name: "forwards runtime-backed Telegram actions and capabilities",
|
||||
@@ -283,7 +261,7 @@ export const actionContractRegistry: ActionsContractEntry[] = [
|
||||
},
|
||||
{
|
||||
id: "discord",
|
||||
plugin: discordPlugin,
|
||||
plugin: requireBundledChannelPlugin("discord"),
|
||||
cases: [
|
||||
{
|
||||
name: "forwards runtime-backed Discord actions and capabilities",
|
||||
@@ -304,7 +282,7 @@ export const actionContractRegistry: ActionsContractEntry[] = [
|
||||
export const setupContractRegistry: SetupContractEntry[] = [
|
||||
{
|
||||
id: "slack",
|
||||
plugin: slackPlugin,
|
||||
plugin: requireBundledChannelPlugin("slack"),
|
||||
cases: [
|
||||
{
|
||||
name: "default account stores tokens and enables the channel",
|
||||
@@ -334,7 +312,7 @@ export const setupContractRegistry: SetupContractEntry[] = [
|
||||
},
|
||||
{
|
||||
id: "mattermost",
|
||||
plugin: mattermostPlugin,
|
||||
plugin: requireBundledChannelPlugin("mattermost"),
|
||||
cases: [
|
||||
{
|
||||
name: "default account stores token and normalized base URL",
|
||||
@@ -363,7 +341,7 @@ export const setupContractRegistry: SetupContractEntry[] = [
|
||||
},
|
||||
{
|
||||
id: "line",
|
||||
plugin: linePlugin,
|
||||
plugin: requireBundledChannelPlugin("line"),
|
||||
cases: [
|
||||
{
|
||||
name: "default account stores token and secret",
|
||||
@@ -396,7 +374,7 @@ export const setupContractRegistry: SetupContractEntry[] = [
|
||||
export const statusContractRegistry: StatusContractEntry[] = [
|
||||
{
|
||||
id: "slack",
|
||||
plugin: slackPlugin,
|
||||
plugin: requireBundledChannelPlugin("slack"),
|
||||
cases: [
|
||||
{
|
||||
name: "configured account produces a configured status snapshot",
|
||||
@@ -424,7 +402,7 @@ export const statusContractRegistry: StatusContractEntry[] = [
|
||||
},
|
||||
{
|
||||
id: "mattermost",
|
||||
plugin: mattermostPlugin,
|
||||
plugin: requireBundledChannelPlugin("mattermost"),
|
||||
cases: [
|
||||
{
|
||||
name: "configured account preserves connectivity details in the snapshot",
|
||||
@@ -455,7 +433,7 @@ export const statusContractRegistry: StatusContractEntry[] = [
|
||||
},
|
||||
{
|
||||
id: "line",
|
||||
plugin: linePlugin,
|
||||
plugin: requireBundledChannelPlugin("line"),
|
||||
cases: [
|
||||
{
|
||||
name: "configured account produces a webhook status snapshot",
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
// Shim: re-exports from extension
|
||||
export * from "../../../../extensions/discord/src/normalize.js";
|
||||
@@ -1 +0,0 @@
|
||||
export * from "../../../../extensions/telegram/src/normalize.js";
|
||||
@@ -1,2 +1,25 @@
|
||||
// Shim: re-exports from extensions/whatsapp/src/normalize.ts
|
||||
export * from "../../../../extensions/whatsapp/src/normalize.js";
|
||||
import { normalizeWhatsAppTarget } from "../../../whatsapp/normalize.js";
|
||||
import { looksLikeHandleOrPhoneTarget, trimMessagingTarget } from "./shared.js";
|
||||
|
||||
export function normalizeWhatsAppMessagingTarget(raw: string): string | undefined {
|
||||
const trimmed = trimMessagingTarget(raw);
|
||||
if (!trimmed) {
|
||||
return undefined;
|
||||
}
|
||||
return normalizeWhatsAppTarget(trimmed) ?? undefined;
|
||||
}
|
||||
|
||||
export function normalizeWhatsAppAllowFromEntries(allowFrom: Array<string | number>): string[] {
|
||||
return allowFrom
|
||||
.map((entry) => String(entry).trim())
|
||||
.filter((entry): entry is string => Boolean(entry))
|
||||
.map((entry) => (entry === "*" ? entry : normalizeWhatsAppTarget(entry)))
|
||||
.filter((entry): entry is string => Boolean(entry));
|
||||
}
|
||||
|
||||
export function looksLikeWhatsAppTargetId(raw: string): boolean {
|
||||
return looksLikeHandleOrPhoneTarget({
|
||||
raw,
|
||||
prefixPattern: /^whatsapp:/i,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
import { discordSetupPlugin } from "../../../extensions/discord/src/channel.setup.js";
|
||||
import { googlechatPlugin } from "../../../extensions/googlechat/src/channel.js";
|
||||
import { imessageSetupPlugin } from "../../../extensions/imessage/src/channel.setup.js";
|
||||
import { ircPlugin } from "../../../extensions/irc/src/channel.js";
|
||||
import { lineSetupPlugin } from "../../../extensions/line/src/channel.setup.js";
|
||||
import { signalSetupPlugin } from "../../../extensions/signal/src/channel.setup.js";
|
||||
import { slackSetupPlugin } from "../../../extensions/slack/src/channel.setup.js";
|
||||
import { telegramSetupPlugin } from "../../../extensions/telegram/src/channel.setup.js";
|
||||
import { whatsappSetupPlugin } from "../../../extensions/whatsapp/src/channel.setup.js";
|
||||
import {
|
||||
getActivePluginRegistryVersion,
|
||||
requireActivePluginRegistry,
|
||||
} from "../../plugins/runtime.js";
|
||||
import { CHAT_CHANNEL_ORDER, type ChatChannelId } from "../registry.js";
|
||||
import { bundledChannelSetupPlugins } from "./bundled.js";
|
||||
import type { ChannelId, ChannelPlugin } from "./types.js";
|
||||
|
||||
type CachedChannelSetupPlugins = {
|
||||
@@ -28,18 +20,6 @@ const EMPTY_CHANNEL_SETUP_CACHE: CachedChannelSetupPlugins = {
|
||||
|
||||
let cachedChannelSetupPlugins = EMPTY_CHANNEL_SETUP_CACHE;
|
||||
|
||||
const BUNDLED_CHANNEL_SETUP_PLUGINS = [
|
||||
telegramSetupPlugin,
|
||||
whatsappSetupPlugin,
|
||||
discordSetupPlugin,
|
||||
ircPlugin,
|
||||
googlechatPlugin,
|
||||
slackSetupPlugin,
|
||||
signalSetupPlugin,
|
||||
imessageSetupPlugin,
|
||||
lineSetupPlugin,
|
||||
] as ChannelPlugin[];
|
||||
|
||||
function dedupeSetupPlugins(plugins: ChannelPlugin[]): ChannelPlugin[] {
|
||||
const seen = new Set<string>();
|
||||
const resolved: ChannelPlugin[] = [];
|
||||
@@ -77,7 +57,7 @@ function resolveCachedChannelSetupPlugins(): CachedChannelSetupPlugins {
|
||||
|
||||
const registryPlugins = (registry.channelSetups ?? []).map((entry) => entry.plugin);
|
||||
const sorted = sortChannelSetupPlugins(
|
||||
registryPlugins.length > 0 ? registryPlugins : BUNDLED_CHANNEL_SETUP_PLUGINS,
|
||||
registryPlugins.length > 0 ? registryPlugins : bundledChannelSetupPlugins,
|
||||
);
|
||||
const byId = new Map<string, ChannelPlugin>();
|
||||
for (const plugin of sorted) {
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
// Shim: re-exports from extension
|
||||
export * from "../../../../extensions/discord/src/status-issues.js";
|
||||
@@ -1 +0,0 @@
|
||||
export * from "../../../../extensions/telegram/src/status-issues.js";
|
||||
@@ -1,2 +0,0 @@
|
||||
// Shim: re-exports from extensions/whatsapp/src/status-issues.ts
|
||||
export * from "../../../../extensions/whatsapp/src/status-issues.js";
|
||||
Reference in New Issue
Block a user