{"version":3,"sources":["../src/MicrofoxSlackClient.ts"],"sourcesContent":["import {\n  WebClient,\n  WebClientOptions,\n  ChatPostMessageResponse,\n  ConversationsCreateResponse,\n  ConversationsInviteResponse,\n  ConversationsKickResponse,\n  ReactionsAddResponse,\n  RemindersAddResponse,\n  ChatPostMessageArguments,\n  ConversationsListResponse,\n  ConversationsInfoResponse,\n  ConversationsJoinResponse,\n  UsersListResponse,\n  ConversationsHistoryResponse,\n  UsersLookupByEmailResponse,\n  UsersInfoResponse,\n  FilesInfoResponse,\n  FilesCompleteUploadExternalResponse,\n  UsersConversationsResponse,\n} from '@slack/web-api';\nimport { Buffer } from 'buffer';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\nexport class MicrofoxSlackClient {\n  private web: WebClient;\n\n  constructor(token: string, options?: WebClientOptions) {\n    this.web = new WebClient(token, options);\n  }\n\n  /**\n   * Lists channels in a workspace.\n   * @param cursor A cursor to the next page of results.\n   * @param limit The maximum number of channels to return.\n   * @param types Channel types to include. Defaults to all types (public, private, im).\n   */\n  async getChannels({\n    cursor,\n    limit = 50,\n    types = ['public', 'private'],\n  }: {\n    cursor?: string;\n    limit?: number;\n    types?: ('public' | 'private' | 'im')[];\n  }): Promise<{\n    channels: ConversationsListResponse['channels'];\n    nextCursor: string | undefined;\n  }> {\n    // Convert types to Slack API format\n    const typeMapping = {\n      'public': 'public_channel',\n      'private': 'private_channel',\n      'im': 'im'\n    };\n    const slackTypes = types.map(type => typeMapping[type]).join(',');\n\n    let channels: ConversationsListResponse['channels'] = [];\n    let nextCursor: string | undefined = cursor;\n    let hasMore = true;\n    while (hasMore) {\n      const result = await this.web.conversations.list({\n        types: slackTypes,\n        limit,\n        cursor: nextCursor,\n      });\n      channels = [...channels, ...(result.channels || [])];\n      nextCursor = result.response_metadata?.next_cursor;\n      hasMore = !!nextCursor && channels.length < limit;\n    }\n    return {\n      channels,\n      nextCursor,\n    };\n  }\n\n  /**\n   * Lists channel IDs and names in a workspace.\n   * @param cursor A cursor to the next page of results.\n   * @param limit The maximum number of channels to return.\n   * @param types Channel types to include. Defaults to all types (public, private, im).\n   */\n  async getChannelsIds({\n    cursor,\n    limit,\n    types = ['public', 'private', 'im'],\n  }: {\n    cursor?: string;\n    limit?: number;\n    types?: ('public' | 'private' | 'im')[];\n  }): Promise<{\n    channels: {\n      id: string;\n      name: string;\n    }[];\n    nextCursor: string | undefined;\n  }> {\n    const response = await this.getChannels({ cursor, limit, types });\n    return {\n      channels: response.channels?.map((channel) => ({\n        id: channel.id || '',\n        name: channel.name || '',\n      })) || [],\n      nextCursor: response.nextCursor,\n    }\n  }\n\n  /**\n   * Fetches information about a conversation.\n   * @param channelId Conversation ID to fetch information for.\n   */\n  async getChannelConversationInfo({ channelId }: { channelId: string }): Promise<ConversationsInfoResponse['channel']> {\n    const result = await this.web.conversations.info({\n      channel: channelId,\n    });\n    return result.channel;\n  }\n\n  /**\n   * Lists all users in a workspace.\n   * @param cursor A cursor to the next page of results.\n   * @param limit The maximum number of users to return.\n   * @param includeBots Whether to include bots.\n   */\n  async getActiveUsers({\n    cursor,\n    limit,\n    includeBots = false,\n  }: {\n    cursor?: string;\n    limit?: number;\n    includeBots?: boolean;\n  }): Promise<{\n    users: UsersListResponse['members'];\n    nextCursor: string | undefined;\n  }> {\n    const result = await this.web.users.list({\n      limit: limit || 100,\n      ...(cursor ? { cursor } : {}),\n    });\n    return {\n      users: result.members?.filter((member) => !member.deleted)?.filter((member) => includeBots ? true : !member.is_bot) || [],\n      nextCursor: result.response_metadata?.next_cursor,\n    }\n  }\n\n  /**\n   * Lists all users in a workspace.\n   * @param cursor A cursor to the next page of results.\n   * @param limit The maximum number of users to return.\n   * @param includeBots Whether to include bots.\n   */\n  async getActiveUsersIds({\n    cursor,\n    limit,\n    includeBots = false,\n  }: {\n    includeBots?: boolean;\n    cursor?: string;\n    limit?: number;\n  }): Promise<{\n    users: {\n      id: string;\n      name: string;\n      real_name: string;\n      display_name: string;\n      title: string;\n      email: string;\n    }[];\n    nextCursor: string | undefined;\n  }> {\n    const response = await this.getActiveUsers({ includeBots, cursor, limit });\n    return {\n      users: response.users?.map((user) => ({\n        id: user.id || '',\n        name: user.name || '',\n        email: user.profile?.email || '',\n        real_name: user.profile?.real_name || '',\n        display_name: user.profile?.display_name || '',\n        title: user.profile?.title || '',\n      })) || [],\n      nextCursor: response.nextCursor,\n    }\n  }\n\n  /**\n   * Lists all users in a channel.\n   * @param channelId Channel ID to get members of.\n   */\n  async getChannelMembers({ channelId, includeBots = false, limit, nextCursor }: { channelId: string, includeBots?: boolean, limit?: number, nextCursor?: string }): Promise<{\n    members: {\n      id: string;\n      name: string;\n      is_bot: boolean;\n      real_name: string;\n      display_name: string;\n      title: string;\n      email: string;\n      is_deleted: boolean;\n    }[];\n    nextCursor: string | undefined;\n  }> {\n    const result = await this.web.conversations.members({\n      channel: channelId,\n      limit,\n      cursor: nextCursor,\n    });\n    let members: {\n      id: string;\n      name: string;\n      is_bot: boolean;\n      real_name: string;\n      display_name: string;\n      title: string;\n      email: string;\n      is_deleted: boolean;\n    }[] = [];\n    if (result?.members) {\n      members = await Promise.all(result?.members?.map(async (member) => {\n        const user = await this.getUserInfo({ userId: member });\n        return {\n          id: member || '',\n          name: user?.name || '',\n          is_bot: user?.is_bot || false,\n          real_name: user?.profile?.real_name || '',\n          display_name: user?.profile?.display_name || '',\n          title: user?.profile?.title || '',\n          email: user?.profile?.email || '',\n          is_deleted: user?.deleted || false,\n        };\n      }));\n    }\n    return {\n      members: members?.filter((member) => includeBots ? true : !member.is_bot) || [],\n      nextCursor: result.response_metadata?.next_cursor,\n    }\n  }\n\n  /**\n   * Finds a user by their email address.\n   * @param email The email address of the user to find.\n   */\n  async getUserByEmail({ email }: { email: string }): Promise<UsersLookupByEmailResponse['user']> {\n    const result = await this.web.users.lookupByEmail({ email });\n    return result.user;\n  }\n\n  /**\n   * Finds users by their email addresses.\n   * @param emails The email addresses of the users to find.\n   */\n  async getUsersByEmails({ emails }: { emails: string[] }): Promise<UsersLookupByEmailResponse['user'][]> {\n    const result = await Promise.all(emails.map(async (email) => {\n      const user = await this.getUserByEmail({ email });\n      return user;\n    }));\n    return result;\n  }\n\n  /**\n   * Sends a direct message to a user.\n   * @param userId The ID of the user to message.\n   * @param text The text of the message to send.\n   * @param username Optional custom username for the message.\n   * @param icon_url Optional URL to an image to use as the icon for the message.\n   */\n  async messageUser({\n    userId,\n    text,\n    username,\n    icon_url,\n  }: {\n    userId: string;\n    text: string;\n    username?: string;\n    icon_url?: string;\n  }): Promise<ChatPostMessageResponse> {\n    const im = await this.web.conversations.open({ users: userId });\n    if (im.ok && im.channel?.id) {\n      return this.messageChannel({\n        channelId: im.channel.id,\n        text,\n        username,\n        icon_url,\n      });\n    }\n    throw new Error(`Could not open DM with user ${userId}`);\n  }\n\n  /**\n   * Sends a message to a channel.\n   * @param channelId The ID of the channel to message.\n   * @param text The text of the message to send.\n   * @param username Optional custom username for the message.\n   * @param icon_url Optional URL to an image to use as the icon for the message.\n   */\n  async messageChannel({\n    channelId,\n    text,\n    username,\n    icon_url,\n  }: {\n    channelId: string;\n    text: string;\n    username?: string;\n    icon_url?: string;\n  }): Promise<ChatPostMessageResponse> {\n    const payload: ChatPostMessageArguments = {\n      channel: channelId,\n      text: text,\n    };\n\n    const finalUsername = username ?? process.env.SLACK_AUTHOR_NAME;\n    if (finalUsername) {\n      payload.username = finalUsername;\n    }\n\n    const finalIconUrl = icon_url ?? process.env.SLACK_ICON_URL;\n    if (finalIconUrl) {\n      payload.icon_url = finalIconUrl;\n    }\n\n    return this.web.chat.postMessage(payload);\n  }\n\n  /**\n   * Sends a direct message to multiple users with optional templating.\n   * @param userIds The IDs of the users to message.\n   * @param text The text of the message to send. Can include template variables for personalization.\n   * @param username Optional custom username for the message.\n   * @param icon_url Optional URL to an image to use as the icon for the message.\n   * \n   * Available template variables:\n   * - {mention} - Mentions the user (@username)\n   * - {user_name} - User's name (fallback: username -> real_name -> display_name)\n   * - {user_email} - User's email address\n   * - {user_title} - User's job title\n   * - {user_phone} - User's phone number\n   * - {user_status} - User's status text\n   * - {user_avatar} - User's profile image URL\n   * - {first_name} - User's first name\n   * - {last_name} - User's last name\n   * \n   * @example\n   * ```typescript\n   * // Simple message\n   * await client.messageUsers({\n   *   userIds: ['U1234567890', 'U0987654321'],\n   *   text: \"Hello everyone!\"\n   * });\n   * \n   * // Templated message\n   * await client.messageUsers({\n   *   userIds: ['U1234567890', 'U0987654321'],\n   *   text: \"Hi {mention}! Your title is {user_title} and email is {user_email}.\"\n   * });\n   * ```\n   */\n  async messageUsers({\n    userIds,\n    text,\n    username,\n    icon_url,\n  }: {\n    userIds: string[];\n    text: string;\n    username?: string;\n    icon_url?: string;\n  }): Promise<ChatPostMessageResponse[]> {\n    const results: ChatPostMessageResponse[] = [];\n\n    // Check if text contains template variables\n    const hasTemplateVars = /{(mention|user_name|user_email|user_title|user_phone|user_status|user_avatar|first_name|last_name)}/.test(text);\n\n    if (!hasTemplateVars) {\n      // No template variables, send same message to all users\n      const responses = await Promise.all(\n        userIds.map((userId) =>\n          this.messageUser({ userId, text, username, icon_url })\n        )\n      );\n      return responses;\n    }\n\n    // Process each user ID for templated messages\n    for (const userId of userIds) {\n      try {\n        // Get detailed user information\n        const user = await this.getUserInfo({ userId });\n        \n        if (!user) {\n          // Skip user if not found, but continue with others\n          continue;\n        }\n\n        // Replace template variables with actual user data using fallbacks\n        let personalizedMessage = text\n          // {mention} -> <@U1234567>\n          .replace(/{mention}/g, `<@${user.id}>`)\n          // {user_name} -> best available name\n          .replace(/{user_name}/g, user.name || user.real_name || user.profile?.display_name || user.profile?.real_name || 'User')\n          // {user_email} -> email\n          .replace(/{user_email}/g, user.profile?.email || '')\n          // {user_title} -> job title\n          .replace(/{user_title}/g, user.profile?.title || '')\n          // {user_phone} -> phone number\n          .replace(/{user_phone}/g, user.profile?.phone || '')\n          // {user_status} -> status text\n          .replace(/{user_status}/g, user.profile?.status_text || '')\n          // {user_avatar} -> profile image (prefer 72px size)\n          .replace(/{user_avatar}/g, user.profile?.image_72 || user.profile?.image_192 || user.profile?.image_original || '')\n          // {first_name} -> first name\n          .replace(/{first_name}/g, user.profile?.first_name || user.profile?.real_name?.split(' ')[0] || user.name || 'User')\n          // {last_name} -> last name\n          .replace(/{last_name}/g, user.profile?.last_name || (user.profile?.real_name?.split(' ').slice(1).join(' ')) || '');\n\n        // Send the personalized message\n        const result = await this.messageUser({\n          userId: user.id!,\n          text: personalizedMessage,\n          username,\n          icon_url,\n        });\n\n        results.push(result);\n      } catch (error) {\n        // Skip failed users but continue with others\n        console.error(`Failed to send message to user ${userId}:`, error);\n      }\n    }\n\n    return results;\n  }\n\n  /**\n   * Sends a message to multiple channels.\n   * @param channelIds The IDs of the channels to message.\n   * @param text The text of the message to send.\n   * @param username Optional custom username for the message.\n   * @param icon_url Optional URL to an image to use as the icon for the message.\n   */\n  async messageChannels({\n    channelIds,\n    text,\n    username,\n    icon_url,\n  }: {\n    channelIds: string[];\n    text: string;\n    username?: string;\n    icon_url?: string;\n  }): Promise<ChatPostMessageResponse[]> {\n    const results = await Promise.all(\n      channelIds.map((channelId) =>\n        this.messageChannel({ channelId, text, username, icon_url })\n      )\n    );\n    return results;\n  }\n  \n  /**\n   * Sets a reminder for a user.\n   * @param userId The ID of the user to set a reminder for.\n   * @param text The text of the reminder.\n   * @param time A string describing when the reminder should fire (e.g., \"in 5 minutes\" or a Unix timestamp).\n   */\n  async setReminder({\n    userId,\n    text,\n    time\n  }: {\n    userId: string;\n    text: string;\n    time: string;\n  }): Promise<RemindersAddResponse> {\n    return this.web.reminders.add({\n      user: userId,\n      text: text,\n      time: time,\n    });\n  }\n\n  /**\n   * Creates a new channel.\n   * @param name The name of the channel to create.\n   * @param isPrivate Whether the channel should be private. Defaults to false.\n   * @param join Whether to join the channel after creation. Defaults to true.\n   * @param userIds Optional array of user IDs to add to the channel after creation.\n   */\n  async createChannel({\n    name,\n    isPrivate = false,\n    userIds,\n  }: {\n    name: string;\n    isPrivate?: boolean;\n    join?: boolean;\n    userIds?: string[];\n  }): Promise<ConversationsCreateResponse['channel']> {\n    const result = await this.web.conversations.create({\n      name: name,\n      is_private: isPrivate,\n    });\n    \n    if (result?.channel?.id) {\n      // Add users to the channel if provided\n      if (userIds && userIds.length > 0) {\n        await this.addUsersToChannel({ \n          channelId: result.channel.id, \n          userIds \n        });\n      }\n    }\n    \n    return result.channel;\n  }\n\n  /**\n   * Adds a reaction to a message.\n   * @param channelId The ID of the channel where the message is.\n   * @param timestamp The timestamp of the message to react to.\n   * @param reaction The name of the emoji to use for the reaction.\n   */\n  async reactMessage({\n    channelId,\n    timestamp,\n    reaction\n  }: {\n    channelId: string;\n    timestamp: string;\n    reaction: string;\n  }): Promise<ReactionsAddResponse> {\n    return this.web.reactions.add({\n      channel: channelId,\n      timestamp: timestamp,\n      name: reaction,\n    });\n  }\n\n  /**\n   * Gets information about a user.\n   * @param userId The ID of the user to get information for.\n   */\n  async getUserInfo({ userId }: { userId: string }): Promise<UsersInfoResponse['user']> {\n    const result = await this.web.users.info({\n      user: userId,\n    });\n    return result.user;\n  }\n\n  /**\n   * Fetches a list of conversations a user is a member of.\n   * @param userId The ID of the user to fetch conversations for.\n   * @param cursor A cursor to the next page of results.\n   * @param limit The maximum number of conversations to return.\n   * @param types An array of conversation types to include.\n   * @param excludeArchived Whether to exclude archived conversations.\n   */\n  async getUserChannels({\n    userId,\n    cursor,\n    limit,\n    types = ['public_channel', 'private_channel'],\n    excludeArchived,\n  }: {\n    userId: string;\n    cursor?: string;\n    limit?: number;\n    types?: ('public_channel' | 'private_channel' | 'mpim' | 'im')[];\n    excludeArchived?: boolean;\n  }): Promise<{\n    channels: UsersConversationsResponse['channels'];\n    nextCursor: string | undefined;\n  }> {\n    const result = await this.web.users.conversations({\n      user: userId,\n      cursor,\n      limit,\n      types: types.join(','),\n      exclude_archived: excludeArchived,\n    });\n\n    return {\n      channels: result.channels || [],\n      nextCursor: result.response_metadata?.next_cursor,\n    };\n  }\n\n  /**\n   * Replies to a message in a thread.\n   * @param channelId The ID of the channel where the message is.\n   * @param thread_ts The timestamp of the message to reply to, establishing the thread.\n   * @param text The text of the reply.\n   * @param username Optional custom username for the message.\n   * @param icon_url Optional URL to an image to use as the icon for the message.\n   */\n  async replyMessage({\n    channelId,\n    thread_ts,\n    text,\n    username,\n    icon_url,\n  }: {\n    channelId: string;\n    thread_ts: string;\n    text: string;\n    username?: string;\n    icon_url?: string;\n  }): Promise<ChatPostMessageResponse> {\n    const payload: ChatPostMessageArguments = {\n      channel: channelId,\n      thread_ts: thread_ts,\n      text: text,\n    };\n\n    const finalUsername = username ?? process.env.SLACK_AUTHOR_NAME;\n    if (finalUsername) {\n      payload.username = finalUsername;\n    }\n\n    const finalIconUrl = icon_url ?? process.env.SLACK_ICON_URL;\n    if (finalIconUrl) {\n      payload.icon_url = finalIconUrl;\n    }\n\n    return this.web.chat.postMessage(payload);\n  }\n\n  /**\n   * Joins a channel.\n   * @param channelId The ID of the channel to join.\n   */\n  async joinChannel({\n    channelId\n  }: {\n    channelId: string;\n  }): Promise<ConversationsJoinResponse> {\n    return this.web.conversations.join({\n      channel: channelId,\n    });\n  }\n\n\n\n  /**\n   * Adds multiple users to a channel.\n   * @param channelId The ID of the channel to add users to.\n   * @param userIds Array of user IDs to add to the channel.\n   */\n  async addUsersToChannel({\n    channelId,\n    userIds\n  }: {\n    channelId: string;\n    userIds: string[];\n  }): Promise<ConversationsInviteResponse[]> {\n    const results: ConversationsInviteResponse[] = [];\n    \n    // Slack API supports adding multiple users in one call with comma-separated list\n    // but to handle errors better, we'll add them in batches or individually if needed\n    try {\n      // Try to add all users at once (more efficient)\n      const result = await this.web.conversations.invite({\n        channel: channelId,\n        users: userIds.join(','),\n      });\n      results.push(result);\n    } catch (error) {\n      // If bulk invite fails, try adding users individually\n      console.warn('Bulk user invite failed, trying individual invites:', error);\n      for (const userId of userIds) {\n        try {\n          const result = await this.web.conversations.invite({\n            channel: channelId,\n            users: userId,\n          });\n          results.push(result);\n        } catch (individualError) {\n          console.error(`Failed to add user ${userId} to channel ${channelId}:`, individualError);\n          // Continue with other users even if one fails\n        }\n      }\n    }\n    \n    return results;\n  }\n\n  /**\n   * Removes a user from a channel.\n   * @param channelId The ID of the channel to remove the user from.\n   * @param userId The ID of the user to remove.\n   */\n  async removeUserFromChannel({\n    channelId,\n    userId\n  }: {\n    channelId: string;\n    userId: string;\n  }): Promise<ConversationsKickResponse> {\n    return this.web.conversations.kick({\n      channel: channelId,\n      user: userId,\n    });\n  }\n\n  /**\n   * Gets information about a file.\n   * @param fileId The ID of the file to get information for.\n   */\n  async getFileInfo({ fileId }: { fileId: string }): Promise<FilesInfoResponse['file']> {\n    const result = await this.web.files.info({\n      file: fileId,\n    });\n    return result.file;\n  }\n\n  /**\n   * Fetches a conversation's history of messages and events.\n   * @param channelId Conversation ID to fetch history for.\n   * @param limit The maximum number of items to return.\n   * @param latest End of the time range of messages to include in results.\n   * @param oldest Start of the time range of messages to include in results.\n   * @param inclusive Include messages with latest or oldest timestamps in results.\n   * @param cursor Paginate through collections of data by setting the cursor parameter to a next_cursor attribute returned by a previous request's response_metadata.\n   */\n  async getConversationHistory({\n    channelId,\n    limit,\n    latest,\n    oldest,\n    inclusive,\n    cursor,\n  }: {\n    channelId: string;\n    limit?: number;\n    latest?: string;\n    oldest?: string;\n    inclusive?: boolean;\n    cursor?: string;\n  }): Promise<{\n    messages: ConversationsHistoryResponse['messages'];\n    nextCursor: string | undefined;\n  }> {\n    const result = await this.web.conversations.history({\n      channel: channelId,\n      limit,\n      latest,\n      oldest,\n      inclusive,\n      cursor,\n    });\n    return {\n      messages: result.messages || [],\n      nextCursor: result.response_metadata?.next_cursor,\n    }\n  }\n\n  /**\n   * Uploads a file to a channel using an external URL.\n   * @param filename The name of the file.\n   * @param file A Buffer containing the file content.\n   * @param channelId The ID of the channel to upload the file to. Can be a comma-separated list of strings.\n   * @param alt_text Description of image for screen-reader.\n   * @param snippet_type Syntax type of the snippet being uploaded.\n   * @param initialComment The message text introducing the file in specified channels.\n   * @param title An optional title for the file.\n   */\n  async uploadFile({\n    filename,\n    file,\n    channelId,\n    alt_text,\n    snippet_type,\n    initialComment,\n    title,\n  }: {\n    filename: string;\n    file: Buffer;\n    channelId?: string;\n    alt_text?: string;\n    snippet_type?: string;\n    initialComment?: string;\n    title?: string;\n  }): Promise<FilesCompleteUploadExternalResponse['files']> {\n    // Step 1: Get an upload URL\n    const uploadURLResponse = await this.web.files.getUploadURLExternal({\n      filename,\n      length: file.length,\n      alt_text,\n      snippet_type,\n    });\n\n    if (!uploadURLResponse.ok || !uploadURLResponse.upload_url || !uploadURLResponse.file_id) {\n      throw new Error(`Failed to get upload URL: ${uploadURLResponse.error}`);\n    }\n\n    const { upload_url, file_id } = uploadURLResponse;\n\n    // Step 2: Upload the file to the URL\n    const uploadResponse = await fetch(upload_url, {\n      method: 'POST',\n      body: file,\n    });\n\n    if (!uploadResponse.ok) {\n      throw new Error(`File upload failed with status: ${uploadResponse.statusText}`);\n    }\n\n    // Step 3: Complete the upload\n    const completeUploadResponse = await this.web.files.completeUploadExternal({\n      files: [{ id: file_id, title: title || filename }],\n      channel_id: channelId,\n      initial_comment: initialComment,\n    });\n\n    if (!completeUploadResponse.ok) {\n      throw new Error(`Failed to complete upload: ${completeUploadResponse.error}`);\n    }\n\n    return completeUploadResponse.files;\n  }\n} \n"],"mappings":"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","names":["_a","_b"]}