mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 13:11:22 +00:00
refactor(src): split oversized modules
This commit is contained in:
84
src/slack/monitor/events/channels.ts
Normal file
84
src/slack/monitor/events/channels.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import type { SlackEventMiddlewareArgs } from "@slack/bolt";
|
||||
|
||||
import { danger } from "../../../globals.js";
|
||||
import { enqueueSystemEvent } from "../../../infra/system-events.js";
|
||||
|
||||
import { resolveSlackChannelLabel } from "../channel-config.js";
|
||||
import type { SlackMonitorContext } from "../context.js";
|
||||
import type {
|
||||
SlackChannelCreatedEvent,
|
||||
SlackChannelRenamedEvent,
|
||||
} from "../types.js";
|
||||
|
||||
export function registerSlackChannelEvents(params: {
|
||||
ctx: SlackMonitorContext;
|
||||
}) {
|
||||
const { ctx } = params;
|
||||
|
||||
ctx.app.event(
|
||||
"channel_created",
|
||||
async ({ event }: SlackEventMiddlewareArgs<"channel_created">) => {
|
||||
try {
|
||||
const payload = event as SlackChannelCreatedEvent;
|
||||
const channelId = payload.channel?.id;
|
||||
const channelName = payload.channel?.name;
|
||||
if (
|
||||
!ctx.isChannelAllowed({
|
||||
channelId,
|
||||
channelName,
|
||||
channelType: "channel",
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const label = resolveSlackChannelLabel({ channelId, channelName });
|
||||
const sessionKey = ctx.resolveSlackSystemEventSessionKey({
|
||||
channelId,
|
||||
channelType: "channel",
|
||||
});
|
||||
enqueueSystemEvent(`Slack channel created: ${label}.`, {
|
||||
sessionKey,
|
||||
contextKey: `slack:channel:created:${channelId ?? channelName ?? "unknown"}`,
|
||||
});
|
||||
} catch (err) {
|
||||
ctx.runtime.error?.(
|
||||
danger(`slack channel created handler failed: ${String(err)}`),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
ctx.app.event(
|
||||
"channel_rename",
|
||||
async ({ event }: SlackEventMiddlewareArgs<"channel_rename">) => {
|
||||
try {
|
||||
const payload = event as SlackChannelRenamedEvent;
|
||||
const channelId = payload.channel?.id;
|
||||
const channelName =
|
||||
payload.channel?.name_normalized ?? payload.channel?.name;
|
||||
if (
|
||||
!ctx.isChannelAllowed({
|
||||
channelId,
|
||||
channelName,
|
||||
channelType: "channel",
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const label = resolveSlackChannelLabel({ channelId, channelName });
|
||||
const sessionKey = ctx.resolveSlackSystemEventSessionKey({
|
||||
channelId,
|
||||
channelType: "channel",
|
||||
});
|
||||
enqueueSystemEvent(`Slack channel renamed: ${label}.`, {
|
||||
sessionKey,
|
||||
contextKey: `slack:channel:renamed:${channelId ?? channelName ?? "unknown"}`,
|
||||
});
|
||||
} catch (err) {
|
||||
ctx.runtime.error?.(
|
||||
danger(`slack channel rename handler failed: ${String(err)}`),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
100
src/slack/monitor/events/members.ts
Normal file
100
src/slack/monitor/events/members.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import type { SlackEventMiddlewareArgs } from "@slack/bolt";
|
||||
|
||||
import { danger } from "../../../globals.js";
|
||||
import { enqueueSystemEvent } from "../../../infra/system-events.js";
|
||||
|
||||
import { resolveSlackChannelLabel } from "../channel-config.js";
|
||||
import type { SlackMonitorContext } from "../context.js";
|
||||
import type { SlackMemberChannelEvent } from "../types.js";
|
||||
|
||||
export function registerSlackMemberEvents(params: {
|
||||
ctx: SlackMonitorContext;
|
||||
}) {
|
||||
const { ctx } = params;
|
||||
|
||||
ctx.app.event(
|
||||
"member_joined_channel",
|
||||
async ({ event }: SlackEventMiddlewareArgs<"member_joined_channel">) => {
|
||||
try {
|
||||
const payload = event as SlackMemberChannelEvent;
|
||||
const channelId = payload.channel;
|
||||
const channelInfo = channelId
|
||||
? await ctx.resolveChannelName(channelId)
|
||||
: {};
|
||||
const channelType = payload.channel_type ?? channelInfo?.type;
|
||||
if (
|
||||
!ctx.isChannelAllowed({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
channelType,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const userInfo = payload.user
|
||||
? await ctx.resolveUserName(payload.user)
|
||||
: {};
|
||||
const userLabel = userInfo?.name ?? payload.user ?? "someone";
|
||||
const label = resolveSlackChannelLabel({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
});
|
||||
const sessionKey = ctx.resolveSlackSystemEventSessionKey({
|
||||
channelId,
|
||||
channelType,
|
||||
});
|
||||
enqueueSystemEvent(`Slack: ${userLabel} joined ${label}.`, {
|
||||
sessionKey,
|
||||
contextKey: `slack:member:joined:${channelId ?? "unknown"}:${payload.user ?? "unknown"}`,
|
||||
});
|
||||
} catch (err) {
|
||||
ctx.runtime.error?.(
|
||||
danger(`slack join handler failed: ${String(err)}`),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
ctx.app.event(
|
||||
"member_left_channel",
|
||||
async ({ event }: SlackEventMiddlewareArgs<"member_left_channel">) => {
|
||||
try {
|
||||
const payload = event as SlackMemberChannelEvent;
|
||||
const channelId = payload.channel;
|
||||
const channelInfo = channelId
|
||||
? await ctx.resolveChannelName(channelId)
|
||||
: {};
|
||||
const channelType = payload.channel_type ?? channelInfo?.type;
|
||||
if (
|
||||
!ctx.isChannelAllowed({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
channelType,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const userInfo = payload.user
|
||||
? await ctx.resolveUserName(payload.user)
|
||||
: {};
|
||||
const userLabel = userInfo?.name ?? payload.user ?? "someone";
|
||||
const label = resolveSlackChannelLabel({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
});
|
||||
const sessionKey = ctx.resolveSlackSystemEventSessionKey({
|
||||
channelId,
|
||||
channelType,
|
||||
});
|
||||
enqueueSystemEvent(`Slack: ${userLabel} left ${label}.`, {
|
||||
sessionKey,
|
||||
contextKey: `slack:member:left:${channelId ?? "unknown"}:${payload.user ?? "unknown"}`,
|
||||
});
|
||||
} catch (err) {
|
||||
ctx.runtime.error?.(
|
||||
danger(`slack leave handler failed: ${String(err)}`),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
142
src/slack/monitor/events/messages.ts
Normal file
142
src/slack/monitor/events/messages.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import type { SlackEventMiddlewareArgs } from "@slack/bolt";
|
||||
|
||||
import { danger } from "../../../globals.js";
|
||||
import { enqueueSystemEvent } from "../../../infra/system-events.js";
|
||||
|
||||
import type { SlackAppMentionEvent, SlackMessageEvent } from "../../types.js";
|
||||
import { resolveSlackChannelLabel } from "../channel-config.js";
|
||||
import type { SlackMonitorContext } from "../context.js";
|
||||
import type { SlackMessageHandler } from "../message-handler.js";
|
||||
import type {
|
||||
SlackMessageChangedEvent,
|
||||
SlackMessageDeletedEvent,
|
||||
SlackThreadBroadcastEvent,
|
||||
} from "../types.js";
|
||||
|
||||
export function registerSlackMessageEvents(params: {
|
||||
ctx: SlackMonitorContext;
|
||||
handleSlackMessage: SlackMessageHandler;
|
||||
}) {
|
||||
const { ctx, handleSlackMessage } = params;
|
||||
|
||||
ctx.app.event(
|
||||
"message",
|
||||
async ({ event }: SlackEventMiddlewareArgs<"message">) => {
|
||||
try {
|
||||
const message = event as SlackMessageEvent;
|
||||
if (message.subtype === "message_changed") {
|
||||
const changed = event as SlackMessageChangedEvent;
|
||||
const channelId = changed.channel;
|
||||
const channelInfo = channelId
|
||||
? await ctx.resolveChannelName(channelId)
|
||||
: {};
|
||||
const channelType = channelInfo?.type;
|
||||
if (
|
||||
!ctx.isChannelAllowed({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
channelType,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const messageId = changed.message?.ts ?? changed.previous_message?.ts;
|
||||
const label = resolveSlackChannelLabel({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
});
|
||||
const sessionKey = ctx.resolveSlackSystemEventSessionKey({
|
||||
channelId,
|
||||
channelType,
|
||||
});
|
||||
enqueueSystemEvent(`Slack message edited in ${label}.`, {
|
||||
sessionKey,
|
||||
contextKey: `slack:message:changed:${channelId ?? "unknown"}:${messageId ?? changed.event_ts ?? "unknown"}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (message.subtype === "message_deleted") {
|
||||
const deleted = event as SlackMessageDeletedEvent;
|
||||
const channelId = deleted.channel;
|
||||
const channelInfo = channelId
|
||||
? await ctx.resolveChannelName(channelId)
|
||||
: {};
|
||||
const channelType = channelInfo?.type;
|
||||
if (
|
||||
!ctx.isChannelAllowed({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
channelType,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const label = resolveSlackChannelLabel({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
});
|
||||
const sessionKey = ctx.resolveSlackSystemEventSessionKey({
|
||||
channelId,
|
||||
channelType,
|
||||
});
|
||||
enqueueSystemEvent(`Slack message deleted in ${label}.`, {
|
||||
sessionKey,
|
||||
contextKey: `slack:message:deleted:${channelId ?? "unknown"}:${deleted.deleted_ts ?? deleted.event_ts ?? "unknown"}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (message.subtype === "thread_broadcast") {
|
||||
const thread = event as SlackThreadBroadcastEvent;
|
||||
const channelId = thread.channel;
|
||||
const channelInfo = channelId
|
||||
? await ctx.resolveChannelName(channelId)
|
||||
: {};
|
||||
const channelType = channelInfo?.type;
|
||||
if (
|
||||
!ctx.isChannelAllowed({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
channelType,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const label = resolveSlackChannelLabel({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
});
|
||||
const messageId = thread.message?.ts ?? thread.event_ts;
|
||||
const sessionKey = ctx.resolveSlackSystemEventSessionKey({
|
||||
channelId,
|
||||
channelType,
|
||||
});
|
||||
enqueueSystemEvent(`Slack thread reply broadcast in ${label}.`, {
|
||||
sessionKey,
|
||||
contextKey: `slack:thread:broadcast:${channelId ?? "unknown"}:${messageId ?? "unknown"}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
await handleSlackMessage(message, { source: "message" });
|
||||
} catch (err) {
|
||||
ctx.runtime.error?.(danger(`slack handler failed: ${String(err)}`));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
ctx.app.event(
|
||||
"app_mention",
|
||||
async ({ event }: SlackEventMiddlewareArgs<"app_mention">) => {
|
||||
try {
|
||||
const mention = event as SlackAppMentionEvent;
|
||||
await handleSlackMessage(mention as unknown as SlackMessageEvent, {
|
||||
source: "app_mention",
|
||||
wasMentioned: true,
|
||||
});
|
||||
} catch (err) {
|
||||
ctx.runtime.error?.(
|
||||
danger(`slack mention handler failed: ${String(err)}`),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
106
src/slack/monitor/events/pins.ts
Normal file
106
src/slack/monitor/events/pins.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import type { SlackEventMiddlewareArgs } from "@slack/bolt";
|
||||
|
||||
import { danger } from "../../../globals.js";
|
||||
import { enqueueSystemEvent } from "../../../infra/system-events.js";
|
||||
|
||||
import { resolveSlackChannelLabel } from "../channel-config.js";
|
||||
import type { SlackMonitorContext } from "../context.js";
|
||||
import type { SlackPinEvent } from "../types.js";
|
||||
|
||||
export function registerSlackPinEvents(params: { ctx: SlackMonitorContext }) {
|
||||
const { ctx } = params;
|
||||
|
||||
ctx.app.event(
|
||||
"pin_added",
|
||||
async ({ event }: SlackEventMiddlewareArgs<"pin_added">) => {
|
||||
try {
|
||||
const payload = event as SlackPinEvent;
|
||||
const channelId = payload.channel_id;
|
||||
const channelInfo = channelId
|
||||
? await ctx.resolveChannelName(channelId)
|
||||
: {};
|
||||
if (
|
||||
!ctx.isChannelAllowed({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
channelType: channelInfo?.type,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const label = resolveSlackChannelLabel({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
});
|
||||
const userInfo = payload.user
|
||||
? await ctx.resolveUserName(payload.user)
|
||||
: {};
|
||||
const userLabel = userInfo?.name ?? payload.user ?? "someone";
|
||||
const itemType = payload.item?.type ?? "item";
|
||||
const messageId = payload.item?.message?.ts ?? payload.event_ts;
|
||||
const sessionKey = ctx.resolveSlackSystemEventSessionKey({
|
||||
channelId,
|
||||
channelType: channelInfo?.type ?? undefined,
|
||||
});
|
||||
enqueueSystemEvent(
|
||||
`Slack: ${userLabel} pinned a ${itemType} in ${label}.`,
|
||||
{
|
||||
sessionKey,
|
||||
contextKey: `slack:pin:added:${channelId ?? "unknown"}:${messageId ?? "unknown"}`,
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
ctx.runtime.error?.(
|
||||
danger(`slack pin added handler failed: ${String(err)}`),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
ctx.app.event(
|
||||
"pin_removed",
|
||||
async ({ event }: SlackEventMiddlewareArgs<"pin_removed">) => {
|
||||
try {
|
||||
const payload = event as SlackPinEvent;
|
||||
const channelId = payload.channel_id;
|
||||
const channelInfo = channelId
|
||||
? await ctx.resolveChannelName(channelId)
|
||||
: {};
|
||||
if (
|
||||
!ctx.isChannelAllowed({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
channelType: channelInfo?.type,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const label = resolveSlackChannelLabel({
|
||||
channelId,
|
||||
channelName: channelInfo?.name,
|
||||
});
|
||||
const userInfo = payload.user
|
||||
? await ctx.resolveUserName(payload.user)
|
||||
: {};
|
||||
const userLabel = userInfo?.name ?? payload.user ?? "someone";
|
||||
const itemType = payload.item?.type ?? "item";
|
||||
const messageId = payload.item?.message?.ts ?? payload.event_ts;
|
||||
const sessionKey = ctx.resolveSlackSystemEventSessionKey({
|
||||
channelId,
|
||||
channelType: channelInfo?.type ?? undefined,
|
||||
});
|
||||
enqueueSystemEvent(
|
||||
`Slack: ${userLabel} unpinned a ${itemType} in ${label}.`,
|
||||
{
|
||||
sessionKey,
|
||||
contextKey: `slack:pin:removed:${channelId ?? "unknown"}:${messageId ?? "unknown"}`,
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
ctx.runtime.error?.(
|
||||
danger(`slack pin removed handler failed: ${String(err)}`),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
104
src/slack/monitor/events/reactions.ts
Normal file
104
src/slack/monitor/events/reactions.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import type { SlackEventMiddlewareArgs } from "@slack/bolt";
|
||||
|
||||
import { danger } from "../../../globals.js";
|
||||
import { enqueueSystemEvent } from "../../../infra/system-events.js";
|
||||
|
||||
import { normalizeSlackSlug } from "../allow-list.js";
|
||||
import {
|
||||
resolveSlackChannelConfig,
|
||||
shouldEmitSlackReactionNotification,
|
||||
} from "../channel-config.js";
|
||||
import type { SlackMonitorContext } from "../context.js";
|
||||
import type { SlackReactionEvent } from "../types.js";
|
||||
|
||||
export function registerSlackReactionEvents(params: {
|
||||
ctx: SlackMonitorContext;
|
||||
}) {
|
||||
const { ctx } = params;
|
||||
|
||||
const handleReactionEvent = async (
|
||||
event: SlackReactionEvent,
|
||||
action: "added" | "removed",
|
||||
) => {
|
||||
try {
|
||||
const item = event.item;
|
||||
if (!event.user) return;
|
||||
if (!item?.channel || !item?.ts) return;
|
||||
if (item.type && item.type !== "message") return;
|
||||
if (ctx.botUserId && event.user === ctx.botUserId) return;
|
||||
|
||||
const channelInfo = await ctx.resolveChannelName(item.channel);
|
||||
const channelType = channelInfo?.type;
|
||||
const channelName = channelInfo?.name;
|
||||
|
||||
if (
|
||||
!ctx.isChannelAllowed({
|
||||
channelId: item.channel,
|
||||
channelName,
|
||||
channelType,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isRoom = channelType === "channel" || channelType === "group";
|
||||
if (isRoom) {
|
||||
const channelConfig = resolveSlackChannelConfig({
|
||||
channelId: item.channel,
|
||||
channelName,
|
||||
channels: ctx.channelsConfig,
|
||||
});
|
||||
if (channelConfig?.allowed === false) return;
|
||||
}
|
||||
|
||||
const actor = await ctx.resolveUserName(event.user);
|
||||
const shouldNotify = shouldEmitSlackReactionNotification({
|
||||
mode: ctx.reactionMode,
|
||||
botId: ctx.botUserId,
|
||||
messageAuthorId: event.item_user ?? undefined,
|
||||
userId: event.user,
|
||||
userName: actor?.name ?? undefined,
|
||||
allowlist: ctx.reactionAllowlist,
|
||||
});
|
||||
if (!shouldNotify) return;
|
||||
|
||||
const emojiLabel = event.reaction ?? "emoji";
|
||||
const actorLabel = actor?.name ?? event.user;
|
||||
const channelLabel = channelName
|
||||
? `#${normalizeSlackSlug(channelName) || channelName}`
|
||||
: `#${item.channel}`;
|
||||
const authorInfo = event.item_user
|
||||
? await ctx.resolveUserName(event.item_user)
|
||||
: undefined;
|
||||
const authorLabel = authorInfo?.name ?? event.item_user;
|
||||
const baseText = `Slack reaction ${action}: :${emojiLabel}: by ${actorLabel} in ${channelLabel} msg ${item.ts}`;
|
||||
const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
|
||||
const sessionKey = ctx.resolveSlackSystemEventSessionKey({
|
||||
channelId: item.channel,
|
||||
channelType,
|
||||
});
|
||||
enqueueSystemEvent(text, {
|
||||
sessionKey,
|
||||
contextKey: `slack:reaction:${action}:${item.channel}:${item.ts}:${event.user}:${emojiLabel}`,
|
||||
});
|
||||
} catch (err) {
|
||||
ctx.runtime.error?.(
|
||||
danger(`slack reaction handler failed: ${String(err)}`),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
ctx.app.event(
|
||||
"reaction_added",
|
||||
async ({ event }: SlackEventMiddlewareArgs<"reaction_added">) => {
|
||||
await handleReactionEvent(event as SlackReactionEvent, "added");
|
||||
},
|
||||
);
|
||||
|
||||
ctx.app.event(
|
||||
"reaction_removed",
|
||||
async ({ event }: SlackEventMiddlewareArgs<"reaction_removed">) => {
|
||||
await handleReactionEvent(event as SlackReactionEvent, "removed");
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user