UNPKG

n8n

Version:

n8n Workflow Automation Tool

288 lines • 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.executeSlackContextQuery = executeSlackContextQuery; exports.executeSlackAction = executeSlackAction; exports.subscribeSlackThread = subscribeSlackThread; const zod_1 = require("zod"); const integration_helpers_1 = require("../integration-helpers"); const integration_error_codes_1 = require("../integration-error-codes"); const PLATFORM = 'slack'; const getUserSchema = zod_1.z.object({ userId: zod_1.z.string().min(1) }); const getChannelInfoSchema = zod_1.z.object({ channelId: zod_1.z.string().min(1) }); const searchUsersSchema = zod_1.z .object({ query: zod_1.z.string().min(1).optional(), email: zod_1.z.string().min(1).optional(), limit: zod_1.z.number().int().min(1).max(50).default(10), cursor: zod_1.z.string().min(1).optional(), includeBots: zod_1.z.boolean().default(false), includeDeleted: zod_1.z.boolean().default(false), }) .refine((input) => input.query !== undefined || input.email !== undefined, { message: 'Provide query or email.', }); const searchChannelsSchema = zod_1.z.object({ query: zod_1.z.string().min(1), limit: zod_1.z.number().int().min(1).max(50).default(10), cursor: zod_1.z.string().min(1).optional(), includeArchived: zod_1.z.boolean().default(false), }); const addReactionSchema = zod_1.z.object({ emoji: zod_1.z.string().min(1), threadId: zod_1.z.string().min(1).optional(), messageId: zod_1.z.string().min(1).optional(), }); async function executeSlackContextQuery(params) { if (params.query === 'get_user') { const input = getUserSchema.parse(params.input); const user = await params.chat.getUser(input.userId); return { ok: true, user }; } if (params.query === 'get_channel_info') { const input = getChannelInfoSchema.parse(params.input); const channel = params.chat.channel(normalizeChannelId(input.channelId)); const channelInfo = await channel.fetchMetadata(); return { ok: true, channel: channelInfo }; } if (params.query === 'search_users') { return await searchSlackUsers(params.chat, searchUsersSchema.parse(params.input)); } if (params.query === 'search_channels') { return await searchSlackChannels(params.chat, searchChannelsSchema.parse(params.input)); } return (0, integration_helpers_1.unsupportedQuery)(PLATFORM, params.query); } async function executeSlackAction(params) { if (params.action !== 'add_reaction') return undefined; return await addSlackReaction({ chat: params.chat, descriptor: params.descriptor, input: addReactionSchema.parse(params.input), currentMessageContext: params.currentMessageContext, }); } async function searchSlackUsers(chat, input) { const adapter = getSlackAdapter(chat); const usersApi = adapter?.client?.users; if (!adapter || !usersApi?.list) { return (0, integration_helpers_1.unsupportedQuery)(PLATFORM, 'search_users'); } const usersById = new Map(); const searchTerm = normalizeSearchTerm(input.query ?? input.email ?? ''); const email = input.email?.trim(); if (!input.cursor && email && usersApi.lookupByEmail) { try { const response = await usersApi.lookupByEmail(await withSlackToken(adapter, { email })); const user = normalizeSlackUser(response.user); if (user && shouldIncludeUser(response.user, input) && matchesUserSearch(response.user, searchTerm, email)) { usersById.set(user.userId, user); } } catch { } } let cursor = input.cursor; while (usersById.size < input.limit) { const remainingLimit = input.limit - usersById.size; const response = await usersApi.list(await withSlackToken(adapter, { limit: remainingLimit, ...(cursor ? { cursor } : {}), })); for (const rawUser of response.members ?? []) { if (!shouldIncludeUser(rawUser, input) || !matchesUserSearch(rawUser, searchTerm, email)) { continue; } const user = normalizeSlackUser(rawUser); if (user) usersById.set(user.userId, user); } cursor = response.response_metadata?.next_cursor || undefined; if (!cursor) break; } const users = [...usersById.values()].slice(0, input.limit); return { ok: true, users, resultCount: users.length, ...(cursor ? { nextCursor: cursor } : {}), }; } async function searchSlackChannels(chat, input) { const adapter = getSlackAdapter(chat); const conversationsApi = adapter?.client?.conversations; if (!adapter || !conversationsApi?.list) { return (0, integration_helpers_1.unsupportedQuery)(PLATFORM, 'search_channels'); } const channelsById = new Map(); const searchTerm = normalizeChannelSearchTerm(input.query); let cursor = input.cursor; while (channelsById.size < input.limit) { const remainingLimit = input.limit - channelsById.size; const response = await conversationsApi.list(await withSlackToken(adapter, { exclude_archived: !input.includeArchived, limit: remainingLimit, types: 'public_channel,private_channel', ...(cursor ? { cursor } : {}), })); for (const rawChannel of response.channels ?? []) { if (!input.includeArchived && rawChannel.is_archived === true) continue; if (!matchesChannelSearch(rawChannel, searchTerm)) continue; const channel = normalizeSlackChannel(rawChannel); if (channel) channelsById.set(channel.channelId, channel); } cursor = response.response_metadata?.next_cursor || undefined; if (!cursor) break; } const channels = [...channelsById.values()].slice(0, input.limit); return { ok: true, channels, resultCount: channels.length, ...(cursor ? { nextCursor: cursor } : {}), }; } async function addSlackReaction(params) { const adapter = getSlackAdapter(params.chat); if (!adapter || typeof adapter.addReaction !== 'function') { return (0, integration_helpers_1.unsupportedAction)(PLATFORM, 'add_reaction'); } const threadId = params.input.threadId ?? params.currentMessageContext?.target.threadId; const messageId = params.input.messageId ?? params.currentMessageContext?.messageId; if (!threadId || !messageId) { return (0, integration_helpers_1.integrationError)(integration_error_codes_1.INTEGRATION_ERROR_CODES.NO_MESSAGE_CONTEXT, 'Slack reactions require a messageId and threadId or current message context.'); } await adapter.addReaction(threadId, messageId, params.input.emoji); return { ok: true, reaction: { emoji: params.input.emoji, threadId, messageId }, messageContext: { integrationConnectionId: params.descriptor.integrationConnectionId, platform: params.descriptor.integration.type, target: buildSlackReactionTarget(threadId, params.currentMessageContext), messageId, updatedAt: new Date().toISOString(), }, }; } async function subscribeSlackThread(thread) { await thread.subscribe?.(); } function getSlackAdapter(chat) { const adapter = chat.getAdapter('slack'); if (!(0, integration_helpers_1.isRecord)(adapter)) return undefined; const candidate = adapter; if (candidate.client !== undefined && !(0, integration_helpers_1.isRecord)(candidate.client)) return undefined; if (candidate.withToken !== undefined && typeof candidate.withToken !== 'function') { return undefined; } return adapter; } async function withSlackToken(adapter, options) { if (!adapter.withToken) return options; return await adapter.withToken(options); } function normalizeChannelId(id) { return id.includes(':') ? id : `slack:${id}`; } function normalizeSlackUser(user) { const userId = (0, integration_helpers_1.stringValue)(user?.id); if (!userId) return undefined; const profile = user?.profile; const userName = (0, integration_helpers_1.stringValue)(user?.name) ?? userId; const fullName = (0, integration_helpers_1.stringValue)(user?.real_name) ?? (0, integration_helpers_1.stringValue)(profile?.real_name) ?? (0, integration_helpers_1.stringValue)(profile?.display_name) ?? userName; const email = (0, integration_helpers_1.stringValue)(profile?.email); const avatarUrl = (0, integration_helpers_1.stringValue)(profile?.image_192); return { userId, userName, fullName, ...(email ? { email } : {}), ...(avatarUrl ? { avatarUrl } : {}), isBot: user?.is_bot === true, }; } function normalizeSlackChannel(channel) { if (!channel) return undefined; const channelId = (0, integration_helpers_1.stringValue)(channel.id); const name = (0, integration_helpers_1.stringValue)(channel.name); if (!channelId || !name) return undefined; return { channelId, name: `#${name}`, isArchived: channel.is_archived === true, isMember: channel.is_member === true, isPrivate: channel.is_private === true, ...(typeof channel.num_members === 'number' ? { memberCount: channel.num_members } : {}), }; } function shouldIncludeUser(user, input) { if (!input.includeDeleted && user?.deleted === true) return false; if (!input.includeBots && user?.is_bot === true) return false; return true; } function matchesUserSearch(user, searchTerm, email) { const fields = [ (0, integration_helpers_1.stringValue)(user?.id), (0, integration_helpers_1.stringValue)(user?.name), (0, integration_helpers_1.stringValue)(user?.real_name), (0, integration_helpers_1.stringValue)(user?.profile?.display_name), (0, integration_helpers_1.stringValue)(user?.profile?.real_name), (0, integration_helpers_1.stringValue)(user?.profile?.email), ] .filter((field) => field !== undefined) .map(normalizeSearchTerm); if (email) { const normalizedEmail = normalizeSearchTerm(email); if (fields.some((field) => field === normalizedEmail)) return true; } return fields.some((field) => field.includes(searchTerm)); } function matchesChannelSearch(channel, searchTerm) { const fields = [(0, integration_helpers_1.stringValue)(channel?.id), (0, integration_helpers_1.stringValue)(channel?.name)] .filter((field) => field !== undefined) .map(normalizeChannelSearchTerm); return fields.some((field) => field.includes(searchTerm)); } function normalizeSearchTerm(value) { return value.trim().toLowerCase().replace(/^[#@]/, ''); } function normalizeChannelSearchTerm(value) { return normalizeSearchTerm(value); } function buildSlackReactionTarget(threadId, currentMessageContext) { if (currentMessageContext?.target.threadId === threadId) return currentMessageContext.target; const channelId = parseSlackChannelId(threadId); return { type: 'thread', threadId, ...(channelId ? { channelId } : {}), }; } function parseSlackChannelId(threadId) { const [platform, channel] = threadId.split(':'); if (platform !== 'slack' || !channel) return undefined; return `${platform}:${channel}`; } //# sourceMappingURL=slack-operations.js.map