refactor(channels): dedupe plugin routing and channel helpers

This commit is contained in:
Peter Steinberger
2026-02-22 14:05:46 +00:00
parent 7abae052f9
commit 66f814a0af
57 changed files with 3744 additions and 2127 deletions

View File

@@ -82,6 +82,25 @@ const stringifyAllowFrom = (allowFrom: Array<string | number>) =>
const trimAllowFromEntries = (allowFrom: Array<string | number>) =>
allowFrom.map((entry) => String(entry).trim()).filter(Boolean);
const DEFAULT_OUTBOUND_TEXT_CHUNK_LIMIT_4000 = { textChunkLimit: 4000 };
const DEFAULT_BLOCK_STREAMING_COALESCE = {
blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 },
};
function formatAllowFromWithReplacements(
allowFrom: Array<string | number>,
replacements: RegExp[],
): string[] {
return trimAllowFromEntries(allowFrom).map((entry) => {
let normalized = entry;
for (const replacement of replacements) {
normalized = normalized.replace(replacement, "");
}
return normalized.toLowerCase();
});
}
const formatDiscordAllowFrom = (allowFrom: Array<string | number>) =>
allowFrom
.map((entry) =>
@@ -168,6 +187,35 @@ function resolveDefaultToCaseInsensitiveAccount(params: {
const account = resolveCaseInsensitiveAccount(params.channel?.accounts, params.accountId);
return (account?.defaultTo ?? params.channel?.defaultTo)?.trim() || undefined;
}
function resolveChannelDefaultTo(
channel:
| {
accounts?: Record<string, { defaultTo?: string }>;
defaultTo?: string;
}
| undefined,
accountId?: string | null,
): string | undefined {
return resolveDefaultToCaseInsensitiveAccount({ channel, accountId });
}
type CaseInsensitiveDefaultToChannel = {
accounts?: Record<string, { defaultTo?: string }>;
defaultTo?: string;
};
type CaseInsensitiveDefaultToChannels = Partial<
Record<"irc" | "googlechat", CaseInsensitiveDefaultToChannel>
>;
function resolveNamedChannelDefaultTo(params: {
channels?: CaseInsensitiveDefaultToChannels;
channelId: keyof CaseInsensitiveDefaultToChannels;
accountId?: string | null;
}): string | undefined {
return resolveChannelDefaultTo(params.channels?.[params.channelId], params.accountId);
}
// Channel docks: lightweight channel metadata/behavior for shared code paths.
//
// Rules:
@@ -186,7 +234,7 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
nativeCommands: true,
blockStreaming: true,
},
outbound: { textChunkLimit: 4000 },
outbound: DEFAULT_OUTBOUND_TEXT_CHUNK_LIMIT_4000,
config: {
resolveAllowFrom: ({ cfg, accountId }) =>
stringifyAllowFrom(resolveTelegramAccount({ cfg, accountId }).config.allowFrom ?? []),
@@ -221,7 +269,7 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
enforceOwnerForCommands: true,
skipWhenConfigEmpty: true,
},
outbound: { textChunkLimit: 4000 },
outbound: DEFAULT_OUTBOUND_TEXT_CHUNK_LIMIT_4000,
config: {
resolveAllowFrom: ({ cfg, accountId }) =>
resolveWhatsAppAccount({ cfg, accountId }).allowFrom ?? [],
@@ -276,9 +324,7 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
threads: true,
},
outbound: { textChunkLimit: 2000 },
streaming: {
blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 },
},
streaming: DEFAULT_BLOCK_STREAMING_COALESCE,
elevated: {
allowFromFallback: ({ cfg }) =>
cfg.channels?.discord?.allowFrom ?? cfg.channels?.discord?.dm?.allowFrom,
@@ -328,21 +374,13 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
return (account?.allowFrom ?? channel?.allowFrom ?? []).map((entry) => String(entry));
},
formatAllowFrom: ({ allowFrom }) =>
allowFrom
.map((entry) => String(entry).trim())
.filter(Boolean)
.map((entry) =>
entry
.replace(/^irc:/i, "")
.replace(/^user:/i, "")
.toLowerCase(),
),
resolveDefaultTo: ({ cfg, accountId }) => {
const channel = cfg.channels?.irc as
| { accounts?: Record<string, { defaultTo?: string }>; defaultTo?: string }
| undefined;
return resolveDefaultToCaseInsensitiveAccount({ channel, accountId });
},
formatAllowFromWithReplacements(allowFrom, [/^irc:/i, /^user:/i]),
resolveDefaultTo: ({ cfg, accountId }) =>
resolveNamedChannelDefaultTo({
channels: cfg.channels as CaseInsensitiveDefaultToChannels | undefined,
channelId: "irc",
accountId,
}),
},
groups: {
resolveRequireMention: ({ cfg, accountId, groupId }) => {
@@ -385,7 +423,7 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
threads: true,
blockStreaming: true,
},
outbound: { textChunkLimit: 4000 },
outbound: DEFAULT_OUTBOUND_TEXT_CHUNK_LIMIT_4000,
config: {
resolveAllowFrom: ({ cfg, accountId }) => {
const channel = cfg.channels?.googlechat as
@@ -400,22 +438,17 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
);
},
formatAllowFrom: ({ allowFrom }) =>
allowFrom
.map((entry) => String(entry).trim())
.filter(Boolean)
.map((entry) =>
entry
.replace(/^(googlechat|google-chat|gchat):/i, "")
.replace(/^user:/i, "")
.replace(/^users\//i, "")
.toLowerCase(),
),
resolveDefaultTo: ({ cfg, accountId }) => {
const channel = cfg.channels?.googlechat as
| { accounts?: Record<string, { defaultTo?: string }>; defaultTo?: string }
| undefined;
return resolveDefaultToCaseInsensitiveAccount({ channel, accountId });
},
formatAllowFromWithReplacements(allowFrom, [
/^(googlechat|google-chat|gchat):/i,
/^user:/i,
/^users\//i,
]),
resolveDefaultTo: ({ cfg, accountId }) =>
resolveNamedChannelDefaultTo({
channels: cfg.channels as CaseInsensitiveDefaultToChannels | undefined,
channelId: "googlechat",
accountId,
}),
},
groups: {
resolveRequireMention: resolveGoogleChatGroupRequireMention,
@@ -436,10 +469,8 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
nativeCommands: true,
threads: true,
},
outbound: { textChunkLimit: 4000 },
streaming: {
blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 },
},
outbound: DEFAULT_OUTBOUND_TEXT_CHUNK_LIMIT_4000,
streaming: DEFAULT_BLOCK_STREAMING_COALESCE,
config: {
resolveAllowFrom: ({ cfg, accountId }) => {
const account = resolveSlackAccount({ cfg, accountId });
@@ -472,10 +503,8 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
reactions: true,
media: true,
},
outbound: { textChunkLimit: 4000 },
streaming: {
blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 },
},
outbound: DEFAULT_OUTBOUND_TEXT_CHUNK_LIMIT_4000,
streaming: DEFAULT_BLOCK_STREAMING_COALESCE,
config: {
resolveAllowFrom: ({ cfg, accountId }) =>
stringifyAllowFrom(resolveSignalAccount({ cfg, accountId }).config.allowFrom ?? []),
@@ -498,7 +527,7 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
reactions: true,
media: true,
},
outbound: { textChunkLimit: 4000 },
outbound: DEFAULT_OUTBOUND_TEXT_CHUNK_LIMIT_4000,
config: {
resolveAllowFrom: ({ cfg, accountId }) =>
(resolveIMessageAccount({ cfg, accountId }).config.allowFrom ?? []).map((entry) =>