@chat-adapter/slack 4.20.0 → 4.20.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/cards.ts","../src/crypto.ts","../src/markdown.ts","../src/modals.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { createHmac, timingSafeEqual } from \"node:crypto\";\nimport {\n AdapterRateLimitError,\n AuthenticationError,\n extractCard,\n extractFiles,\n NetworkError,\n toBuffer,\n ValidationError,\n} from \"@chat-adapter/shared\";\nimport { WebClient } from \"@slack/web-api\";\nimport type {\n ActionEvent,\n Adapter,\n AdapterPostableMessage,\n Attachment,\n ChannelInfo,\n ChatInstance,\n EmojiValue,\n EphemeralMessage,\n FetchOptions,\n FetchResult,\n FileUpload,\n FormattedContent,\n ListThreadsOptions,\n ListThreadsResult,\n Logger,\n ModalElement,\n ModalResponse,\n RawMessage,\n ReactionEvent,\n Root,\n ScheduledMessage,\n StreamChunk,\n StreamOptions,\n ThreadInfo,\n ThreadSummary,\n WebhookOptions,\n} from \"chat\";\n\nimport {\n ConsoleLogger,\n convertEmojiPlaceholders,\n defaultEmojiResolver,\n isJSX,\n Message,\n parseMarkdown,\n StreamingMarkdownRenderer,\n toModalElement,\n} from \"chat\";\nimport { cardToBlockKit, cardToFallbackText, type SlackBlock } from \"./cards\";\nimport type { EncryptedTokenData } from \"./crypto\";\nimport {\n decodeKey,\n decryptToken,\n encryptToken,\n isEncryptedTokenData,\n} from \"./crypto\";\nimport { SlackFormatConverter } from \"./markdown\";\nimport {\n decodeModalMetadata,\n encodeModalMetadata,\n modalToSlackView,\n type SlackModalResponse,\n} from \"./modals\";\n\nconst SLACK_USER_ID_PATTERN = /^[A-Z0-9_]+$/;\n\nexport interface SlackAdapterConfig {\n /** Bot token (xoxb-...). Required for single-workspace mode. Omit for multi-workspace. */\n botToken?: string;\n /** Bot user ID (will be fetched if not provided) */\n botUserId?: string;\n /** Slack app client ID (required for OAuth / multi-workspace) */\n clientId?: string;\n /** Slack app client secret (required for OAuth / multi-workspace) */\n clientSecret?: string;\n /**\n * Base64-encoded 32-byte AES-256-GCM encryption key.\n * If provided, bot tokens stored via setInstallation() will be encrypted at rest.\n */\n encryptionKey?: string;\n /**\n * Prefix for the state key used to store workspace installations.\n * Defaults to `slack:installation`. The full key will be `{prefix}:{teamId}`.\n */\n installationKeyPrefix?: string;\n /** Logger instance for error reporting. Defaults to ConsoleLogger. */\n logger?: Logger;\n /** Signing secret for webhook verification. Defaults to SLACK_SIGNING_SECRET env var. */\n signingSecret?: string;\n /** Override bot username (optional) */\n userName?: string;\n}\n\n/** Data stored per Slack workspace installation */\nexport interface SlackInstallation {\n botToken: string;\n botUserId?: string;\n teamName?: string;\n}\n\n/** Slack-specific thread ID data */\nexport interface SlackThreadId {\n channel: string;\n threadTs: string;\n}\n\n/** Slack event payload (raw message format) */\nexport interface SlackEvent {\n bot_id?: string;\n channel?: string;\n /** Channel type: \"channel\", \"group\", \"mpim\", or \"im\" (DM) */\n channel_type?: string;\n edited?: { ts: string };\n files?: Array<{\n id?: string;\n mimetype?: string;\n url_private?: string;\n name?: string;\n size?: number;\n original_w?: number;\n original_h?: number;\n }>;\n /** Timestamp of the latest reply (present on thread parent messages) */\n latest_reply?: string;\n /** Number of replies in the thread (present on thread parent messages) */\n reply_count?: number;\n subtype?: string;\n team?: string;\n team_id?: string;\n text?: string;\n thread_ts?: string;\n ts?: string;\n type: string;\n user?: string;\n username?: string;\n}\n\n/** Slack reaction event payload */\nexport interface SlackReactionEvent {\n event_ts: string;\n item: {\n type: string;\n channel: string;\n ts: string;\n };\n item_user?: string;\n reaction: string;\n type: \"reaction_added\" | \"reaction_removed\";\n user: string;\n}\n\n/** Slack assistant_thread_started event payload */\ninterface SlackAssistantThreadStartedEvent {\n assistant_thread: {\n user_id: string;\n channel_id: string;\n thread_ts: string;\n context: {\n channel_id?: string;\n team_id?: string;\n enterprise_id?: string;\n thread_entry_point?: string;\n force_search?: boolean;\n };\n };\n event_ts: string;\n type: \"assistant_thread_started\";\n}\n\n/** Slack assistant_thread_context_changed event payload */\ninterface SlackAssistantContextChangedEvent {\n assistant_thread: {\n user_id: string;\n channel_id: string;\n thread_ts: string;\n context: {\n channel_id?: string;\n team_id?: string;\n enterprise_id?: string;\n thread_entry_point?: string;\n force_search?: boolean;\n };\n };\n event_ts: string;\n type: \"assistant_thread_context_changed\";\n}\n\n/** Slack app_home_opened event payload */\ninterface SlackAppHomeOpenedEvent {\n channel: string;\n event_ts: string;\n tab: string;\n type: \"app_home_opened\";\n user: string;\n}\n\n/** Slack member_joined_channel event payload */\ninterface SlackMemberJoinedChannelEvent {\n channel: string;\n channel_type?: string;\n event_ts: string;\n inviter?: string;\n team?: string;\n type: \"member_joined_channel\";\n user: string;\n}\n\n/** Slack webhook payload envelope */\ninterface SlackWebhookPayload {\n challenge?: string;\n event?:\n | SlackEvent\n | SlackReactionEvent\n | SlackAssistantThreadStartedEvent\n | SlackAssistantContextChangedEvent\n | SlackAppHomeOpenedEvent\n | SlackMemberJoinedChannelEvent;\n event_id?: string;\n event_time?: number;\n team_id?: string;\n type: string;\n}\n\n/** Slack interactive payload (block_actions) for button clicks */\ninterface SlackBlockActionsPayload {\n actions: Array<{\n type: string;\n action_id: string;\n block_id?: string;\n value?: string;\n action_ts?: string;\n selected_option?: { value: string };\n }>;\n channel: {\n id: string;\n name: string;\n };\n container: {\n type: string;\n message_ts: string;\n channel_id: string;\n is_ephemeral?: boolean;\n thread_ts?: string;\n };\n message: {\n ts: string;\n thread_ts?: string;\n };\n response_url?: string;\n trigger_id: string;\n type: \"block_actions\";\n user: {\n id: string;\n username: string;\n name?: string;\n };\n}\n\ninterface SlackViewSubmissionPayload {\n trigger_id: string;\n type: \"view_submission\";\n user: {\n id: string;\n username: string;\n name?: string;\n };\n view: {\n id: string;\n callback_id: string;\n private_metadata?: string;\n state: {\n values: Record<\n string,\n Record<string, { value?: string; selected_option?: { value: string } }>\n >;\n };\n };\n}\n\ninterface SlackViewClosedPayload {\n type: \"view_closed\";\n user: {\n id: string;\n username: string;\n name?: string;\n };\n view: {\n id: string;\n callback_id: string;\n private_metadata?: string;\n };\n}\n\ntype SlackInteractivePayload =\n | SlackBlockActionsPayload\n | SlackViewSubmissionPayload\n | SlackViewClosedPayload;\n\n/** Cached user info */\ninterface CachedUser {\n displayName: string;\n realName: string;\n}\n\nexport class SlackAdapter implements Adapter<SlackThreadId, unknown> {\n readonly name = \"slack\";\n readonly userName: string;\n\n private readonly client: WebClient;\n private readonly signingSecret: string;\n private readonly defaultBotToken: string | undefined;\n private chat: ChatInstance | null = null;\n private readonly logger: Logger;\n private _botUserId: string | null = null;\n private _botId: string | null = null; // Bot app ID (B_xxx) - different from user ID\n private readonly formatConverter = new SlackFormatConverter();\n private static USER_CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour\n\n // Multi-workspace support\n private readonly clientId: string | undefined;\n private readonly clientSecret: string | undefined;\n private readonly encryptionKey: Buffer | undefined;\n private readonly installationKeyPrefix: string;\n private readonly requestContext = new AsyncLocalStorage<{\n token: string;\n botUserId?: string;\n }>();\n\n /** Bot user ID (e.g., U_BOT_123) used for mention detection */\n get botUserId(): string | undefined {\n const ctx = this.requestContext.getStore();\n if (ctx?.botUserId) {\n return ctx.botUserId;\n }\n return this._botUserId || undefined;\n }\n\n constructor(config: SlackAdapterConfig = {}) {\n const signingSecret =\n config.signingSecret ?? process.env.SLACK_SIGNING_SECRET;\n if (!signingSecret) {\n throw new ValidationError(\n \"slack\",\n \"signingSecret is required. Set SLACK_SIGNING_SECRET or provide it in config.\"\n );\n }\n\n // Auth fields (botToken, clientId, clientSecret) are modal: botToken's\n // presence selects single-workspace mode, its absence selects multi-workspace\n // (per-team token lookup via installations). Only fall back to env vars\n // in zero-config mode (no config fields provided at all).\n const zeroConfig = !(\n config.signingSecret ||\n config.botToken ||\n config.clientId ||\n config.clientSecret\n );\n\n const botToken =\n config.botToken ?? (zeroConfig ? process.env.SLACK_BOT_TOKEN : undefined);\n\n this.client = new WebClient(botToken);\n this.signingSecret = signingSecret;\n this.defaultBotToken = botToken;\n this.logger = config.logger ?? new ConsoleLogger(\"info\").child(\"slack\");\n this.userName = config.userName || \"bot\";\n this._botUserId = config.botUserId || null;\n\n this.clientId =\n config.clientId ?? (zeroConfig ? process.env.SLACK_CLIENT_ID : undefined);\n this.clientSecret =\n config.clientSecret ??\n (zeroConfig ? process.env.SLACK_CLIENT_SECRET : undefined);\n this.installationKeyPrefix =\n config.installationKeyPrefix ?? \"slack:installation\";\n\n const encryptionKey =\n config.encryptionKey ?? process.env.SLACK_ENCRYPTION_KEY;\n if (encryptionKey) {\n this.encryptionKey = decodeKey(encryptionKey);\n }\n }\n\n /**\n * Get the current bot token for API calls.\n * Checks request context (multi-workspace) → default token (single-workspace) → throws.\n */\n private getToken(): string {\n const ctx = this.requestContext.getStore();\n if (ctx?.token) {\n return ctx.token;\n }\n if (this.defaultBotToken) {\n return this.defaultBotToken;\n }\n throw new AuthenticationError(\n \"slack\",\n \"No bot token available. In multi-workspace mode, ensure the webhook is being processed.\"\n );\n }\n\n /**\n * Add the current token to API call options.\n * Workaround for Slack WebClient types not including `token` in per-method args.\n */\n // biome-ignore lint/suspicious/noExplicitAny: Slack types don't include token in method args\n private withToken<T extends Record<string, any>>(\n options: T\n ): T & { token: string } {\n return { ...options, token: this.getToken() };\n }\n\n async initialize(chat: ChatInstance): Promise<void> {\n this.chat = chat;\n\n // Only fetch bot user ID in single-workspace mode (when default token is available)\n if (this.defaultBotToken && !this._botUserId) {\n try {\n const authResult = await this.client.auth.test(this.withToken({}));\n this._botUserId = authResult.user_id as string;\n this._botId = (authResult.bot_id as string) || null;\n if (authResult.user) {\n (this as { userName: string }).userName = authResult.user as string;\n }\n this.logger.info(\"Slack auth completed\", {\n botUserId: this._botUserId,\n botId: this._botId,\n });\n } catch (error) {\n this.logger.warn(\"Could not fetch bot user ID\", { error });\n }\n }\n\n if (!this.defaultBotToken) {\n this.logger.info(\"Slack adapter initialized in multi-workspace mode\");\n }\n }\n\n // ===========================================================================\n // Multi-workspace installation management\n // ===========================================================================\n\n private installationKey(teamId: string): string {\n return `${this.installationKeyPrefix}:${teamId}`;\n }\n\n /**\n * Save a Slack workspace installation.\n * Call this from your OAuth callback route after a successful installation.\n */\n async setInstallation(\n teamId: string,\n installation: SlackInstallation\n ): Promise<void> {\n if (!this.chat) {\n throw new ValidationError(\n \"slack\",\n \"Adapter not initialized. Ensure chat.initialize() has been called first.\"\n );\n }\n\n const state = this.chat.getState();\n const key = this.installationKey(teamId);\n\n const dataToStore = this.encryptionKey\n ? {\n ...installation,\n botToken: encryptToken(installation.botToken, this.encryptionKey),\n }\n : installation;\n\n await state.set(key, dataToStore);\n this.logger.info(\"Slack installation saved\", {\n teamId,\n teamName: installation.teamName,\n });\n }\n\n /**\n * Retrieve a Slack workspace installation.\n */\n async getInstallation(teamId: string): Promise<SlackInstallation | null> {\n if (!this.chat) {\n throw new ValidationError(\n \"slack\",\n \"Adapter not initialized. Ensure chat.initialize() has been called first.\"\n );\n }\n\n const state = this.chat.getState();\n const key = this.installationKey(teamId);\n const stored = await state.get<\n | SlackInstallation\n | (Omit<SlackInstallation, \"botToken\"> & {\n botToken: EncryptedTokenData;\n })\n >(key);\n\n if (!stored) {\n return null;\n }\n\n if (this.encryptionKey && isEncryptedTokenData(stored.botToken)) {\n return {\n ...stored,\n botToken: decryptToken(\n stored.botToken as EncryptedTokenData,\n this.encryptionKey\n ),\n };\n }\n\n return stored as SlackInstallation;\n }\n\n /**\n * Handle the Slack OAuth V2 callback.\n * Accepts the incoming request, extracts the authorization code,\n * exchanges it for tokens, and saves the installation.\n */\n async handleOAuthCallback(\n request: Request\n ): Promise<{ teamId: string; installation: SlackInstallation }> {\n if (!(this.clientId && this.clientSecret)) {\n throw new ValidationError(\n \"slack\",\n \"clientId and clientSecret are required for OAuth. Pass them in createSlackAdapter().\"\n );\n }\n\n const url = new URL(request.url);\n const code = url.searchParams.get(\"code\");\n if (!code) {\n throw new ValidationError(\n \"slack\",\n \"Missing 'code' query parameter in OAuth callback request.\"\n );\n }\n\n const redirectUri = url.searchParams.get(\"redirect_uri\") ?? undefined;\n\n const result = await this.client.oauth.v2.access({\n client_id: this.clientId,\n client_secret: this.clientSecret,\n code,\n redirect_uri: redirectUri,\n });\n\n if (!(result.ok && result.access_token && result.team?.id)) {\n throw new AuthenticationError(\n \"slack\",\n `Slack OAuth failed: ${result.error || \"missing access_token or team.id\"}`\n );\n }\n\n const teamId = result.team.id;\n const installation: SlackInstallation = {\n botToken: result.access_token,\n botUserId: result.bot_user_id,\n teamName: result.team.name,\n };\n\n await this.setInstallation(teamId, installation);\n\n return { teamId, installation };\n }\n\n /**\n * Remove a Slack workspace installation.\n */\n async deleteInstallation(teamId: string): Promise<void> {\n if (!this.chat) {\n throw new ValidationError(\n \"slack\",\n \"Adapter not initialized. Ensure chat.initialize() has been called first.\"\n );\n }\n\n const state = this.chat.getState();\n await state.delete(this.installationKey(teamId));\n this.logger.info(\"Slack installation deleted\", { teamId });\n }\n\n /**\n * Run a function with a specific bot token in context.\n * Use this for operations outside webhook handling (cron jobs, workflows).\n */\n withBotToken<T>(token: string, fn: () => T): T {\n return this.requestContext.run({ token }, fn);\n }\n\n // ===========================================================================\n // Private helpers\n // ===========================================================================\n\n /**\n * Resolve the bot token for a team from the state adapter.\n */\n private async resolveTokenForTeam(\n teamId: string\n ): Promise<{ token: string; botUserId?: string } | null> {\n try {\n const installation = await this.getInstallation(teamId);\n if (installation) {\n return {\n token: installation.botToken,\n botUserId: installation.botUserId,\n };\n }\n this.logger.warn(\"No installation found for team\", { teamId });\n return null;\n } catch (error) {\n this.logger.error(\"Failed to resolve token for team\", {\n teamId,\n error,\n });\n return null;\n }\n }\n\n /**\n * Extract team_id from an interactive payload (form-urlencoded).\n */\n private extractTeamIdFromInteractive(body: string): string | null {\n try {\n const params = new URLSearchParams(body);\n const payloadStr = params.get(\"payload\");\n if (!payloadStr) {\n return null;\n }\n const payload = JSON.parse(payloadStr);\n return payload.team?.id || payload.team_id || null;\n } catch {\n return null;\n }\n }\n\n /**\n * Look up user info from Slack API with caching via state adapter.\n * Returns display name and real name, or falls back to user ID.\n */\n private async lookupUser(\n userId: string\n ): Promise<{ displayName: string; realName: string }> {\n const cacheKey = `slack:user:${userId}`;\n\n // Check cache first (via state adapter for serverless compatibility)\n if (this.chat) {\n const cached = await this.chat.getState().get<CachedUser>(cacheKey);\n if (cached) {\n return { displayName: cached.displayName, realName: cached.realName };\n }\n }\n\n try {\n const result = await this.client.users.info(\n this.withToken({ user: userId })\n );\n const user = result.user as {\n name?: string;\n real_name?: string;\n profile?: { display_name?: string; real_name?: string };\n };\n\n // Slack user naming: profile.display_name > profile.real_name > real_name > name > userId\n const displayName =\n user?.profile?.display_name ||\n user?.profile?.real_name ||\n user?.real_name ||\n user?.name ||\n userId;\n const realName =\n user?.real_name || user?.profile?.real_name || displayName;\n\n // Cache the result via state adapter\n if (this.chat) {\n await this.chat\n .getState()\n .set<CachedUser>(\n cacheKey,\n { displayName, realName },\n SlackAdapter.USER_CACHE_TTL_MS\n );\n }\n\n this.logger.debug(\"Fetched user info\", {\n userId,\n displayName,\n realName,\n });\n return { displayName, realName };\n } catch (error) {\n this.logger.warn(\"Could not fetch user info\", { userId, error });\n // Fall back to user ID\n return { displayName: userId, realName: userId };\n }\n }\n\n async handleWebhook(\n request: Request,\n options?: WebhookOptions\n ): Promise<Response> {\n const body = await request.text();\n this.logger.debug(\"Slack webhook raw body\", { body });\n\n // Verify request signature\n const timestamp = request.headers.get(\"x-slack-request-timestamp\");\n const signature = request.headers.get(\"x-slack-signature\");\n\n if (!this.verifySignature(body, timestamp, signature)) {\n return new Response(\"Invalid signature\", { status: 401 });\n }\n\n // Check if this is a form-urlencoded payload\n const contentType = request.headers.get(\"content-type\") || \"\";\n if (contentType.includes(\"application/x-www-form-urlencoded\")) {\n const params = new URLSearchParams(body);\n if (params.has(\"command\") && !params.has(\"payload\")) {\n const teamId = params.get(\"team_id\");\n if (!this.defaultBotToken && teamId) {\n const ctx = await this.resolveTokenForTeam(teamId);\n if (ctx) {\n return this.requestContext.run(ctx, () =>\n this.handleSlashCommand(params, options)\n );\n }\n this.logger.warn(\"Could not resolve token for slash command\");\n }\n return this.handleSlashCommand(params, options);\n }\n // In multi-workspace mode, resolve token before processing\n if (!this.defaultBotToken) {\n const teamId = this.extractTeamIdFromInteractive(body);\n if (teamId) {\n const ctx = await this.resolveTokenForTeam(teamId);\n if (ctx) {\n return this.requestContext.run(ctx, () =>\n this.handleInteractivePayload(body, options)\n );\n }\n }\n this.logger.warn(\"Could not resolve token for interactive payload\");\n }\n return this.handleInteractivePayload(body, options);\n }\n\n // Parse the JSON payload\n let payload: SlackWebhookPayload;\n try {\n payload = JSON.parse(body);\n } catch {\n return new Response(\"Invalid JSON\", { status: 400 });\n }\n\n // Handle URL verification challenge (signature already verified above)\n if (payload.type === \"url_verification\" && payload.challenge) {\n return Response.json({ challenge: payload.challenge });\n }\n\n // In multi-workspace mode, resolve token from team_id before processing events\n if (!this.defaultBotToken && payload.type === \"event_callback\") {\n const teamId = payload.team_id;\n if (teamId) {\n const ctx = await this.resolveTokenForTeam(teamId);\n if (ctx) {\n return this.requestContext.run(ctx, () => {\n this.processEventPayload(payload, options);\n return new Response(\"ok\", { status: 200 });\n });\n }\n this.logger.warn(\"Could not resolve token for team\", { teamId });\n return new Response(\"ok\", { status: 200 });\n }\n }\n\n // Single-workspace mode or fallback\n this.processEventPayload(payload, options);\n return new Response(\"ok\", { status: 200 });\n }\n\n /** Extract and dispatch events from a validated payload */\n private processEventPayload(\n payload: SlackWebhookPayload,\n options?: WebhookOptions\n ): void {\n if (payload.type === \"event_callback\" && payload.event) {\n const event = payload.event;\n\n if (event.type === \"message\" || event.type === \"app_mention\") {\n const slackEvent = event as SlackEvent;\n if (!(slackEvent.team || slackEvent.team_id) && payload.team_id) {\n slackEvent.team_id = payload.team_id;\n }\n this.handleMessageEvent(slackEvent, options);\n } else if (\n event.type === \"reaction_added\" ||\n event.type === \"reaction_removed\"\n ) {\n this.handleReactionEvent(event as SlackReactionEvent, options);\n } else if (event.type === \"assistant_thread_started\") {\n this.handleAssistantThreadStarted(\n event as SlackAssistantThreadStartedEvent,\n options\n );\n } else if (event.type === \"assistant_thread_context_changed\") {\n this.handleAssistantContextChanged(\n event as SlackAssistantContextChangedEvent,\n options\n );\n } else if (\n event.type === \"app_home_opened\" &&\n (event as SlackAppHomeOpenedEvent).tab === \"home\"\n ) {\n this.handleAppHomeOpened(event as SlackAppHomeOpenedEvent, options);\n } else if (event.type === \"member_joined_channel\") {\n this.handleMemberJoinedChannel(\n event as SlackMemberJoinedChannelEvent,\n options\n );\n }\n }\n }\n\n /**\n * Handle Slack interactive payloads (button clicks, view submissions, etc.).\n * These are sent as form-urlencoded with a `payload` JSON field.\n */\n private handleInteractivePayload(\n body: string,\n options?: WebhookOptions\n ): Response | Promise<Response> {\n const params = new URLSearchParams(body);\n const payloadStr = params.get(\"payload\");\n\n if (!payloadStr) {\n return new Response(\"Missing payload\", { status: 400 });\n }\n\n let payload: SlackInteractivePayload;\n try {\n payload = JSON.parse(payloadStr);\n } catch {\n return new Response(\"Invalid payload JSON\", { status: 400 });\n }\n\n switch (payload.type) {\n case \"block_actions\":\n this.handleBlockActions(payload, options);\n return new Response(\"\", { status: 200 });\n\n case \"view_submission\":\n return this.handleViewSubmission(payload, options);\n\n case \"view_closed\":\n this.handleViewClosed(payload, options);\n return new Response(\"\", { status: 200 });\n\n default:\n return new Response(\"\", { status: 200 });\n }\n }\n\n /**\n * Handle Slack slash command payloads.\n * Slash commands are sent as form-urlencoded with command, text, user_id, channel_id, etc.\n */\n private async handleSlashCommand(\n params: URLSearchParams,\n options?: WebhookOptions\n ): Promise<Response> {\n if (!this.chat) {\n this.logger.warn(\"Chat instance not initialized, ignoring slash command\");\n return new Response(\"\", { status: 200 });\n }\n\n const command = params.get(\"command\") || \"\";\n const text = params.get(\"text\") || \"\";\n const userId = params.get(\"user_id\") || \"\";\n const channelId = params.get(\"channel_id\") || \"\";\n const triggerId = params.get(\"trigger_id\") || undefined;\n\n this.logger.debug(\"Processing Slack slash command\", {\n command,\n text,\n userId,\n channelId,\n triggerId,\n });\n const userInfo = await this.lookupUser(userId);\n const event = {\n command,\n text,\n user: {\n userId,\n userName: userInfo.displayName,\n fullName: userInfo.realName,\n isBot: false,\n isMe: false,\n },\n adapter: this as Adapter,\n raw: Object.fromEntries(params),\n triggerId,\n channelId: channelId ? `slack:${channelId}` : \"\",\n };\n this.chat.processSlashCommand(event, options);\n return new Response(\"\", { status: 200 });\n }\n\n /**\n * Handle block_actions payload (button clicks in Block Kit).\n */\n private handleBlockActions(\n payload: SlackBlockActionsPayload,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\"Chat instance not initialized, ignoring action\");\n return;\n }\n\n const channel = payload.channel?.id || payload.container?.channel_id;\n const messageTs = payload.message?.ts || payload.container?.message_ts;\n const threadTs =\n payload.message?.thread_ts || payload.container?.thread_ts || messageTs;\n\n // Actions from Home tab views don't have channel/messageTs\n const isViewAction = payload.container?.type === \"view\";\n\n if (!(isViewAction || channel)) {\n this.logger.warn(\"Missing channel in block_actions\", { channel });\n return;\n }\n\n const threadId =\n channel && (threadTs || messageTs)\n ? this.encodeThreadId({\n channel,\n threadTs: threadTs || messageTs || \"\",\n })\n : \"\";\n\n const isEphemeral = payload.container?.is_ephemeral === true;\n const responseUrl = payload.response_url;\n const messageId =\n isEphemeral && responseUrl && messageTs\n ? this.encodeEphemeralMessageId(messageTs, responseUrl, payload.user.id)\n : messageTs || \"\";\n\n // Process each action (usually just one, but can be multiple)\n for (const action of payload.actions) {\n const actionValue = action.selected_option?.value ?? action.value;\n const actionEvent: Omit<ActionEvent, \"thread\" | \"openModal\"> & {\n adapter: SlackAdapter;\n } = {\n actionId: action.action_id,\n value: actionValue,\n user: {\n userId: payload.user.id,\n userName: payload.user.username || payload.user.name || \"unknown\",\n fullName: payload.user.name || payload.user.username || \"unknown\",\n isBot: false,\n isMe: false,\n },\n messageId,\n threadId,\n adapter: this,\n raw: payload,\n triggerId: payload.trigger_id,\n };\n\n this.logger.debug(\"Processing Slack block action\", {\n actionId: action.action_id,\n value: action.value,\n messageId: messageTs,\n threadId,\n triggerId: payload.trigger_id,\n });\n\n this.chat.processAction(actionEvent, options);\n }\n }\n\n private async handleViewSubmission(\n payload: SlackViewSubmissionPayload,\n options?: WebhookOptions\n ): Promise<Response> {\n if (!this.chat) {\n this.logger.warn(\n \"Chat instance not initialized, ignoring view submission\"\n );\n return new Response(\"\", { status: 200 });\n }\n\n // Flatten values from Slack's nested structure\n const values: Record<string, string> = {};\n for (const blockValues of Object.values(payload.view.state.values)) {\n for (const [actionId, input] of Object.entries(blockValues)) {\n values[actionId] = input.value ?? input.selected_option?.value ?? \"\";\n }\n }\n\n // Decode contextId and user privateMetadata from private_metadata\n const { contextId, privateMetadata } = decodeModalMetadata(\n payload.view.private_metadata || undefined\n );\n\n const event = {\n callbackId: payload.view.callback_id,\n viewId: payload.view.id,\n values,\n privateMetadata,\n user: {\n userId: payload.user.id,\n userName: payload.user.username || payload.user.name || \"unknown\",\n fullName: payload.user.name || payload.user.username || \"unknown\",\n isBot: false,\n isMe: false,\n },\n adapter: this as Adapter,\n raw: payload,\n };\n\n const response = await this.chat.processModalSubmit(\n event,\n contextId,\n options\n );\n\n if (response) {\n const slackResponse = this.modalResponseToSlack(response, contextId);\n return new Response(JSON.stringify(slackResponse), {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n return new Response(\"\", { status: 200 });\n }\n\n private handleViewClosed(\n payload: SlackViewClosedPayload,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\"Chat instance not initialized, ignoring view closed\");\n return;\n }\n\n // Decode contextId and user privateMetadata from private_metadata\n const { contextId, privateMetadata } = decodeModalMetadata(\n payload.view.private_metadata || undefined\n );\n\n const event = {\n callbackId: payload.view.callback_id,\n viewId: payload.view.id,\n privateMetadata,\n user: {\n userId: payload.user.id,\n userName: payload.user.username || payload.user.name || \"unknown\",\n fullName: payload.user.name || payload.user.username || \"unknown\",\n isBot: false,\n isMe: false,\n },\n adapter: this as Adapter,\n raw: payload,\n };\n\n this.chat.processModalClose(event, contextId, options);\n }\n\n private modalResponseToSlack(\n response: ModalResponse,\n contextId?: string\n ): SlackModalResponse {\n switch (response.action) {\n case \"close\":\n return {};\n case \"errors\":\n return { response_action: \"errors\", errors: response.errors };\n case \"update\": {\n const modal = this.convertModalJSX(response.modal);\n const metadata = encodeModalMetadata({\n contextId,\n privateMetadata: modal.privateMetadata,\n });\n const view = modalToSlackView(modal, metadata);\n return {\n response_action: \"update\",\n view,\n };\n }\n case \"push\": {\n const modal = this.convertModalJSX(response.modal);\n const metadata = encodeModalMetadata({\n contextId,\n privateMetadata: modal.privateMetadata,\n });\n const view = modalToSlackView(modal, metadata);\n return {\n response_action: \"push\",\n view,\n };\n }\n default:\n return {};\n }\n }\n\n private convertModalJSX(modal: ModalElement): ModalElement {\n if (isJSX(modal)) {\n const converted = toModalElement(modal);\n if (!converted) {\n throw new ValidationError(\n \"slack\",\n \"Invalid JSX element: must be a Modal element\"\n );\n }\n return converted;\n }\n return modal;\n }\n\n private verifySignature(\n body: string,\n timestamp: string | null,\n signature: string | null\n ): boolean {\n if (!(timestamp && signature)) {\n return false;\n }\n\n // Check timestamp is recent (within 5 minutes)\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - Number.parseInt(timestamp, 10)) > 300) {\n return false;\n }\n\n // Compute expected signature\n const sigBasestring = `v0:${timestamp}:${body}`;\n const expectedSignature =\n \"v0=\" +\n createHmac(\"sha256\", this.signingSecret)\n .update(sigBasestring)\n .digest(\"hex\");\n\n // Compare signatures using timing-safe comparison\n try {\n return timingSafeEqual(\n Buffer.from(signature),\n Buffer.from(expectedSignature)\n );\n } catch {\n return false;\n }\n }\n\n /**\n * Handle message events from Slack.\n * Bot message filtering (isMe) is handled centrally by the Chat class.\n */\n private handleMessageEvent(\n event: SlackEvent,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\"Chat instance not initialized, ignoring event\");\n return;\n }\n\n // Skip message subtypes that are system/meta events (edits, deletes, joins, etc.)\n // Allow through: bot_message, file_share, thread_broadcast, me_message, and\n // any other content-carrying subtypes. Chat class handles isMe filtering.\n const ignoredSubtypes = new Set([\n \"message_changed\",\n \"message_deleted\",\n \"message_replied\",\n \"channel_join\",\n \"channel_leave\",\n \"channel_topic\",\n \"channel_purpose\",\n \"channel_name\",\n \"channel_archive\",\n \"channel_unarchive\",\n \"group_join\",\n \"group_leave\",\n \"group_topic\",\n \"group_purpose\",\n \"group_name\",\n \"group_archive\",\n \"group_unarchive\",\n \"ekm_access_denied\",\n \"tombstone\",\n ]);\n\n if (event.subtype && ignoredSubtypes.has(event.subtype)) {\n this.logger.debug(\"Ignoring message subtype\", {\n subtype: event.subtype,\n });\n return;\n }\n\n if (!(event.channel && event.ts)) {\n this.logger.debug(\"Ignoring event without channel or ts\", {\n channel: event.channel,\n ts: event.ts,\n });\n return;\n }\n\n // For DMs: top-level messages use empty threadTs (matches openDM subscriptions),\n // thread replies use thread_ts for per-conversation isolation.\n // For channels: always use thread_ts or ts for per-thread IDs.\n const isDM = event.channel_type === \"im\";\n const threadTs = isDM ? event.thread_ts || \"\" : event.thread_ts || event.ts;\n const threadId = this.encodeThreadId({\n channel: event.channel,\n threadTs,\n });\n\n // Let Chat class handle async processing, waitUntil, and isMe filtering\n // Use factory function since parseSlackMessage is async (user lookup)\n //\n // In multi-workspace mode, the request context (token + botUserId) is set via\n // AsyncLocalStorage during synchronous webhook handling. processMessage creates\n // an async task (via waitUntil) that may run after requestContext.run() returns.\n // Node.js AsyncLocalStorage propagates context to async continuations as long as\n // the Promise is created within the run() callback. We call processMessage inside\n // run() so the async task and all its awaits inherit the context.\n const isMention = event.type === \"app_mention\";\n const factory = async (): Promise<Message<unknown>> => {\n const msg = await this.parseSlackMessage(event, threadId);\n if (isMention) {\n msg.isMention = true;\n }\n return msg;\n };\n\n this.chat.processMessage(this, threadId, factory, options);\n }\n\n /**\n * Handle reaction events from Slack (reaction_added, reaction_removed).\n */\n private async handleReactionEvent(\n event: SlackReactionEvent,\n options?: WebhookOptions\n ): Promise<void> {\n if (!this.chat) {\n this.logger.warn(\"Chat instance not initialized, ignoring reaction\");\n return;\n }\n\n // Only handle reactions to messages (not files, etc.)\n if (event.item.type !== \"message\") {\n this.logger.debug(\"Ignoring reaction to non-message item\", {\n itemType: event.item.type,\n });\n return;\n }\n\n // Resolve the parent thread ts — when a reaction is on a reply,\n // event.item.ts is the reply's ts, not the parent thread_ts.\n let parentTs = event.item.ts;\n try {\n const result = await this.client.conversations.replies(\n this.withToken({\n channel: event.item.channel,\n ts: event.item.ts,\n limit: 1,\n })\n );\n const firstMessage = (result.messages as { thread_ts?: string }[])?.[0];\n if (firstMessage?.thread_ts) {\n parentTs = firstMessage.thread_ts;\n }\n } catch (error) {\n this.logger.warn(\n \"Failed to resolve parent thread for reaction, using message ts\",\n {\n error: String(error),\n channel: event.item.channel,\n ts: event.item.ts,\n }\n );\n }\n\n // Build thread ID from the parent thread\n const threadId = this.encodeThreadId({\n channel: event.item.channel,\n threadTs: parentTs,\n });\n\n // Message ID is just the timestamp (Slack uses ts as message ID)\n const messageId = event.item.ts;\n\n // Normalize emoji\n const rawEmoji = event.reaction;\n const normalizedEmoji = defaultEmojiResolver.fromSlack(rawEmoji);\n\n // Check if reaction is from this bot (check request context for multi-workspace)\n const ctx = this.requestContext.getStore();\n const isMe =\n (ctx?.botUserId && event.user === ctx.botUserId) ||\n (this._botUserId !== null && event.user === this._botUserId) ||\n (this._botId !== null && event.user === this._botId);\n\n // Build reaction event\n const reactionEvent: Omit<ReactionEvent, \"adapter\" | \"thread\"> = {\n emoji: normalizedEmoji,\n rawEmoji,\n added: event.type === \"reaction_added\",\n user: {\n userId: event.user,\n userName: event.user, // Will be resolved below if possible\n fullName: event.user,\n isBot: false, // Users add reactions, not bots typically\n isMe,\n },\n messageId,\n threadId,\n raw: event,\n };\n\n // Process reaction\n this.chat.processReaction({ ...reactionEvent, adapter: this }, options);\n }\n\n /**\n * Handle assistant_thread_started events from Slack's Assistants API.\n * Fires when a user opens a new assistant thread (DM with the bot).\n */\n private handleAssistantThreadStarted(\n event: SlackAssistantThreadStartedEvent,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\n \"Chat instance not initialized, ignoring assistant_thread_started\"\n );\n return;\n }\n\n if (!event.assistant_thread) {\n this.logger.warn(\n \"Malformed assistant_thread_started: missing assistant_thread\"\n );\n return;\n }\n\n const { channel_id, thread_ts, user_id, context } = event.assistant_thread;\n const threadId = this.encodeThreadId({\n channel: channel_id,\n threadTs: thread_ts,\n });\n\n this.chat.processAssistantThreadStarted(\n {\n threadId,\n userId: user_id,\n channelId: channel_id,\n threadTs: thread_ts,\n context: {\n channelId: context.channel_id,\n teamId: context.team_id,\n enterpriseId: context.enterprise_id,\n threadEntryPoint: context.thread_entry_point,\n forceSearch: context.force_search,\n },\n adapter: this,\n },\n options\n );\n }\n\n /**\n * Handle assistant_thread_context_changed events from Slack's Assistants API.\n * Fires when a user navigates to a different channel with the assistant panel open.\n */\n private handleAssistantContextChanged(\n event: SlackAssistantContextChangedEvent,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\n \"Chat instance not initialized, ignoring assistant_thread_context_changed\"\n );\n return;\n }\n\n if (!event.assistant_thread) {\n this.logger.warn(\n \"Malformed assistant_thread_context_changed: missing assistant_thread\"\n );\n return;\n }\n\n const { channel_id, thread_ts, user_id, context } = event.assistant_thread;\n const threadId = this.encodeThreadId({\n channel: channel_id,\n threadTs: thread_ts,\n });\n\n this.chat.processAssistantContextChanged(\n {\n threadId,\n userId: user_id,\n channelId: channel_id,\n threadTs: thread_ts,\n context: {\n channelId: context.channel_id,\n teamId: context.team_id,\n enterpriseId: context.enterprise_id,\n threadEntryPoint: context.thread_entry_point,\n forceSearch: context.force_search,\n },\n adapter: this,\n },\n options\n );\n }\n\n /**\n * Handle app_home_opened events from Slack.\n * Fires when a user opens the bot's Home tab.\n */\n private handleAppHomeOpened(\n event: SlackAppHomeOpenedEvent,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\n \"Chat instance not initialized, ignoring app_home_opened\"\n );\n return;\n }\n\n this.chat.processAppHomeOpened(\n {\n userId: event.user,\n channelId: event.channel,\n adapter: this,\n },\n options\n );\n }\n\n /**\n * Handle member_joined_channel events from Slack.\n * Fires when a user (including the bot) joins a channel.\n */\n private handleMemberJoinedChannel(\n event: SlackMemberJoinedChannelEvent,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\n \"Chat instance not initialized, ignoring member_joined_channel\"\n );\n return;\n }\n\n this.chat.processMemberJoinedChannel(\n {\n userId: event.user,\n channelId: this.encodeThreadId({\n channel: event.channel,\n threadTs: \"\",\n }),\n inviterId: event.inviter,\n adapter: this,\n },\n options\n );\n }\n\n /**\n * Publish a Home tab view for a user.\n * Slack API: views.publish\n */\n async publishHomeView(\n userId: string,\n view: Record<string, unknown>\n ): Promise<void> {\n await this.client.views.publish(\n // biome-ignore lint/suspicious/noExplicitAny: view blocks are consumer-defined\n this.withToken({ user_id: userId, view }) as any\n );\n }\n\n /**\n * Set suggested prompts for an assistant thread.\n * Slack Assistants API: assistant.threads.setSuggestedPrompts\n */\n async setSuggestedPrompts(\n channelId: string,\n threadTs: string,\n prompts: Array<{ title: string; message: string }>,\n title?: string\n ): Promise<void> {\n await this.client.assistant.threads.setSuggestedPrompts(\n this.withToken({\n channel_id: channelId,\n thread_ts: threadTs,\n prompts,\n title,\n })\n );\n }\n\n /**\n * Set status/thinking indicator for an assistant thread.\n * Slack Assistants API: assistant.threads.setStatus\n */\n async setAssistantStatus(\n channelId: string,\n threadTs: string,\n status: string,\n loadingMessages?: string[]\n ): Promise<void> {\n await this.client.assistant.threads.setStatus(\n this.withToken({\n channel_id: channelId,\n thread_ts: threadTs,\n status,\n ...(loadingMessages && { loading_messages: loadingMessages }),\n })\n );\n }\n\n /**\n * Set title for an assistant thread (shown in History tab).\n * Slack Assistants API: assistant.threads.setTitle\n */\n async setAssistantTitle(\n channelId: string,\n threadTs: string,\n title: string\n ): Promise<void> {\n await this.client.assistant.threads.setTitle(\n this.withToken({\n channel_id: channelId,\n thread_ts: threadTs,\n title,\n })\n );\n }\n\n /**\n * Resolve inline user mentions in Slack mrkdwn text.\n * Converts <@U123> to <@U123|displayName> so that toAst/extractPlainText\n * renders them as @displayName instead of @U123.\n *\n * @param skipSelfMention - When true, skips the bot's own user ID so that\n * mention detection (which looks for @botUserId in the text) continues to\n * work. Set to false when parsing historical/channel messages where mention\n * detection doesn't apply.\n */\n private async resolveInlineMentions(\n text: string,\n skipSelfMention: boolean\n ): Promise<string> {\n const userIds = new Set<string>();\n // Parse mentions by splitting on angle brackets to avoid ReDoS\n for (const segment of text.split(\"<\")) {\n const end = segment.indexOf(\">\");\n if (end === -1) {\n continue;\n }\n const inner = segment.slice(0, end);\n if (!inner.startsWith(\"@\")) {\n continue;\n }\n const rest = inner.slice(1);\n const pipeIdx = rest.indexOf(\"|\");\n const uid = pipeIdx >= 0 ? rest.slice(0, pipeIdx) : rest;\n if (SLACK_USER_ID_PATTERN.test(uid)) {\n userIds.add(uid);\n }\n }\n if (userIds.size === 0) {\n return text;\n }\n\n // Don't resolve the bot's own mention when processing incoming webhooks —\n // detectMention needs @botUserId in the text\n if (skipSelfMention && this._botUserId) {\n userIds.delete(this._botUserId);\n }\n if (userIds.size === 0) {\n return text;\n }\n\n // Look up all mentioned users in parallel\n const lookups = await Promise.all(\n [...userIds].map(async (uid) => {\n const info = await this.lookupUser(uid);\n return [uid, info.displayName] as const;\n })\n );\n const nameMap = new Map(lookups);\n\n // Replace <@U123> and <@U123|old> with <@U123|resolvedName>\n // Use split-based approach to avoid ReDoS on user-controlled input\n let result = \"\";\n let remaining = text;\n let startIdx = remaining.indexOf(\"<@\");\n while (startIdx !== -1) {\n result += remaining.slice(0, startIdx);\n remaining = remaining.slice(startIdx);\n const endIdx = remaining.indexOf(\">\");\n if (endIdx === -1) {\n break;\n }\n const inner = remaining.slice(2, endIdx); // after \"<@\"\n const pipeIdx = inner.indexOf(\"|\");\n const uid = pipeIdx >= 0 ? inner.slice(0, pipeIdx) : inner;\n if (SLACK_USER_ID_PATTERN.test(uid)) {\n const name = nameMap.get(uid);\n result += name ? `<@${uid}|${name}>` : `<@${uid}>`;\n } else {\n result += remaining.slice(0, endIdx + 1);\n }\n remaining = remaining.slice(endIdx + 1);\n startIdx = remaining.indexOf(\"<@\");\n }\n return result + remaining;\n }\n\n private async parseSlackMessage(\n event: SlackEvent,\n threadId: string,\n options?: { skipSelfMention?: boolean }\n ): Promise<Message<unknown>> {\n const isMe = this.isMessageFromSelf(event);\n const skipSelfMention = options?.skipSelfMention ?? true;\n\n const rawText = event.text || \"\";\n\n // Get user info - for human users we need to look up the display name\n // since Slack events only include the user ID, not the username\n let userName = event.username || \"unknown\";\n let fullName = event.username || \"unknown\";\n\n // If we have a user ID but no username, look up the user info\n if (event.user && !event.username) {\n const userInfo = await this.lookupUser(event.user);\n userName = userInfo.displayName;\n fullName = userInfo.realName;\n }\n\n // Resolve inline @mentions to display names\n const text = await this.resolveInlineMentions(rawText, skipSelfMention);\n\n return new Message({\n id: event.ts || \"\",\n threadId,\n text: this.formatConverter.extractPlainText(text),\n formatted: this.formatConverter.toAst(text),\n raw: event,\n author: {\n userId: event.user || event.bot_id || \"unknown\",\n userName,\n fullName,\n isBot: !!event.bot_id,\n isMe,\n },\n metadata: {\n dateSent: new Date(Number.parseFloat(event.ts || \"0\") * 1000),\n edited: !!event.edited,\n editedAt: event.edited\n ? new Date(Number.parseFloat(event.edited.ts) * 1000)\n : undefined,\n },\n attachments: (event.files || []).map((file) =>\n this.createAttachment(file)\n ),\n });\n }\n\n /**\n * Create an Attachment object from a Slack file.\n * Includes a fetchData method that uses the bot token for auth.\n */\n private createAttachment(file: {\n id?: string;\n mimetype?: string;\n url_private?: string;\n name?: string;\n size?: number;\n original_w?: number;\n original_h?: number;\n }): Attachment {\n const url = file.url_private;\n // Capture token at attachment creation time (during webhook processing context)\n const botToken = this.getToken();\n\n // Determine type based on mimetype\n let type: Attachment[\"type\"] = \"file\";\n if (file.mimetype?.startsWith(\"image/\")) {\n type = \"image\";\n } else if (file.mimetype?.startsWith(\"video/\")) {\n type = \"video\";\n } else if (file.mimetype?.startsWith(\"audio/\")) {\n type = \"audio\";\n }\n\n return {\n type,\n url,\n name: file.name,\n mimeType: file.mimetype,\n size: file.size,\n width: file.original_w,\n height: file.original_h,\n fetchData: url\n ? async () => {\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${botToken}`,\n },\n });\n if (!response.ok) {\n throw new NetworkError(\n \"slack\",\n `Failed to fetch file: ${response.status} ${response.statusText}`\n );\n }\n const arrayBuffer = await response.arrayBuffer();\n return Buffer.from(arrayBuffer);\n }\n : undefined,\n };\n }\n\n /**\n * Try to render a message using native Slack table blocks.\n * Returns blocks + fallback text if the message contains tables, null otherwise.\n */\n private renderWithTableBlocks(\n message: AdapterPostableMessage\n ): { text: string; blocks: SlackBlock[] } | null {\n let ast: Root | null = null;\n if (typeof message === \"object\" && message !== null) {\n if (\"ast\" in message) {\n ast = (message as { ast: Root }).ast;\n } else if (\"markdown\" in message) {\n ast = parseMarkdown((message as { markdown: string }).markdown);\n }\n }\n if (!ast) {\n return null;\n }\n\n const blocks = this.formatConverter.toBlocksWithTable(ast);\n if (!blocks) {\n return null;\n }\n\n // Use regular rendering as fallback text for notifications\n const fallbackText = convertEmojiPlaceholders(\n this.formatConverter.renderPostable(message),\n \"slack\"\n );\n return { text: fallbackText, blocks };\n }\n\n async postMessage(\n threadId: string,\n message: AdapterPostableMessage\n ): Promise<RawMessage<unknown>> {\n const { channel, threadTs } = this.decodeThreadId(threadId);\n\n try {\n // Check for files to upload\n const files = extractFiles(message);\n if (files.length > 0) {\n // Upload files first (they're shared to the channel automatically)\n await this.uploadFiles(files, channel, threadTs || undefined);\n\n // If message only has files (no text/card), return early\n const hasText =\n typeof message === \"string\" ||\n (typeof message === \"object\" &&\n message !== null &&\n ((\"raw\" in message && message.raw) ||\n (\"markdown\" in message && message.markdown) ||\n (\"ast\" in message && message.ast)));\n const card = extractCard(message);\n\n if (!(hasText || card)) {\n // Return a synthetic message ID since files.uploadV2 handles sharing\n return {\n id: `file-${Date.now()}`,\n threadId,\n raw: { files },\n };\n }\n }\n\n // Check if message contains a card\n const card = extractCard(message);\n\n if (card) {\n // Render card as Block Kit\n const blocks = cardToBlockKit(card);\n const fallbackText = cardToFallbackText(card);\n\n this.logger.debug(\"Slack API: chat.postMessage (blocks)\", {\n channel,\n threadTs,\n blockCount: blocks.length,\n });\n\n const result = await this.client.chat.postMessage(\n this.withToken({\n channel,\n thread_ts: threadTs,\n text: fallbackText, // Fallback for notifications\n blocks,\n unfurl_links: false,\n unfurl_media: false,\n })\n );\n\n this.logger.debug(\"Slack API: chat.postMessage response\", {\n messageId: result.ts,\n ok: result.ok,\n });\n\n return {\n id: result.ts as string,\n threadId,\n raw: result,\n };\n }\n\n // Check for tables in markdown/AST messages → use native table blocks\n const tableResult = this.renderWithTableBlocks(message);\n if (tableResult) {\n this.logger.debug(\"Slack API: chat.postMessage (table blocks)\", {\n channel,\n threadTs,\n blockCount: tableResult.blocks.length,\n });\n\n const result = await this.client.chat.postMessage(\n this.withToken({\n channel,\n thread_ts: threadTs,\n text: tableResult.text,\n blocks: tableResult.blocks,\n unfurl_links: false,\n unfurl_media: false,\n })\n );\n\n this.logger.debug(\"Slack API: chat.postMessage response\", {\n messageId: result.ts,\n ok: result.ok,\n });\n\n return {\n id: result.ts as string,\n threadId,\n raw: result,\n };\n }\n\n // Regular text message\n const text = convertEmojiPlaceholders(\n this.formatConverter.renderPostable(message),\n \"slack\"\n );\n\n this.logger.debug(\"Slack API: chat.postMessage\", {\n channel,\n threadTs,\n textLength: text.length,\n });\n\n const result = await this.client.chat.postMessage(\n this.withToken({\n channel,\n thread_ts: threadTs,\n text,\n unfurl_links: false,\n unfurl_media: false,\n })\n );\n\n this.logger.debug(\"Slack API: chat.postMessage response\", {\n messageId: result.ts,\n ok: result.ok,\n });\n\n return {\n id: result.ts as string,\n threadId,\n raw: result,\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async postEphemeral(\n threadId: string,\n userId: string,\n message: AdapterPostableMessage\n ): Promise<EphemeralMessage> {\n const { channel, threadTs } = this.decodeThreadId(threadId);\n\n try {\n // Check if message contains a card\n const card = extractCard(message);\n\n if (card) {\n // Render card as Block Kit\n const blocks = cardToBlockKit(card);\n const fallbackText = cardToFallbackText(card);\n\n this.logger.debug(\"Slack API: chat.postEphemeral (blocks)\", {\n channel,\n threadTs,\n userId,\n blockCount: blocks.length,\n });\n\n const result = await this.client.chat.postEphemeral(\n this.withToken({\n channel,\n thread_ts: threadTs || undefined,\n user: userId,\n text: fallbackText,\n blocks,\n })\n );\n\n this.logger.debug(\"Slack API: chat.postEphemeral response\", {\n messageTs: result.message_ts,\n ok: result.ok,\n });\n\n return {\n id: result.message_ts || \"\",\n threadId,\n usedFallback: false,\n raw: result,\n };\n }\n\n // Check for tables in markdown/AST messages → use native table blocks\n const tableResult = this.renderWithTableBlocks(message);\n if (tableResult) {\n this.logger.debug(\"Slack API: chat.postEphemeral (table blocks)\", {\n channel,\n threadTs,\n userId,\n blockCount: tableResult.blocks.length,\n });\n\n const result = await this.client.chat.postEphemeral(\n this.withToken({\n channel,\n thread_ts: threadTs || undefined,\n user: userId,\n text: tableResult.text,\n blocks: tableResult.blocks,\n })\n );\n\n this.logger.debug(\"Slack API: chat.postEphemeral response\", {\n messageTs: result.message_ts,\n ok: result.ok,\n });\n\n return {\n id: result.message_ts || \"\",\n threadId,\n usedFallback: false,\n raw: result,\n };\n }\n\n // Regular text message\n const text = convertEmojiPlaceholders(\n this.formatConverter.renderPostable(message),\n \"slack\"\n );\n\n this.logger.debug(\"Slack API: chat.postEphemeral\", {\n channel,\n threadTs,\n userId,\n textLength: text.length,\n });\n\n const result = await this.client.chat.postEphemeral(\n this.withToken({\n channel,\n thread_ts: threadTs || undefined,\n user: userId,\n text,\n })\n );\n\n this.logger.debug(\"Slack API: chat.postEphemeral response\", {\n messageTs: result.message_ts,\n ok: result.ok,\n });\n\n return {\n id: result.message_ts || \"\",\n threadId,\n usedFallback: false,\n raw: result,\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async scheduleMessage(\n threadId: string,\n message: AdapterPostableMessage,\n options: { postAt: Date }\n ): Promise<ScheduledMessage> {\n const { channel, threadTs } = this.decodeThreadId(threadId);\n const postAtUnix = Math.floor(options.postAt.getTime() / 1000);\n\n if (postAtUnix <= Math.floor(Date.now() / 1000)) {\n throw new ValidationError(\"slack\", \"postAt must be in the future\");\n }\n\n // File uploads are not supported by chat.scheduleMessage\n const files = extractFiles(message);\n if (files.length > 0) {\n throw new ValidationError(\n \"slack\",\n \"File uploads are not supported in scheduled messages\"\n );\n }\n\n // Capture token now so cancel() works outside request context\n const token = this.getToken();\n\n try {\n const card = extractCard(message);\n\n if (card) {\n const blocks = cardToBlockKit(card);\n const fallbackText = cardToFallbackText(card);\n\n this.logger.debug(\"Slack API: chat.scheduleMessage (blocks)\", {\n channel,\n threadTs,\n postAt: postAtUnix,\n blockCount: blocks.length,\n });\n\n const result = await this.client.chat.scheduleMessage({\n token,\n channel,\n thread_ts: threadTs || undefined,\n post_at: postAtUnix,\n text: fallbackText,\n blocks,\n unfurl_links: false,\n unfurl_media: false,\n });\n\n const scheduledMessageId = result.scheduled_message_id as string;\n const adapter = this;\n\n return {\n scheduledMessageId,\n channelId: channel,\n postAt: options.postAt,\n raw: result,\n async cancel() {\n await adapter.client.chat.deleteScheduledMessage({\n token,\n channel,\n scheduled_message_id: scheduledMessageId,\n });\n },\n };\n }\n\n // Regular text message\n const text = convertEmojiPlaceholders(\n this.formatConverter.renderPostable(message),\n \"slack\"\n );\n\n this.logger.debug(\"Slack API: chat.scheduleMessage\", {\n channel,\n threadTs,\n postAt: postAtUnix,\n textLength: text.length,\n });\n\n const result = await this.client.chat.scheduleMessage({\n token,\n channel,\n thread_ts: threadTs || undefined,\n post_at: postAtUnix,\n text,\n unfurl_links: false,\n unfurl_media: false,\n });\n\n const scheduledMessageId = result.scheduled_message_id as string;\n const adapter = this;\n\n return {\n scheduledMessageId,\n channelId: channel,\n postAt: options.postAt,\n raw: result,\n async cancel() {\n await adapter.client.chat.deleteScheduledMessage({\n token,\n channel,\n scheduled_message_id: scheduledMessageId,\n });\n },\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async openModal(\n triggerId: string,\n modal: ModalElement,\n contextId?: string\n ): Promise<{ viewId: string }> {\n const metadata = encodeModalMetadata({\n contextId,\n privateMetadata: modal.privateMetadata,\n });\n const view = modalToSlackView(modal, metadata);\n\n this.logger.debug(\"Slack API: views.open\", {\n triggerId,\n callbackId: modal.callbackId,\n });\n\n try {\n const result = await this.client.views.open(\n this.withToken({\n trigger_id: triggerId,\n view,\n })\n );\n\n this.logger.debug(\"Slack API: views.open response\", {\n viewId: result.view?.id,\n ok: result.ok,\n });\n\n return { viewId: result.view?.id as string };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async updateModal(\n viewId: string,\n modal: ModalElement\n ): Promise<{ viewId: string }> {\n const view = modalToSlackView(modal);\n\n this.logger.debug(\"Slack API: views.update\", {\n viewId,\n callbackId: modal.callbackId,\n });\n\n try {\n const result = await this.client.views.update(\n this.withToken({\n view_id: viewId,\n view,\n })\n );\n\n this.logger.debug(\"Slack API: views.update response\", {\n viewId: result.view?.id,\n ok: result.ok,\n });\n\n return { viewId: result.view?.id as string };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n /**\n * Upload files to Slack and share them to a channel.\n * Returns the file IDs of uploaded files.\n */\n private async uploadFiles(\n files: FileUpload[],\n channel: string,\n threadTs?: string\n ): Promise<string[]> {\n const bufferResults = await Promise.all(\n files.map(async (file) => {\n try {\n const fileBuffer = await toBuffer(file.data, { platform: \"slack\" });\n if (!fileBuffer) {\n return null;\n }\n return { file: fileBuffer, filename: file.filename };\n } catch (error) {\n this.logger.error(\"Failed to convert file to buffer\", {\n filename: file.filename,\n error,\n });\n return null;\n }\n })\n );\n const fileUploads = bufferResults.filter(\n (result): result is NonNullable<typeof result> => result !== null\n );\n if (fileUploads.length === 0) {\n return [];\n }\n this.logger.debug(\"Slack API: files.uploadV2 (batch)\", {\n fileCount: fileUploads.length,\n filenames: fileUploads.map((f) => f.filename),\n });\n\n // biome-ignore lint/suspicious/noExplicitAny: Slack API types don't match actual usage\n const uploadArgs: any = { channel_id: channel, file_uploads: fileUploads };\n if (threadTs) {\n uploadArgs.thread_ts = threadTs;\n }\n uploadArgs.token = this.getToken();\n const result = (await this.client.files.uploadV2(uploadArgs)) as {\n ok: boolean;\n files?: Array<{ files?: Array<{ id?: string }> }>;\n };\n this.logger.debug(\"Slack API: files.uploadV2 response\", { ok: result.ok });\n const fileIds: string[] = [];\n if (result.files?.[0]?.files) {\n for (const uploadedFile of result.files[0].files) {\n if (uploadedFile.id) {\n fileIds.push(uploadedFile.id);\n }\n }\n }\n\n return fileIds;\n }\n\n async editMessage(\n threadId: string,\n messageId: string,\n message: AdapterPostableMessage\n ): Promise<RawMessage<unknown>> {\n const ephemeral = this.decodeEphemeralMessageId(messageId);\n if (ephemeral) {\n const { threadTs } = this.decodeThreadId(threadId);\n const result = await this.sendToResponseUrl(\n ephemeral.responseUrl,\n \"replace\",\n {\n message,\n threadTs,\n }\n );\n return {\n id: ephemeral.messageTs,\n threadId,\n raw: { ephemeral: true, ...result },\n };\n }\n\n const { channel } = this.decodeThreadId(threadId);\n\n try {\n // Check if message contains a card\n const card = extractCard(message);\n\n if (card) {\n // Render card as Block Kit\n const blocks = cardToBlockKit(card);\n const fallbackText = cardToFallbackText(card);\n\n this.logger.debug(\"Slack API: chat.update (blocks)\", {\n channel,\n messageId,\n blockCount: blocks.length,\n });\n\n const result = await this.client.chat.update(\n this.withToken({\n channel,\n ts: messageId,\n text: fallbackText,\n blocks,\n })\n );\n\n this.logger.debug(\"Slack API: chat.update response\", {\n messageId: result.ts,\n ok: result.ok,\n });\n\n return {\n id: result.ts as string,\n threadId,\n raw: result,\n };\n }\n\n // Check for tables in markdown/AST messages → use native table blocks\n const tableResult = this.renderWithTableBlocks(message);\n if (tableResult) {\n this.logger.debug(\"Slack API: chat.update (table blocks)\", {\n channel,\n messageId,\n blockCount: tableResult.blocks.length,\n });\n\n const result = await this.client.chat.update(\n this.withToken({\n channel,\n ts: messageId,\n text: tableResult.text,\n blocks: tableResult.blocks,\n })\n );\n\n this.logger.debug(\"Slack API: chat.update response\", {\n messageId: result.ts,\n ok: result.ok,\n });\n\n return {\n id: result.ts as string,\n threadId,\n raw: result,\n };\n }\n\n // Regular text message\n const text = convertEmojiPlaceholders(\n this.formatConverter.renderPostable(message),\n \"slack\"\n );\n\n this.logger.debug(\"Slack API: chat.update\", {\n channel,\n messageId,\n textLength: text.length,\n });\n\n const result = await this.client.chat.update(\n this.withToken({\n channel,\n ts: messageId,\n text,\n })\n );\n\n this.logger.debug(\"Slack API: chat.update response\", {\n messageId: result.ts,\n ok: result.ok,\n });\n\n return {\n id: result.ts as string,\n threadId,\n raw: result,\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async deleteMessage(threadId: string, messageId: string): Promise<void> {\n const ephemeral = this.decodeEphemeralMessageId(messageId);\n if (ephemeral) {\n await this.sendToResponseUrl(ephemeral.responseUrl, \"delete\");\n return;\n }\n const { channel } = this.decodeThreadId(threadId);\n\n try {\n this.logger.debug(\"Slack API: chat.delete\", { channel, messageId });\n\n await this.client.chat.delete(\n this.withToken({\n channel,\n ts: messageId,\n })\n );\n\n this.logger.debug(\"Slack API: chat.delete response\", { ok: true });\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async addReaction(\n threadId: string,\n messageId: string,\n emoji: EmojiValue | string\n ): Promise<void> {\n const { channel } = this.decodeThreadId(threadId);\n // Convert emoji (EmojiValue or string) to Slack format, strip colons\n const slackEmoji = defaultEmojiResolver.toSlack(emoji);\n const name = slackEmoji.replace(/:/g, \"\");\n\n try {\n this.logger.debug(\"Slack API: reactions.add\", {\n channel,\n messageId,\n emoji: name,\n });\n\n await this.client.reactions.add(\n this.withToken({\n channel,\n timestamp: messageId,\n name,\n })\n );\n\n this.logger.debug(\"Slack API: reactions.add response\", { ok: true });\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async removeReaction(\n threadId: string,\n messageId: string,\n emoji: EmojiValue | string\n ): Promise<void> {\n const { channel } = this.decodeThreadId(threadId);\n // Convert emoji (EmojiValue or string) to Slack format, strip colons\n const slackEmoji = defaultEmojiResolver.toSlack(emoji);\n const name = slackEmoji.replace(/:/g, \"\");\n\n try {\n this.logger.debug(\"Slack API: reactions.remove\", {\n channel,\n messageId,\n emoji: name,\n });\n\n await this.client.reactions.remove(\n this.withToken({\n channel,\n timestamp: messageId,\n name,\n })\n );\n\n this.logger.debug(\"Slack API: reactions.remove response\", { ok: true });\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n /**\n * Show typing indicator with optional custom status.\n *\n * When status is provided, uses Slack's assistant.threads.setStatus API\n * to show custom loading text (requires Agents & AI Apps feature and assistant:write scope).\n * The status auto-clears when a message is posted to the thread.\n *\n * When status is not provided, defaults to \"Typing...\" with default loading messages.\n *\n * @param threadId - The thread to show the indicator in\n * @param status - Optional custom status message (e.g., \"Searching documents...\")\n */\n async startTyping(threadId: string, status?: string): Promise<void> {\n const { channel, threadTs } = this.decodeThreadId(threadId);\n if (!threadTs) {\n this.logger.debug(\"Slack: startTyping skipped - no thread context\");\n return;\n }\n this.logger.debug(\"Slack API: assistant.threads.setStatus\", {\n channel,\n threadTs,\n status,\n });\n try {\n await this.client.assistant.threads.setStatus(\n this.withToken({\n channel_id: channel,\n thread_ts: threadTs,\n status: status ?? \"Typing...\",\n loading_messages: [status ?? \"Typing...\"],\n })\n );\n } catch (error) {\n this.logger.warn(\"Slack API: assistant.threads.setStatus failed\", {\n channel,\n threadTs,\n error,\n });\n }\n }\n\n /**\n * Stream a message using Slack's native streaming API.\n *\n * Consumes an async iterable of text chunks and/or structured StreamChunk\n * objects (task_update, plan_update, markdown_text) and streams them to Slack.\n *\n * Plain strings are rendered through StreamingMarkdownRenderer for safe\n * incremental markdown. StreamChunk objects are passed directly to Slack's\n * streaming API as chunk payloads, enabling native task progress cards\n * and plan displays in the Slack AI Assistant UI.\n *\n * Requires `recipientUserId` and `recipientTeamId` in options.\n */\n async stream(\n threadId: string,\n textStream: AsyncIterable<string | StreamChunk>,\n options?: StreamOptions\n ): Promise<RawMessage<unknown>> {\n if (!(options?.recipientUserId && options?.recipientTeamId)) {\n throw new ValidationError(\n \"slack\",\n \"Slack streaming requires recipientUserId and recipientTeamId in options\"\n );\n }\n const { channel, threadTs } = this.decodeThreadId(threadId);\n this.logger.debug(\"Slack: starting stream\", { channel, threadTs });\n\n const token = this.getToken();\n const streamer = this.client.chatStream({\n channel,\n thread_ts: threadTs,\n recipient_user_id: options.recipientUserId,\n recipient_team_id: options.recipientTeamId,\n ...(options.taskDisplayMode && {\n task_display_mode: options.taskDisplayMode,\n }),\n });\n\n let first = true;\n let lastAppended = \"\";\n const renderer = new StreamingMarkdownRenderer();\n\n /**\n * Helper to flush markdown text delta to the stream.\n * Handles first-append token passing and empty-delta skipping.\n */\n const flushMarkdownDelta = async (delta: string): Promise<void> => {\n if (delta.length === 0) {\n return;\n }\n if (first) {\n // Pass token on first append so the streamer uses it for all subsequent calls\n // biome-ignore lint/suspicious/noExplicitAny: ChatStreamer types don't include token\n await streamer.append({ markdown_text: delta, token } as any);\n first = false;\n } else {\n await streamer.append({ markdown_text: delta });\n }\n };\n\n /**\n * Helper to send a structured chunk (task_update, plan_update, etc.)\n * directly to Slack's streaming API. Any buffered markdown text is\n * flushed first to maintain correct ordering.\n *\n * If the Slack API rejects the chunk (e.g. missing assistant:write scope,\n * older @slack/web-api version, or Assistant features not enabled in the\n * app manifest), the error is logged and the chunk is silently skipped.\n * Text streaming continues unaffected.\n */\n let structuredChunksSupported = true;\n const sendStructuredChunk = async (chunk: StreamChunk): Promise<void> => {\n if (!structuredChunksSupported) {\n return;\n }\n\n // Flush any buffered markdown before sending the structured chunk\n const committable = renderer.getCommittableText();\n const delta = committable.slice(lastAppended.length);\n await flushMarkdownDelta(delta);\n lastAppended = committable;\n\n try {\n // Send the chunk directly — Slack's API accepts chunks array\n if (first) {\n // biome-ignore lint/suspicious/noExplicitAny: ChatStreamer types don't include token or chunks\n await streamer.append({ chunks: [chunk], token } as any);\n first = false;\n } else {\n // biome-ignore lint/suspicious/noExplicitAny: chunks not in ChatAppendStreamArguments for older @slack/web-api\n await streamer.append({ chunks: [chunk] } as any);\n }\n } catch (error) {\n // Structured chunks may fail if the app doesn't have the required\n // Assistant scopes/features. Disable for the rest of this stream\n // to avoid repeated failures and log once.\n structuredChunksSupported = false;\n this.logger.warn(\n \"Structured streaming chunk failed, falling back to text-only streaming. \" +\n \"Ensure your Slack app manifest includes assistant_view, assistant:write scope, \" +\n \"and @slack/web-api >= 7.14.0\",\n { chunkType: chunk.type, error }\n );\n }\n };\n\n const pushTextAndFlush = async (text: string): Promise<void> => {\n renderer.push(text);\n const committable = renderer.getCommittableText();\n const delta = committable.slice(lastAppended.length);\n await flushMarkdownDelta(delta);\n lastAppended = committable;\n };\n\n for await (const chunk of textStream) {\n if (typeof chunk === \"string\") {\n await pushTextAndFlush(chunk);\n } else if (chunk.type === \"markdown_text\") {\n await pushTextAndFlush(chunk.text);\n } else {\n // Structured chunk (task_update, plan_update) — send directly to Slack\n await sendStructuredChunk(chunk);\n }\n }\n\n // Flush any remaining buffered content (e.g. held table rows at end of stream).\n renderer.finish();\n const finalCommittable = renderer.getCommittableText();\n const finalDelta = finalCommittable.slice(lastAppended.length);\n await flushMarkdownDelta(finalDelta);\n\n const result = await streamer.stop(\n // biome-ignore lint/suspicious/noExplicitAny: stopBlocks are platform-specific Block Kit elements\n options?.stopBlocks ? { blocks: options.stopBlocks as any[] } : undefined\n );\n const messageTs = (result.message?.ts ?? result.ts) as string;\n\n this.logger.debug(\"Slack: stream complete\", { messageId: messageTs });\n\n return {\n id: messageTs,\n threadId,\n raw: result,\n };\n }\n\n /**\n * Open a direct message conversation with a user.\n * Returns a thread ID that can be used to post messages.\n */\n async openDM(userId: string): Promise<string> {\n try {\n this.logger.debug(\"Slack API: conversations.open\", { userId });\n\n const result = await this.client.conversations.open(\n this.withToken({ users: userId })\n );\n\n if (!result.channel?.id) {\n throw new NetworkError(\n \"slack\",\n \"Failed to open DM - no channel returned\"\n );\n }\n\n const channelId = result.channel.id;\n\n this.logger.debug(\"Slack API: conversations.open response\", {\n channelId,\n ok: result.ok,\n });\n\n // Encode as thread ID (no threadTs for new DM - messages will start new threads)\n return this.encodeThreadId({\n channel: channelId,\n threadTs: \"\", // Empty threadTs indicates top-level channel messages\n });\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async fetchMessages(\n threadId: string,\n options: FetchOptions = {}\n ): Promise<FetchResult<unknown>> {\n const { channel, threadTs } = this.decodeThreadId(threadId);\n const direction = options.direction ?? \"backward\";\n const limit = options.limit || 100;\n\n try {\n if (direction === \"forward\") {\n // Forward direction: fetch oldest messages first, cursor moves to newer\n // Uses native Slack cursor pagination which is efficient\n return await this.fetchMessagesForward(\n channel,\n threadTs,\n threadId,\n limit,\n options.cursor\n );\n }\n // Backward direction: fetch most recent messages first, cursor moves to older\n // Slack API returns oldest-first, so we need to work around this\n return await this.fetchMessagesBackward(\n channel,\n threadTs,\n threadId,\n limit,\n options.cursor\n );\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n /**\n * Fetch messages in forward direction (oldest first, efficient).\n * Uses native Slack cursor pagination.\n */\n private async fetchMessagesForward(\n channel: string,\n threadTs: string,\n threadId: string,\n limit: number,\n cursor?: string\n ): Promise<FetchResult<unknown>> {\n this.logger.debug(\"Slack API: conversations.replies (forward)\", {\n channel,\n threadTs,\n limit,\n cursor,\n });\n\n const result = await this.client.conversations.replies(\n this.withToken({\n channel,\n ts: threadTs,\n limit,\n cursor,\n })\n );\n\n const slackMessages = (result.messages || []) as SlackEvent[];\n const nextCursor = (\n result as { response_metadata?: { next_cursor?: string } }\n ).response_metadata?.next_cursor;\n\n this.logger.debug(\"Slack API: conversations.replies response\", {\n messageCount: slackMessages.length,\n ok: result.ok,\n hasNextCursor: !!nextCursor,\n });\n\n const messages = await Promise.all(\n slackMessages.map((msg) => this.parseSlackMessage(msg, threadId))\n );\n\n return {\n messages,\n nextCursor: nextCursor || undefined,\n };\n }\n\n /**\n * Fetch messages in backward direction (most recent first).\n *\n * Slack's API returns oldest-first, so for backward direction we:\n * 1. Use `latest` parameter to fetch messages before a timestamp (cursor)\n * 2. Fetch up to 1000 messages (API limit) and take the last N\n * 3. Return messages in chronological order (oldest first within the page)\n *\n * Note: For very large threads (>1000 messages), the first backward call\n * may not return the absolute most recent messages. This is a Slack API limitation.\n */\n private async fetchMessagesBackward(\n channel: string,\n threadTs: string,\n threadId: string,\n limit: number,\n cursor?: string\n ): Promise<FetchResult<unknown>> {\n // Cursor is a timestamp - fetch messages before this time\n // For the initial call (no cursor), we want the most recent messages\n const latest = cursor || undefined;\n\n this.logger.debug(\"Slack API: conversations.replies (backward)\", {\n channel,\n threadTs,\n limit,\n latest,\n });\n\n // Fetch a larger batch to ensure we can return the last `limit` messages\n // Slack API max is 1000 messages per request\n const fetchLimit = Math.min(1000, Math.max(limit * 2, 200));\n\n const result = await this.client.conversations.replies(\n this.withToken({\n channel,\n ts: threadTs,\n limit: fetchLimit,\n latest,\n inclusive: false, // Don't include the cursor message itself\n })\n );\n\n const slackMessages = (result.messages || []) as SlackEvent[];\n\n this.logger.debug(\"Slack API: conversations.replies response (backward)\", {\n messageCount: slackMessages.length,\n ok: result.ok,\n hasMore: result.has_more,\n });\n\n // If we have more messages than requested, take the last `limit`\n // This gives us the most recent messages\n const startIndex = Math.max(0, slackMessages.length - limit);\n const selectedMessages = slackMessages.slice(startIndex);\n\n const messages = await Promise.all(\n selectedMessages.map((msg) => this.parseSlackMessage(msg, threadId))\n );\n\n // For backward pagination, nextCursor points to older messages\n // Use the timestamp of the oldest message we're NOT returning\n let nextCursor: string | undefined;\n if (startIndex > 0 || result.has_more) {\n // There are more (older) messages available\n // Use the timestamp of the oldest message in our selection as the cursor\n const oldestSelected = selectedMessages[0];\n if (oldestSelected?.ts) {\n nextCursor = oldestSelected.ts;\n }\n }\n\n return {\n messages,\n nextCursor,\n };\n }\n\n async fetchThread(threadId: string): Promise<ThreadInfo> {\n const { channel, threadTs } = this.decodeThreadId(threadId);\n\n try {\n this.logger.debug(\"Slack API: conversations.info\", { channel });\n\n const result = await this.client.conversations.info(\n this.withToken({ channel })\n );\n const channelInfo = result.channel as { name?: string } | undefined;\n\n this.logger.debug(\"Slack API: conversations.info response\", {\n channelName: channelInfo?.name,\n ok: result.ok,\n });\n\n return {\n id: threadId,\n channelId: channel,\n channelName: channelInfo?.name,\n metadata: {\n threadTs,\n channel: result.channel,\n },\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n /**\n * Fetch a single message by ID (timestamp).\n */\n async fetchMessage(\n threadId: string,\n messageId: string\n ): Promise<Message<unknown> | null> {\n const { channel, threadTs } = this.decodeThreadId(threadId);\n\n try {\n const result = await this.client.conversations.replies(\n this.withToken({\n channel,\n ts: threadTs,\n oldest: messageId,\n inclusive: true,\n limit: 1,\n })\n );\n\n const messages = (result.messages || []) as SlackEvent[];\n const target = messages.find((msg) => msg.ts === messageId);\n if (!target) {\n return null;\n }\n\n return this.parseSlackMessage(target, threadId);\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n encodeThreadId(platformData: SlackThreadId): string {\n return `slack:${platformData.channel}:${platformData.threadTs}`;\n }\n\n /**\n * Check if a thread is a direct message conversation.\n * Slack DM channel IDs start with 'D'.\n */\n isDM(threadId: string): boolean {\n const { channel } = this.decodeThreadId(threadId);\n return channel.startsWith(\"D\");\n }\n\n decodeThreadId(threadId: string): SlackThreadId {\n const parts = threadId.split(\":\");\n if (parts.length < 2 || parts.length > 3 || parts[0] !== \"slack\") {\n throw new ValidationError(\n \"slack\",\n `Invalid Slack thread ID: ${threadId}`\n );\n }\n return {\n channel: parts[1] as string,\n threadTs: parts.length === 3 ? (parts[2] as string) : \"\",\n };\n }\n\n parseMessage(raw: SlackEvent): Message<unknown> {\n const event = raw;\n const threadTs = event.thread_ts || event.ts || \"\";\n const threadId = this.encodeThreadId({\n channel: event.channel || \"\",\n threadTs,\n });\n // Use synchronous version without user lookup for interface compliance\n return this.parseSlackMessageSync(event, threadId);\n }\n\n /**\n * Synchronous message parsing without user lookup.\n * Used for parseMessage interface - falls back to user ID for username.\n */\n private parseSlackMessageSync(\n event: SlackEvent,\n threadId: string\n ): Message<unknown> {\n const isMe = this.isMessageFromSelf(event);\n\n const text = event.text || \"\";\n // Without async lookup, fall back to user ID for human users\n const userName = event.username || event.user || \"unknown\";\n const fullName = event.username || event.user || \"unknown\";\n\n return new Message({\n id: event.ts || \"\",\n threadId,\n text: this.formatConverter.extractPlainText(text),\n formatted: this.formatConverter.toAst(text),\n raw: event,\n author: {\n userId: event.user || event.bot_id || \"unknown\",\n userName,\n fullName,\n isBot: !!event.bot_id,\n isMe,\n },\n metadata: {\n dateSent: new Date(Number.parseFloat(event.ts || \"0\") * 1000),\n edited: !!event.edited,\n editedAt: event.edited\n ? new Date(Number.parseFloat(event.edited.ts) * 1000)\n : undefined,\n },\n attachments: (event.files || []).map((file) =>\n this.createAttachment(file)\n ),\n });\n }\n\n // =========================================================================\n // Channel-level methods\n // =========================================================================\n\n /**\n * Derive channel ID from a Slack thread ID.\n * Slack thread IDs are \"slack:CHANNEL:THREAD_TS\", channel ID is \"slack:CHANNEL\".\n */\n channelIdFromThreadId(threadId: string): string {\n const { channel } = this.decodeThreadId(threadId);\n return `slack:${channel}`;\n }\n\n /**\n * Fetch channel-level messages (conversations.history, not thread replies).\n */\n async fetchChannelMessages(\n channelId: string,\n options: FetchOptions = {}\n ): Promise<FetchResult<unknown>> {\n // Channel ID format: \"slack:CHANNEL\"\n const channel = channelId.split(\":\")[1];\n if (!channel) {\n throw new ValidationError(\n \"slack\",\n `Invalid Slack channel ID: ${channelId}`\n );\n }\n\n const direction = options.direction ?? \"backward\";\n const limit = options.limit || 100;\n\n try {\n if (direction === \"forward\") {\n return await this.fetchChannelMessagesForward(\n channel,\n limit,\n options.cursor\n );\n }\n return await this.fetchChannelMessagesBackward(\n channel,\n limit,\n options.cursor\n );\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n private async fetchChannelMessagesForward(\n channel: string,\n limit: number,\n cursor?: string\n ): Promise<FetchResult<unknown>> {\n this.logger.debug(\"Slack API: conversations.history (forward)\", {\n channel,\n limit,\n cursor,\n });\n\n const result = await this.client.conversations.history(\n this.withToken({\n channel,\n limit,\n oldest: cursor,\n inclusive: cursor ? false : undefined,\n })\n );\n\n const slackMessages = ((result.messages || []) as SlackEvent[]).reverse(); // Slack returns newest-first, we want oldest-first\n\n const messages = await Promise.all(\n slackMessages.map((msg) => {\n const threadTs = msg.thread_ts || msg.ts || \"\";\n const threadId = `slack:${channel}:${threadTs}`;\n return this.parseSlackMessage(msg, threadId, {\n skipSelfMention: false,\n });\n })\n );\n\n // For forward pagination, cursor points to newer messages\n let nextCursor: string | undefined;\n if (result.has_more && slackMessages.length > 0) {\n const newest = slackMessages.at(-1);\n if (newest?.ts) {\n nextCursor = newest.ts;\n }\n }\n\n return {\n messages,\n nextCursor,\n };\n }\n\n private async fetchChannelMessagesBackward(\n channel: string,\n limit: number,\n cursor?: string\n ): Promise<FetchResult<unknown>> {\n this.logger.debug(\"Slack API: conversations.history (backward)\", {\n channel,\n limit,\n cursor,\n });\n\n const result = await this.client.conversations.history(\n this.withToken({\n channel,\n limit,\n latest: cursor,\n inclusive: cursor ? false : undefined,\n })\n );\n\n const slackMessages = (result.messages || []) as SlackEvent[];\n // Slack returns newest-first for conversations.history; reverse for chronological\n const chronological = [...slackMessages].reverse();\n\n const messages = await Promise.all(\n chronological.map((msg) => {\n const threadTs = msg.thread_ts || msg.ts || \"\";\n const threadId = `slack:${channel}:${threadTs}`;\n return this.parseSlackMessage(msg, threadId, {\n skipSelfMention: false,\n });\n })\n );\n\n // For backward pagination, cursor points to older messages\n let nextCursor: string | undefined;\n if (result.has_more && chronological.length > 0) {\n const oldest = chronological[0];\n if (oldest?.ts) {\n nextCursor = oldest.ts;\n }\n }\n\n return {\n messages,\n nextCursor,\n };\n }\n\n /**\n * List threads in a Slack channel.\n * Fetches channel history and filters for messages with replies.\n */\n async listThreads(\n channelId: string,\n options: ListThreadsOptions = {}\n ): Promise<ListThreadsResult<unknown>> {\n const channel = channelId.split(\":\")[1];\n if (!channel) {\n throw new ValidationError(\n \"slack\",\n `Invalid Slack channel ID: ${channelId}`\n );\n }\n\n const limit = options.limit || 50;\n\n try {\n this.logger.debug(\"Slack API: conversations.history (listThreads)\", {\n channel,\n limit,\n cursor: options.cursor,\n });\n\n const result = await this.client.conversations.history(\n this.withToken({\n channel,\n limit: Math.min(limit * 3, 200), // Fetch extra since not all have threads\n cursor: options.cursor,\n })\n );\n\n const slackMessages = (result.messages || []) as SlackEvent[];\n\n // Filter messages that have replies (they are thread parents)\n const threadMessages = slackMessages.filter(\n (msg) => (msg.reply_count ?? 0) > 0\n );\n\n // Take up to `limit` threads\n const selected = threadMessages.slice(0, limit);\n\n const threads: ThreadSummary[] = await Promise.all(\n selected.map(async (msg) => {\n const threadTs = msg.ts || \"\";\n const threadId = `slack:${channel}:${threadTs}`;\n const rootMessage = await this.parseSlackMessage(msg, threadId, {\n skipSelfMention: false,\n });\n\n return {\n id: threadId,\n rootMessage,\n replyCount: msg.reply_count,\n lastReplyAt: msg.latest_reply\n ? new Date(Number.parseFloat(msg.latest_reply) * 1000)\n : undefined,\n };\n })\n );\n\n const nextCursor = (\n result as { response_metadata?: { next_cursor?: string } }\n ).response_metadata?.next_cursor;\n\n return {\n threads,\n nextCursor: nextCursor || undefined,\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n /**\n * Fetch Slack channel info/metadata.\n */\n async fetchChannelInfo(channelId: string): Promise<ChannelInfo> {\n const channel = channelId.split(\":\")[1];\n if (!channel) {\n throw new ValidationError(\n \"slack\",\n `Invalid Slack channel ID: ${channelId}`\n );\n }\n\n try {\n this.logger.debug(\"Slack API: conversations.info (channel)\", { channel });\n\n const result = await this.client.conversations.info(\n this.withToken({ channel })\n );\n\n const info = result.channel as {\n id?: string;\n name?: string;\n is_im?: boolean;\n is_mpim?: boolean;\n num_members?: number;\n purpose?: { value?: string };\n topic?: { value?: string };\n };\n\n return {\n id: channelId,\n name: info?.name ? `#${info.name}` : undefined,\n isDM: Boolean(info?.is_im || info?.is_mpim),\n memberCount: info?.num_members,\n metadata: {\n purpose: info?.purpose?.value,\n topic: info?.topic?.value,\n },\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n /**\n * Post a top-level message to a channel (not in a thread).\n */\n async postChannelMessage(\n channelId: string,\n message: AdapterPostableMessage\n ): Promise<RawMessage<unknown>> {\n const channel = channelId.split(\":\")[1];\n if (!channel) {\n throw new ValidationError(\n \"slack\",\n `Invalid Slack channel ID: ${channelId}`\n );\n }\n\n // Use the existing postMessage logic but with no threadTs\n // Build a synthetic thread ID with empty threadTs\n const syntheticThreadId = `slack:${channel}:`;\n return await this.postMessage(syntheticThreadId, message);\n }\n\n renderFormatted(content: FormattedContent): string {\n return this.formatConverter.fromAst(content);\n }\n\n /**\n * Check if a Slack event is from this bot.\n *\n * Slack messages can come from:\n * - User messages: have `user` field (U_xxx format)\n * - Bot messages: have `bot_id` field (B_xxx format)\n *\n * We check both because:\n * - _botUserId is the user ID (U_xxx) - matches event.user\n * - _botId is the bot ID (B_xxx) - matches event.bot_id\n */\n private isMessageFromSelf(event: SlackEvent): boolean {\n // Check request context first (multi-workspace)\n const ctx = this.requestContext.getStore();\n if (ctx?.botUserId && event.user === ctx.botUserId) {\n return true;\n }\n\n // Primary check: user ID match (for messages sent as the bot user)\n if (this._botUserId && event.user === this._botUserId) {\n return true;\n }\n\n // Secondary check: bot ID match (for bot_message subtypes)\n if (this._botId && event.bot_id === this._botId) {\n return true;\n }\n\n return false;\n }\n\n private handleSlackError(error: unknown): never {\n const slackError = error as { data?: { error?: string }; code?: string };\n\n if (\n slackError.code === \"slack_webapi_platform_error\" &&\n slackError.data?.error === \"ratelimited\"\n ) {\n throw new AdapterRateLimitError(\"slack\");\n }\n\n throw error;\n }\n\n /**\n * Encode response_url and userId into messageId for ephemeral messages.\n * This allows edit/delete operations to work via response_url.\n */\n private encodeEphemeralMessageId(\n messageTs: string,\n responseUrl: string,\n userId: string\n ): string {\n const data = JSON.stringify({ responseUrl, userId });\n return `ephemeral:${messageTs}:${btoa(data)}`;\n }\n\n /**\n * Decode ephemeral messageId to extract messageTs, responseUrl, and userId.\n * Returns null if the messageId is not an ephemeral encoding.\n */\n private decodeEphemeralMessageId(\n messageId: string\n ): { messageTs: string; responseUrl: string; userId: string } | null {\n if (!messageId.startsWith(\"ephemeral:\")) {\n return null;\n }\n const parts = messageId.split(\":\");\n if (parts.length < 3) {\n return null;\n }\n const messageTs = parts[1];\n const encodedData = parts.slice(2).join(\":\");\n try {\n const decoded = atob(encodedData);\n try {\n const data = JSON.parse(decoded);\n if (data.responseUrl && data.userId) {\n return {\n messageTs,\n responseUrl: data.responseUrl,\n userId: data.userId,\n };\n }\n } catch {\n return { messageTs, responseUrl: decoded, userId: \"\" };\n }\n return null;\n } catch {\n this.logger.warn(\"Failed to decode ephemeral messageId\", { messageId });\n return null;\n }\n }\n\n /**\n * Send a request to Slack's response_url to modify an ephemeral message.\n */\n private async sendToResponseUrl(\n responseUrl: string,\n action: \"replace\" | \"delete\",\n options?: { message?: AdapterPostableMessage; threadTs?: string }\n ): Promise<Record<string, unknown>> {\n let payload: Record<string, unknown>;\n\n if (action === \"delete\") {\n payload = { delete_original: true };\n } else {\n const message = options?.message;\n if (!message) {\n throw new ValidationError(\n \"slack\",\n \"Message required for replace action\"\n );\n }\n const card = extractCard(message);\n if (card) {\n payload = {\n replace_original: true,\n text: cardToFallbackText(card),\n blocks: cardToBlockKit(card),\n };\n } else {\n const tableResult = this.renderWithTableBlocks(message);\n if (tableResult) {\n payload = {\n replace_original: true,\n text: tableResult.text,\n blocks: tableResult.blocks,\n };\n } else {\n payload = {\n replace_original: true,\n text: convertEmojiPlaceholders(\n this.formatConverter.renderPostable(message),\n \"slack\"\n ),\n };\n }\n }\n if (options?.threadTs) {\n payload.thread_ts = options.threadTs;\n }\n }\n this.logger.debug(\"Slack response_url request\", {\n action,\n threadTs: options?.threadTs,\n });\n const response = await fetch(responseUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n this.logger.error(\"Slack response_url failed\", {\n action,\n status: response.status,\n body: errorText,\n });\n throw new NetworkError(\n \"slack\",\n `Failed to ${action} via response_url: ${errorText}`\n );\n }\n const responseText = await response.text();\n if (responseText) {\n try {\n return JSON.parse(responseText) as Record<string, unknown>;\n } catch {\n return { raw: responseText };\n }\n }\n return {};\n }\n}\n\nexport function createSlackAdapter(config?: SlackAdapterConfig): SlackAdapter {\n return new SlackAdapter(config ?? {});\n}\n\n// Re-export card converter for advanced use\nexport { cardToBlockKit, cardToFallbackText } from \"./cards\";\nexport type { EncryptedTokenData } from \"./crypto\";\n// Re-export crypto utilities for advanced use\nexport { decodeKey } from \"./crypto\";\n// Re-export format converter for advanced use\nexport {\n SlackFormatConverter,\n SlackFormatConverter as SlackMarkdownConverter,\n} from \"./markdown\";\n","/**\n * Slack Block Kit converter for cross-platform cards.\n *\n * Converts CardElement to Slack Block Kit blocks.\n * @see https://api.slack.com/block-kit\n */\n\nimport {\n createEmojiConverter,\n mapButtonStyle,\n cardToFallbackText as sharedCardToFallbackText,\n} from \"@chat-adapter/shared\";\nimport type {\n ActionsElement,\n ButtonElement,\n CardChild,\n CardElement,\n DividerElement,\n FieldsElement,\n ImageElement,\n LinkButtonElement,\n LinkElement,\n RadioSelectElement,\n SectionElement,\n SelectElement,\n TableElement,\n TextElement,\n} from \"chat\";\nimport { cardChildToFallbackText, tableElementToAscii } from \"chat\";\n\n/**\n * Convert emoji placeholders in text to Slack format.\n */\nconst convertEmoji = createEmojiConverter(\"slack\");\n\n// Slack Block Kit types (simplified)\nexport interface SlackBlock {\n block_id?: string;\n type: string;\n [key: string]: unknown;\n}\n\ninterface SlackTextObject {\n emoji?: boolean;\n text: string;\n type: \"plain_text\" | \"mrkdwn\";\n}\n\ninterface SlackButtonElement {\n action_id: string;\n style?: \"primary\" | \"danger\";\n text: SlackTextObject;\n type: \"button\";\n value?: string;\n}\n\ninterface SlackLinkButtonElement {\n action_id: string;\n style?: \"primary\" | \"danger\";\n text: SlackTextObject;\n type: \"button\";\n url: string;\n}\n\ninterface SlackOptionObject {\n description?: SlackTextObject;\n text: SlackTextObject;\n value: string;\n}\n\ninterface SlackSelectElement {\n action_id: string;\n initial_option?: SlackOptionObject;\n options: SlackOptionObject[];\n placeholder?: SlackTextObject;\n type: \"static_select\";\n}\n\ninterface SlackRadioSelectElement {\n action_id: string;\n initial_option?: SlackOptionObject;\n options: SlackOptionObject[];\n type: \"radio_buttons\";\n}\n\n/**\n * Convert a CardElement to Slack Block Kit blocks.\n */\nexport function cardToBlockKit(card: CardElement): SlackBlock[] {\n const blocks: SlackBlock[] = [];\n\n // Add header if title is present\n if (card.title) {\n blocks.push({\n type: \"header\",\n text: {\n type: \"plain_text\",\n text: convertEmoji(card.title),\n emoji: true,\n },\n });\n }\n\n // Add subtitle as context if present\n if (card.subtitle) {\n blocks.push({\n type: \"context\",\n elements: [\n {\n type: \"mrkdwn\",\n text: convertEmoji(card.subtitle),\n },\n ],\n });\n }\n\n // Add header image if present\n if (card.imageUrl) {\n blocks.push({\n type: \"image\",\n image_url: card.imageUrl,\n alt_text: card.title || \"Card image\",\n });\n }\n\n // Convert children — track whether native table block has been used\n // (Slack allows at most one table block per message)\n const state = { usedNativeTable: false };\n for (const child of card.children) {\n const childBlocks = convertChildToBlocks(child, state);\n blocks.push(...childBlocks);\n }\n\n return blocks;\n}\n\n/**\n * Convert a card child element to Slack blocks.\n */\nfunction convertChildToBlocks(\n child: CardChild,\n state: { usedNativeTable: boolean }\n): SlackBlock[] {\n switch (child.type) {\n case \"text\":\n return [convertTextToBlock(child)];\n case \"image\":\n return [convertImageToBlock(child)];\n case \"divider\":\n return [convertDividerToBlock(child)];\n case \"actions\":\n return [convertActionsToBlock(child)];\n case \"section\":\n return convertSectionToBlocks(child, state);\n case \"fields\":\n return [convertFieldsToBlock(child)];\n case \"link\":\n return [convertLinkToBlock(child)];\n case \"table\":\n return convertTableToBlocks(child, state);\n default: {\n const text = cardChildToFallbackText(child);\n if (text) {\n return [{ type: \"section\", text: { type: \"mrkdwn\", text } }];\n }\n return [];\n }\n }\n}\n\n/** Convert standard Markdown formatting to Slack mrkdwn */\nfunction markdownToMrkdwn(text: string): string {\n // **bold** → *bold*\n return text.replace(/\\*\\*(.+?)\\*\\*/g, \"*$1*\");\n}\n\nexport function convertTextToBlock(element: TextElement): SlackBlock {\n const text = markdownToMrkdwn(convertEmoji(element.content));\n let formattedText = text;\n\n // Apply style\n if (element.style === \"bold\") {\n formattedText = `*${text}*`;\n } else if (element.style === \"muted\") {\n // Slack doesn't have a muted style, use context block\n return {\n type: \"context\",\n elements: [{ type: \"mrkdwn\", text }],\n };\n }\n\n return {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: formattedText,\n },\n };\n}\n\nfunction convertLinkToBlock(element: LinkElement): SlackBlock {\n return {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `<${element.url}|${convertEmoji(element.label)}>`,\n },\n };\n}\n\nfunction convertImageToBlock(element: ImageElement): SlackBlock {\n return {\n type: \"image\",\n image_url: element.url,\n alt_text: element.alt || \"Image\",\n };\n}\n\nfunction convertDividerToBlock(_element: DividerElement): SlackBlock {\n return { type: \"divider\" };\n}\n\ntype SlackActionElement =\n | SlackButtonElement\n | SlackLinkButtonElement\n | SlackSelectElement\n | SlackRadioSelectElement;\n\nfunction convertActionsToBlock(element: ActionsElement): SlackBlock {\n const elements: SlackActionElement[] = element.children.map((child) => {\n if (child.type === \"link-button\") {\n return convertLinkButtonToElement(child);\n }\n if (child.type === \"select\") {\n return convertSelectToElement(child);\n }\n if (child.type === \"radio_select\") {\n return convertRadioSelectToElement(child);\n }\n return convertButtonToElement(child);\n });\n\n return {\n type: \"actions\",\n elements,\n };\n}\n\nfunction convertButtonToElement(button: ButtonElement): SlackButtonElement {\n const element: SlackButtonElement = {\n type: \"button\",\n text: {\n type: \"plain_text\",\n text: convertEmoji(button.label),\n emoji: true,\n },\n action_id: button.id,\n };\n\n if (button.value) {\n element.value = button.value;\n }\n\n const style = mapButtonStyle(button.style, \"slack\");\n if (style) {\n element.style = style as \"primary\" | \"danger\";\n }\n\n return element;\n}\n\nfunction convertLinkButtonToElement(\n button: LinkButtonElement\n): SlackLinkButtonElement {\n const element: SlackLinkButtonElement = {\n type: \"button\",\n text: {\n type: \"plain_text\",\n text: convertEmoji(button.label),\n emoji: true,\n },\n action_id: `link-${button.url.slice(0, 200)}`,\n url: button.url,\n };\n\n const style = mapButtonStyle(button.style, \"slack\");\n if (style) {\n element.style = style as \"primary\" | \"danger\";\n }\n\n return element;\n}\n\nfunction convertSelectToElement(select: SelectElement): SlackSelectElement {\n const options: SlackOptionObject[] = select.options.map((opt) => {\n const option: SlackOptionObject = {\n text: { type: \"plain_text\" as const, text: convertEmoji(opt.label) },\n value: opt.value,\n };\n if (opt.description) {\n option.description = {\n type: \"plain_text\",\n text: convertEmoji(opt.description),\n };\n }\n return option;\n });\n const element: SlackSelectElement = {\n type: \"static_select\",\n action_id: select.id,\n options,\n };\n if (select.placeholder) {\n element.placeholder = {\n type: \"plain_text\",\n text: convertEmoji(select.placeholder),\n };\n }\n if (select.initialOption) {\n const initialOpt = options.find((o) => o.value === select.initialOption);\n if (initialOpt) {\n element.initial_option = initialOpt;\n }\n }\n return element;\n}\n\nfunction convertRadioSelectToElement(\n radioSelect: RadioSelectElement\n): SlackRadioSelectElement {\n const limitedOptions = radioSelect.options.slice(0, 10);\n const options: SlackOptionObject[] = limitedOptions.map((opt) => {\n const option: SlackOptionObject = {\n text: { type: \"mrkdwn\" as const, text: convertEmoji(opt.label) },\n value: opt.value,\n };\n if (opt.description) {\n option.description = {\n type: \"mrkdwn\",\n text: convertEmoji(opt.description),\n };\n }\n return option;\n });\n\n const element: SlackRadioSelectElement = {\n type: \"radio_buttons\",\n action_id: radioSelect.id,\n options,\n };\n if (radioSelect.initialOption) {\n const initialOpt = options.find(\n (o) => o.value === radioSelect.initialOption\n );\n if (initialOpt) {\n element.initial_option = initialOpt;\n }\n }\n return element;\n}\n\n/**\n * Convert a table element to Slack Block Kit blocks.\n * Uses Block Kit Table block for tables within limits (100 rows, 20 columns),\n * falls back to code block for larger tables.\n */\n/**\n * Convert a table element to Slack Block Kit blocks.\n * Uses the native table block with first-row-as-headers schema.\n * Falls back to code block for tables exceeding Slack limits (100 rows, 20 columns)\n * or when a native table block has already been used in this message.\n * @see https://docs.slack.dev/reference/block-kit/blocks/table-block/\n */\nfunction convertTableToBlocks(\n element: TableElement,\n state: { usedNativeTable: boolean }\n): SlackBlock[] {\n const MAX_ROWS = 100;\n const MAX_COLS = 20;\n\n if (\n state.usedNativeTable ||\n element.rows.length > MAX_ROWS ||\n element.headers.length > MAX_COLS\n ) {\n // Fall back to ASCII table in a code block\n return [\n {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `\\`\\`\\`\\n${tableElementToAscii(element.headers, element.rows)}\\n\\`\\`\\``,\n },\n },\n ];\n }\n\n state.usedNativeTable = true;\n\n // First row is headers, subsequent rows are data\n const headerRow = element.headers.map((header) => ({\n type: \"raw_text\" as const,\n text: convertEmoji(header),\n }));\n\n const dataRows = element.rows.map((row) =>\n row.map((cell) => ({\n type: \"raw_text\" as const,\n text: convertEmoji(cell),\n }))\n );\n\n return [\n {\n type: \"table\",\n rows: [headerRow, ...dataRows],\n },\n ];\n}\n\nfunction convertSectionToBlocks(\n element: SectionElement,\n state: { usedNativeTable: boolean }\n): SlackBlock[] {\n // Flatten section children into blocks\n const blocks: SlackBlock[] = [];\n for (const child of element.children) {\n blocks.push(...convertChildToBlocks(child, state));\n }\n return blocks;\n}\n\nexport function convertFieldsToBlock(element: FieldsElement): SlackBlock {\n const fields: SlackTextObject[] = [];\n\n for (const field of element.children) {\n // Add label and value as separate field items\n fields.push({\n type: \"mrkdwn\",\n text: `*${markdownToMrkdwn(convertEmoji(field.label))}*\\n${markdownToMrkdwn(convertEmoji(field.value))}`,\n });\n }\n\n return {\n type: \"section\",\n fields,\n };\n}\n\n/**\n * Generate fallback text from a card element.\n * Used when blocks aren't supported or for notifications.\n */\nexport function cardToFallbackText(card: CardElement): string {\n return sharedCardToFallbackText(card, {\n boldFormat: \"*\",\n lineBreak: \"\\n\",\n platform: \"slack\",\n });\n}\n","import crypto from \"node:crypto\";\n\nconst ALGORITHM = \"aes-256-gcm\";\nconst IV_LENGTH = 12;\nconst AUTH_TAG_LENGTH = 16;\nconst HEX_KEY_PATTERN = /^[0-9a-fA-F]{64}$/;\n\nexport interface EncryptedTokenData {\n data: string;\n iv: string;\n tag: string;\n}\n\nexport function encryptToken(\n plaintext: string,\n key: Buffer\n): EncryptedTokenData {\n const iv = crypto.randomBytes(IV_LENGTH);\n const cipher = crypto.createCipheriv(ALGORITHM, key, iv, {\n authTagLength: AUTH_TAG_LENGTH,\n });\n const ciphertext = Buffer.concat([\n cipher.update(plaintext, \"utf8\"),\n cipher.final(),\n ]);\n const tag = cipher.getAuthTag();\n\n return {\n iv: iv.toString(\"base64\"),\n data: ciphertext.toString(\"base64\"),\n tag: tag.toString(\"base64\"),\n };\n}\n\nexport function decryptToken(\n encrypted: EncryptedTokenData,\n key: Buffer\n): string {\n const iv = Buffer.from(encrypted.iv, \"base64\");\n const ciphertext = Buffer.from(encrypted.data, \"base64\");\n const tag = Buffer.from(encrypted.tag, \"base64\");\n\n const decipher = crypto.createDecipheriv(ALGORITHM, key, iv, {\n authTagLength: AUTH_TAG_LENGTH,\n });\n decipher.setAuthTag(tag);\n\n return Buffer.concat([\n decipher.update(ciphertext),\n decipher.final(),\n ]).toString(\"utf8\");\n}\n\nexport function isEncryptedTokenData(\n value: unknown\n): value is EncryptedTokenData {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const obj = value as Record<string, unknown>;\n return (\n typeof obj.iv === \"string\" &&\n typeof obj.data === \"string\" &&\n typeof obj.tag === \"string\"\n );\n}\n\nexport function decodeKey(rawKey: string): Buffer {\n const trimmed = rawKey.trim();\n // Detect hex encoding: 64 hex chars = 32 bytes\n const isHex = HEX_KEY_PATTERN.test(trimmed);\n const key = Buffer.from(trimmed, isHex ? \"hex\" : \"base64\");\n if (key.length !== 32) {\n throw new Error(\n `Encryption key must decode to exactly 32 bytes (received ${key.length}). Use a 64-char hex string or 44-char base64 string.`\n );\n }\n return key;\n}\n","/**\n * Slack-specific format conversion using AST-based parsing.\n *\n * Slack uses \"mrkdwn\" format which is similar but not identical to markdown:\n * - Bold: *text* (not **text**)\n * - Italic: _text_ (same)\n * - Strikethrough: ~text~ (not ~~text~~)\n * - Links: <url|text> (not [text](url))\n * - User mentions: <@U123>\n * - Channel mentions: <#C123|name>\n */\n\nimport {\n type AdapterPostableMessage,\n BaseFormatConverter,\n type Content,\n getNodeChildren,\n isBlockquoteNode,\n isCodeNode,\n isDeleteNode,\n isEmphasisNode,\n isInlineCodeNode,\n isLinkNode,\n isListNode,\n isParagraphNode,\n isStrongNode,\n isTableNode,\n isTextNode,\n type MdastTable,\n parseMarkdown,\n type Root,\n tableToAscii,\n} from \"chat\";\nimport type { SlackBlock } from \"./cards\";\n\nexport class SlackFormatConverter extends BaseFormatConverter {\n /**\n * Convert @mentions to Slack format in plain text.\n * @name → <@name>\n */\n private convertMentionsToSlack(text: string): string {\n return text.replace(/(?<!<)@(\\w+)/g, \"<@$1>\");\n }\n\n /**\n * Override renderPostable to convert @mentions in plain strings.\n */\n override renderPostable(message: AdapterPostableMessage): string {\n if (typeof message === \"string\") {\n return this.convertMentionsToSlack(message);\n }\n if (\"raw\" in message) {\n return this.convertMentionsToSlack(message.raw);\n }\n if (\"markdown\" in message) {\n return this.fromAst(parseMarkdown(message.markdown));\n }\n if (\"ast\" in message) {\n return this.fromAst(message.ast);\n }\n return \"\";\n }\n\n /**\n * Render an AST to Slack mrkdwn format.\n */\n fromAst(ast: Root): string {\n return this.fromAstWithNodeConverter(ast, (node) =>\n this.nodeToMrkdwn(node)\n );\n }\n\n /**\n * Parse Slack mrkdwn into an AST.\n */\n toAst(mrkdwn: string): Root {\n // Convert Slack mrkdwn to standard markdown string, then parse\n let markdown = mrkdwn;\n\n // User mentions: <@U123|name> -> @name or <@U123> -> @U123\n markdown = markdown.replace(/<@([A-Z0-9_]+)\\|([^>]+)>/g, \"@$2\");\n markdown = markdown.replace(/<@([A-Z0-9_]+)>/g, \"@$1\");\n\n // Channel mentions: <#C123|name> -> #name\n markdown = markdown.replace(/<#[A-Z0-9_]+\\|([^>]+)>/g, \"#$1\");\n markdown = markdown.replace(/<#([A-Z0-9_]+)>/g, \"#$1\");\n\n // Links: <url|text> -> [text](url)\n markdown = markdown.replace(/<(https?:\\/\\/[^|>]+)\\|([^>]+)>/g, \"[$2]($1)\");\n\n // Bare links: <url> -> url\n markdown = markdown.replace(/<(https?:\\/\\/[^>]+)>/g, \"$1\");\n\n // Bold: *text* -> **text** (but be careful with emphasis)\n // This is tricky because Slack uses * for bold, not emphasis\n markdown = markdown.replace(/(?<![_*\\\\])\\*([^*\\n]+)\\*(?![_*])/g, \"**$1**\");\n\n // Strikethrough: ~text~ -> ~~text~~\n markdown = markdown.replace(/(?<!~)~([^~\\n]+)~(?!~)/g, \"~~$1~~\");\n\n return parseMarkdown(markdown);\n }\n\n /**\n * Convert AST to Slack blocks, using a native table block for the first table.\n * Returns null if the AST contains no tables (caller should use regular text).\n * Slack allows at most one table block per message; additional tables use ASCII.\n */\n toBlocksWithTable(ast: Root): SlackBlock[] | null {\n const hasTable = ast.children.some((node) => isTableNode(node as Content));\n if (!hasTable) {\n return null;\n }\n\n const blocks: SlackBlock[] = [];\n let usedNativeTable = false;\n let textBuffer: string[] = [];\n\n const flushText = () => {\n if (textBuffer.length > 0) {\n const text = textBuffer.join(\"\\n\\n\");\n if (text.trim()) {\n blocks.push({\n type: \"section\",\n text: { type: \"mrkdwn\", text },\n });\n }\n textBuffer = [];\n }\n };\n\n for (const child of ast.children) {\n const node = child as Content;\n if (isTableNode(node)) {\n flushText();\n if (usedNativeTable) {\n // Additional tables fall back to ASCII in a code block\n blocks.push({\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `\\`\\`\\`\\n${tableToAscii(node)}\\n\\`\\`\\``,\n },\n });\n } else {\n blocks.push(\n mdastTableToSlackBlock(node, this.nodeToMrkdwn.bind(this))\n );\n usedNativeTable = true;\n }\n } else {\n textBuffer.push(this.nodeToMrkdwn(node));\n }\n }\n\n flushText();\n return blocks;\n }\n\n private nodeToMrkdwn(node: Content): string {\n // Use type guards for type-safe node handling\n if (isParagraphNode(node)) {\n return getNodeChildren(node)\n .map((child) => this.nodeToMrkdwn(child))\n .join(\"\");\n }\n\n if (isTextNode(node)) {\n // Convert @mentions to Slack format <@mention>\n return node.value.replace(/(?<!<)@(\\w+)/g, \"<@$1>\");\n }\n\n if (isStrongNode(node)) {\n // Markdown **text** -> Slack *text*\n const content = getNodeChildren(node)\n .map((child) => this.nodeToMrkdwn(child))\n .join(\"\");\n return `*${content}*`;\n }\n\n if (isEmphasisNode(node)) {\n // Both use _text_\n const content = getNodeChildren(node)\n .map((child) => this.nodeToMrkdwn(child))\n .join(\"\");\n return `_${content}_`;\n }\n\n if (isDeleteNode(node)) {\n // Markdown ~~text~~ -> Slack ~text~\n const content = getNodeChildren(node)\n .map((child) => this.nodeToMrkdwn(child))\n .join(\"\");\n return `~${content}~`;\n }\n\n if (isInlineCodeNode(node)) {\n return `\\`${node.value}\\``;\n }\n\n if (isCodeNode(node)) {\n return `\\`\\`\\`${node.lang || \"\"}\\n${node.value}\\n\\`\\`\\``;\n }\n\n if (isLinkNode(node)) {\n const linkText = getNodeChildren(node)\n .map((child) => this.nodeToMrkdwn(child))\n .join(\"\");\n // Markdown [text](url) -> Slack <url|text>\n return `<${node.url}|${linkText}>`;\n }\n\n if (isBlockquoteNode(node)) {\n return getNodeChildren(node)\n .map((child) => `> ${this.nodeToMrkdwn(child)}`)\n .join(\"\\n\");\n }\n\n if (isListNode(node)) {\n return this.renderList(node, 0, (child) => this.nodeToMrkdwn(child), \"•\");\n }\n\n if (node.type === \"break\") {\n return \"\\n\";\n }\n\n if (node.type === \"thematicBreak\") {\n return \"---\";\n }\n\n if (isTableNode(node)) {\n return `\\`\\`\\`\\n${tableToAscii(node)}\\n\\`\\`\\``;\n }\n\n return this.defaultNodeToText(node, (child) => this.nodeToMrkdwn(child));\n }\n}\n\n/**\n * Convert an mdast Table node to a Slack table block.\n * Uses the table block schema: first row = headers, cells are raw_text,\n * column_settings carries alignment from mdast.\n * @see https://docs.slack.dev/reference/block-kit/blocks/table-block/\n */\nfunction mdastTableToSlackBlock(\n node: MdastTable,\n cellConverter: (node: Content) => string\n): SlackBlock {\n const rows: Array<Array<{ type: \"raw_text\"; text: string }>> = [];\n\n for (const row of node.children) {\n const cells = getNodeChildren(row).map((cell) => ({\n type: \"raw_text\" as const,\n text: getNodeChildren(cell).map(cellConverter).join(\"\"),\n }));\n rows.push(cells);\n }\n\n const block: SlackBlock = { type: \"table\", rows };\n\n if (node.align) {\n const columnSettings = node.align.map(\n (a: \"left\" | \"center\" | \"right\" | null) => ({\n align: a || \"left\",\n })\n );\n block.column_settings = columnSettings;\n }\n\n return block;\n}\n\n// Backwards compatibility alias\nexport { SlackFormatConverter as SlackMarkdownConverter };\n","/**\n * Slack modal (view) converter.\n * Converts ModalElement to Slack Block Kit view format.\n */\n\nimport type {\n ModalChild,\n ModalElement,\n RadioSelectElement,\n SelectElement,\n TextInputElement,\n} from \"chat\";\nimport {\n convertFieldsToBlock,\n convertTextToBlock,\n type SlackBlock,\n} from \"./cards\";\n\nexport interface SlackView {\n blocks: SlackBlock[];\n callback_id: string;\n close?: { type: \"plain_text\"; text: string };\n notify_on_close?: boolean;\n private_metadata?: string;\n submit?: { type: \"plain_text\"; text: string };\n title: { type: \"plain_text\"; text: string };\n type: \"modal\";\n}\n\nexport interface SlackModalResponse {\n errors?: Record<string, string>;\n response_action?: \"errors\" | \"update\" | \"push\" | \"clear\";\n view?: SlackView;\n}\n\n// ============================================================================\n// Private metadata encoding\n// ============================================================================\n\nexport interface ModalMetadata {\n contextId?: string;\n privateMetadata?: string;\n}\n\n/**\n * Encode contextId and user privateMetadata into a single string\n * for Slack's private_metadata field.\n */\nexport function encodeModalMetadata(meta: ModalMetadata): string | undefined {\n if (!(meta.contextId || meta.privateMetadata)) {\n return undefined;\n }\n return JSON.stringify({ c: meta.contextId, m: meta.privateMetadata });\n}\n\n/**\n * Decode Slack's private_metadata back into contextId and user privateMetadata.\n * Falls back to treating the raw string as a plain contextId for backward compat.\n */\nexport function decodeModalMetadata(raw?: string): ModalMetadata {\n if (!raw) {\n return {};\n }\n try {\n const parsed = JSON.parse(raw);\n if (\n typeof parsed === \"object\" &&\n parsed !== null &&\n (\"c\" in parsed || \"m\" in parsed)\n ) {\n return {\n contextId: parsed.c || undefined,\n privateMetadata: parsed.m || undefined,\n };\n }\n } catch {\n // Not JSON — treat as legacy plain contextId\n }\n return { contextId: raw };\n}\n\n// ============================================================================\n// Modal view conversion\n// ============================================================================\n\nexport function modalToSlackView(\n modal: ModalElement,\n contextId?: string\n): SlackView {\n return {\n type: \"modal\",\n callback_id: modal.callbackId,\n title: { type: \"plain_text\", text: modal.title.slice(0, 24) },\n submit: modal.submitLabel\n ? { type: \"plain_text\", text: modal.submitLabel }\n : { type: \"plain_text\", text: \"Submit\" },\n close: modal.closeLabel\n ? { type: \"plain_text\", text: modal.closeLabel }\n : { type: \"plain_text\", text: \"Cancel\" },\n notify_on_close: modal.notifyOnClose,\n private_metadata: contextId,\n blocks: modal.children.map(modalChildToBlock),\n };\n}\n\nfunction modalChildToBlock(child: ModalChild): SlackBlock {\n switch (child.type) {\n case \"text_input\":\n return textInputToBlock(child);\n case \"select\":\n return selectToBlock(child);\n case \"radio_select\":\n return radioSelectToBlock(child);\n case \"text\":\n return convertTextToBlock(child);\n case \"fields\":\n return convertFieldsToBlock(child);\n default:\n throw new Error(\n `Unknown modal child type: ${(child as { type: string }).type}`\n );\n }\n}\n\nfunction textInputToBlock(input: TextInputElement): SlackBlock {\n const element: Record<string, unknown> = {\n type: \"plain_text_input\",\n action_id: input.id,\n multiline: input.multiline ?? false,\n };\n\n if (input.placeholder) {\n element.placeholder = { type: \"plain_text\", text: input.placeholder };\n }\n if (input.initialValue) {\n element.initial_value = input.initialValue;\n }\n if (input.maxLength) {\n element.max_length = input.maxLength;\n }\n\n return {\n type: \"input\",\n block_id: input.id,\n optional: input.optional ?? false,\n label: { type: \"plain_text\", text: input.label },\n element,\n };\n}\n\nfunction selectToBlock(select: SelectElement): SlackBlock {\n const options = select.options.map((opt) => {\n const option: Record<string, unknown> = {\n text: { type: \"plain_text\" as const, text: opt.label },\n value: opt.value,\n };\n if (opt.description) {\n option.description = { type: \"plain_text\", text: opt.description };\n }\n return option;\n });\n\n const element: Record<string, unknown> = {\n type: \"static_select\",\n action_id: select.id,\n options,\n };\n\n if (select.placeholder) {\n element.placeholder = { type: \"plain_text\", text: select.placeholder };\n }\n\n if (select.initialOption) {\n const initialOpt = options.find(\n (o) => (o as { value: string }).value === select.initialOption\n );\n if (initialOpt) {\n element.initial_option = initialOpt;\n }\n }\n\n return {\n type: \"input\",\n block_id: select.id,\n optional: select.optional ?? false,\n label: { type: \"plain_text\", text: select.label },\n element,\n };\n}\n\nfunction radioSelectToBlock(radioSelect: RadioSelectElement): SlackBlock {\n const limitedOptions = radioSelect.options.slice(0, 10);\n const options = limitedOptions.map((opt) => {\n const option: Record<string, unknown> = {\n text: { type: \"mrkdwn\" as const, text: opt.label },\n value: opt.value,\n };\n if (opt.description) {\n option.description = { type: \"mrkdwn\", text: opt.description };\n }\n return option;\n });\n\n const element: Record<string, unknown> = {\n type: \"radio_buttons\",\n action_id: radioSelect.id,\n options,\n };\n if (radioSelect.initialOption) {\n const initialOpt = options.find(\n (o) => (o as { value: string }).value === radioSelect.initialOption\n );\n if (initialOpt) {\n element.initial_option = initialOpt;\n }\n }\n return {\n type: \"input\",\n block_id: radioSelect.id,\n optional: radioSelect.optional ?? false,\n label: { type: \"plain_text\", text: radioSelect.label },\n element,\n };\n}\n"],"mappings":"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","names":["parseMarkdown","parseMarkdown","card","result","scheduledMessageId","adapter"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/cards.ts","../src/crypto.ts","../src/markdown.ts","../src/modals.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { createHmac, timingSafeEqual } from \"node:crypto\";\nimport {\n AdapterRateLimitError,\n AuthenticationError,\n extractCard,\n extractFiles,\n NetworkError,\n toBuffer,\n ValidationError,\n} from \"@chat-adapter/shared\";\nimport { WebClient } from \"@slack/web-api\";\nimport type {\n ActionEvent,\n Adapter,\n AdapterPostableMessage,\n Attachment,\n ChannelInfo,\n ChatInstance,\n EmojiValue,\n EphemeralMessage,\n FetchOptions,\n FetchResult,\n FileUpload,\n FormattedContent,\n LinkPreview,\n ListThreadsOptions,\n ListThreadsResult,\n Logger,\n ModalElement,\n ModalResponse,\n RawMessage,\n ReactionEvent,\n Root,\n ScheduledMessage,\n StreamChunk,\n StreamOptions,\n ThreadInfo,\n ThreadSummary,\n WebhookOptions,\n} from \"chat\";\n\nimport {\n ConsoleLogger,\n convertEmojiPlaceholders,\n defaultEmojiResolver,\n isJSX,\n Message,\n parseMarkdown,\n StreamingMarkdownRenderer,\n toModalElement,\n} from \"chat\";\nimport { cardToBlockKit, cardToFallbackText, type SlackBlock } from \"./cards\";\nimport type { EncryptedTokenData } from \"./crypto\";\nimport {\n decodeKey,\n decryptToken,\n encryptToken,\n isEncryptedTokenData,\n} from \"./crypto\";\nimport { SlackFormatConverter } from \"./markdown\";\nimport {\n decodeModalMetadata,\n encodeModalMetadata,\n modalToSlackView,\n type SlackModalResponse,\n} from \"./modals\";\n\nconst SLACK_USER_ID_PATTERN = /^[A-Z0-9_]+$/;\nconst SLACK_USER_ID_EXACT_PATTERN = /^U[A-Z0-9]+$/;\n\n/** Find the next `<@` or `<#` mention in text. */\nfunction findNextMention(text: string): number {\n const atIdx = text.indexOf(\"<@\");\n const hashIdx = text.indexOf(\"<#\");\n if (atIdx === -1) {\n return hashIdx;\n }\n if (hashIdx === -1) {\n return atIdx;\n }\n return Math.min(atIdx, hashIdx);\n}\n\n/**\n * Pattern to match Slack message URLs.\n * Format: https://{workspace}.slack.com/archives/{channelId}/p{timestamp}\n * The timestamp in the URL has no dot (e.g., p1234567890123456).\n * Supports optional query parameters (e.g., ?thread_ts=...&cid=...).\n */\nconst SLACK_MESSAGE_URL_PATTERN =\n /^https?:\\/\\/[^/]+\\.slack\\.com\\/archives\\/([A-Z0-9]+)\\/p(\\d+)(?:\\?.*)?$/;\n\nexport interface SlackAdapterConfig {\n /** Bot token (xoxb-...). Required for single-workspace mode. Omit for multi-workspace. */\n botToken?: string;\n /** Bot user ID (will be fetched if not provided) */\n botUserId?: string;\n /** Slack app client ID (required for OAuth / multi-workspace) */\n clientId?: string;\n /** Slack app client secret (required for OAuth / multi-workspace) */\n clientSecret?: string;\n /**\n * Base64-encoded 32-byte AES-256-GCM encryption key.\n * If provided, bot tokens stored via setInstallation() will be encrypted at rest.\n */\n encryptionKey?: string;\n /**\n * Prefix for the state key used to store workspace installations.\n * Defaults to `slack:installation`. The full key will be `{prefix}:{teamId}`.\n */\n installationKeyPrefix?: string;\n /** Logger instance for error reporting. Defaults to ConsoleLogger. */\n logger?: Logger;\n /** Signing secret for webhook verification. Defaults to SLACK_SIGNING_SECRET env var. */\n signingSecret?: string;\n /** Override bot username (optional) */\n userName?: string;\n}\n\n/** Data stored per Slack workspace installation */\nexport interface SlackInstallation {\n botToken: string;\n botUserId?: string;\n teamName?: string;\n}\n\n/** Slack-specific thread ID data */\nexport interface SlackThreadId {\n channel: string;\n threadTs: string;\n}\n\n/** Slack event payload (raw message format) */\nexport interface SlackEvent {\n /** Rich text blocks containing structured elements (links, mentions, etc.) */\n blocks?: Array<{\n type: string;\n elements?: Array<{\n type: string;\n elements?: Array<{\n type: string;\n url?: string;\n text?: string;\n }>;\n }>;\n }>;\n bot_id?: string;\n channel?: string;\n /** Channel type: \"channel\", \"group\", \"mpim\", or \"im\" (DM) */\n channel_type?: string;\n edited?: { ts: string };\n files?: Array<{\n id?: string;\n mimetype?: string;\n url_private?: string;\n name?: string;\n size?: number;\n original_w?: number;\n original_h?: number;\n }>;\n /** Timestamp of the latest reply (present on thread parent messages) */\n latest_reply?: string;\n /** Number of replies in the thread (present on thread parent messages) */\n reply_count?: number;\n subtype?: string;\n team?: string;\n team_id?: string;\n text?: string;\n thread_ts?: string;\n ts?: string;\n type: string;\n user?: string;\n username?: string;\n}\n\n/** Slack reaction event payload */\nexport interface SlackReactionEvent {\n event_ts: string;\n item: {\n type: string;\n channel: string;\n ts: string;\n };\n item_user?: string;\n reaction: string;\n type: \"reaction_added\" | \"reaction_removed\";\n user: string;\n}\n\n/** Slack assistant_thread_started event payload */\ninterface SlackAssistantThreadStartedEvent {\n assistant_thread: {\n user_id: string;\n channel_id: string;\n thread_ts: string;\n context: {\n channel_id?: string;\n team_id?: string;\n enterprise_id?: string;\n thread_entry_point?: string;\n force_search?: boolean;\n };\n };\n event_ts: string;\n type: \"assistant_thread_started\";\n}\n\n/** Slack assistant_thread_context_changed event payload */\ninterface SlackAssistantContextChangedEvent {\n assistant_thread: {\n user_id: string;\n channel_id: string;\n thread_ts: string;\n context: {\n channel_id?: string;\n team_id?: string;\n enterprise_id?: string;\n thread_entry_point?: string;\n force_search?: boolean;\n };\n };\n event_ts: string;\n type: \"assistant_thread_context_changed\";\n}\n\n/** Slack app_home_opened event payload */\ninterface SlackAppHomeOpenedEvent {\n channel: string;\n event_ts: string;\n tab: string;\n type: \"app_home_opened\";\n user: string;\n}\n\n/** Slack member_joined_channel event payload */\ninterface SlackMemberJoinedChannelEvent {\n channel: string;\n channel_type?: string;\n event_ts: string;\n inviter?: string;\n team?: string;\n type: \"member_joined_channel\";\n user: string;\n}\n\n/** Slack user_change event payload */\ninterface SlackUserChangeEvent {\n event_ts: string;\n type: \"user_change\";\n user: {\n id: string;\n name?: string;\n real_name?: string;\n profile?: { display_name?: string; real_name?: string };\n };\n}\n\n/** Slack webhook payload envelope */\ninterface SlackWebhookPayload {\n challenge?: string;\n event?:\n | SlackEvent\n | SlackReactionEvent\n | SlackAssistantThreadStartedEvent\n | SlackAssistantContextChangedEvent\n | SlackAppHomeOpenedEvent\n | SlackMemberJoinedChannelEvent\n | SlackUserChangeEvent;\n event_id?: string;\n event_time?: number;\n team_id?: string;\n type: string;\n}\n\n/** Slack interactive payload (block_actions) for button clicks */\ninterface SlackBlockActionsPayload {\n actions: Array<{\n type: string;\n action_id: string;\n block_id?: string;\n value?: string;\n action_ts?: string;\n selected_option?: { value: string };\n }>;\n channel: {\n id: string;\n name: string;\n };\n container: {\n type: string;\n message_ts: string;\n channel_id: string;\n is_ephemeral?: boolean;\n thread_ts?: string;\n };\n message: {\n ts: string;\n thread_ts?: string;\n };\n response_url?: string;\n trigger_id: string;\n type: \"block_actions\";\n user: {\n id: string;\n username: string;\n name?: string;\n };\n}\n\ninterface SlackViewSubmissionPayload {\n trigger_id: string;\n type: \"view_submission\";\n user: {\n id: string;\n username: string;\n name?: string;\n };\n view: {\n id: string;\n callback_id: string;\n private_metadata?: string;\n state: {\n values: Record<\n string,\n Record<string, { value?: string; selected_option?: { value: string } }>\n >;\n };\n };\n}\n\ninterface SlackViewClosedPayload {\n type: \"view_closed\";\n user: {\n id: string;\n username: string;\n name?: string;\n };\n view: {\n id: string;\n callback_id: string;\n private_metadata?: string;\n };\n}\n\ntype SlackInteractivePayload =\n | SlackBlockActionsPayload\n | SlackViewSubmissionPayload\n | SlackViewClosedPayload;\n\n/** Cached user info */\ninterface CachedUser {\n displayName: string;\n realName: string;\n}\n\n/** Cached channel info */\ninterface CachedChannel {\n name: string;\n}\n\nexport class SlackAdapter implements Adapter<SlackThreadId, unknown> {\n readonly name = \"slack\";\n readonly userName: string;\n\n private readonly client: WebClient;\n private readonly signingSecret: string;\n private readonly defaultBotToken: string | undefined;\n private chat: ChatInstance | null = null;\n private readonly logger: Logger;\n private _botUserId: string | null = null;\n private _botId: string | null = null; // Bot app ID (B_xxx) - different from user ID\n private readonly formatConverter = new SlackFormatConverter();\n private static USER_CACHE_TTL_MS = 8 * 24 * 60 * 60 * 1000; // 8 days\n private static CHANNEL_CACHE_TTL_MS = 8 * 24 * 60 * 60 * 1000; // 8 days\n private static REVERSE_INDEX_TTL_MS = 8 * 24 * 60 * 60 * 1000; // 8 days\n\n // Multi-workspace support\n private readonly clientId: string | undefined;\n private readonly clientSecret: string | undefined;\n private readonly encryptionKey: Buffer | undefined;\n private readonly installationKeyPrefix: string;\n private readonly requestContext = new AsyncLocalStorage<{\n token: string;\n botUserId?: string;\n }>();\n\n /** Bot user ID (e.g., U_BOT_123) used for mention detection */\n get botUserId(): string | undefined {\n const ctx = this.requestContext.getStore();\n if (ctx?.botUserId) {\n return ctx.botUserId;\n }\n return this._botUserId || undefined;\n }\n\n constructor(config: SlackAdapterConfig = {}) {\n const signingSecret =\n config.signingSecret ?? process.env.SLACK_SIGNING_SECRET;\n if (!signingSecret) {\n throw new ValidationError(\n \"slack\",\n \"signingSecret is required. Set SLACK_SIGNING_SECRET or provide it in config.\"\n );\n }\n\n // Auth fields (botToken, clientId, clientSecret) are modal: botToken's\n // presence selects single-workspace mode, its absence selects multi-workspace\n // (per-team token lookup via installations). Only fall back to env vars\n // in zero-config mode (no config fields provided at all).\n const zeroConfig = !(\n config.signingSecret ||\n config.botToken ||\n config.clientId ||\n config.clientSecret\n );\n\n const botToken =\n config.botToken ?? (zeroConfig ? process.env.SLACK_BOT_TOKEN : undefined);\n\n this.client = new WebClient(botToken);\n this.signingSecret = signingSecret;\n this.defaultBotToken = botToken;\n this.logger = config.logger ?? new ConsoleLogger(\"info\").child(\"slack\");\n this.userName = config.userName || \"bot\";\n this._botUserId = config.botUserId || null;\n\n this.clientId =\n config.clientId ?? (zeroConfig ? process.env.SLACK_CLIENT_ID : undefined);\n this.clientSecret =\n config.clientSecret ??\n (zeroConfig ? process.env.SLACK_CLIENT_SECRET : undefined);\n this.installationKeyPrefix =\n config.installationKeyPrefix ?? \"slack:installation\";\n\n const encryptionKey =\n config.encryptionKey ?? process.env.SLACK_ENCRYPTION_KEY;\n if (encryptionKey) {\n this.encryptionKey = decodeKey(encryptionKey);\n }\n }\n\n /**\n * Get the current bot token for API calls.\n * Checks request context (multi-workspace) → default token (single-workspace) → throws.\n */\n private getToken(): string {\n const ctx = this.requestContext.getStore();\n if (ctx?.token) {\n return ctx.token;\n }\n if (this.defaultBotToken) {\n return this.defaultBotToken;\n }\n throw new AuthenticationError(\n \"slack\",\n \"No bot token available. In multi-workspace mode, ensure the webhook is being processed.\"\n );\n }\n\n /**\n * Add the current token to API call options.\n * Workaround for Slack WebClient types not including `token` in per-method args.\n */\n // biome-ignore lint/suspicious/noExplicitAny: Slack types don't include token in method args\n private withToken<T extends Record<string, any>>(\n options: T\n ): T & { token: string } {\n return { ...options, token: this.getToken() };\n }\n\n async initialize(chat: ChatInstance): Promise<void> {\n this.chat = chat;\n\n // Only fetch bot user ID in single-workspace mode (when default token is available)\n if (this.defaultBotToken && !this._botUserId) {\n try {\n const authResult = await this.client.auth.test(this.withToken({}));\n this._botUserId = authResult.user_id as string;\n this._botId = (authResult.bot_id as string) || null;\n if (authResult.user) {\n (this as { userName: string }).userName = authResult.user as string;\n }\n this.logger.info(\"Slack auth completed\", {\n botUserId: this._botUserId,\n botId: this._botId,\n });\n } catch (error) {\n this.logger.warn(\"Could not fetch bot user ID\", { error });\n }\n }\n\n if (!this.defaultBotToken) {\n this.logger.info(\"Slack adapter initialized in multi-workspace mode\");\n }\n }\n\n // ===========================================================================\n // Multi-workspace installation management\n // ===========================================================================\n\n private installationKey(teamId: string): string {\n return `${this.installationKeyPrefix}:${teamId}`;\n }\n\n /**\n * Save a Slack workspace installation.\n * Call this from your OAuth callback route after a successful installation.\n */\n async setInstallation(\n teamId: string,\n installation: SlackInstallation\n ): Promise<void> {\n if (!this.chat) {\n throw new ValidationError(\n \"slack\",\n \"Adapter not initialized. Ensure chat.initialize() has been called first.\"\n );\n }\n\n const state = this.chat.getState();\n const key = this.installationKey(teamId);\n\n const dataToStore = this.encryptionKey\n ? {\n ...installation,\n botToken: encryptToken(installation.botToken, this.encryptionKey),\n }\n : installation;\n\n await state.set(key, dataToStore);\n this.logger.info(\"Slack installation saved\", {\n teamId,\n teamName: installation.teamName,\n });\n }\n\n /**\n * Retrieve a Slack workspace installation.\n */\n async getInstallation(teamId: string): Promise<SlackInstallation | null> {\n if (!this.chat) {\n throw new ValidationError(\n \"slack\",\n \"Adapter not initialized. Ensure chat.initialize() has been called first.\"\n );\n }\n\n const state = this.chat.getState();\n const key = this.installationKey(teamId);\n const stored = await state.get<\n | SlackInstallation\n | (Omit<SlackInstallation, \"botToken\"> & {\n botToken: EncryptedTokenData;\n })\n >(key);\n\n if (!stored) {\n return null;\n }\n\n if (this.encryptionKey && isEncryptedTokenData(stored.botToken)) {\n return {\n ...stored,\n botToken: decryptToken(\n stored.botToken as EncryptedTokenData,\n this.encryptionKey\n ),\n };\n }\n\n return stored as SlackInstallation;\n }\n\n /**\n * Handle the Slack OAuth V2 callback.\n * Accepts the incoming request, extracts the authorization code,\n * exchanges it for tokens, and saves the installation.\n */\n async handleOAuthCallback(\n request: Request\n ): Promise<{ teamId: string; installation: SlackInstallation }> {\n if (!(this.clientId && this.clientSecret)) {\n throw new ValidationError(\n \"slack\",\n \"clientId and clientSecret are required for OAuth. Pass them in createSlackAdapter().\"\n );\n }\n\n const url = new URL(request.url);\n const code = url.searchParams.get(\"code\");\n if (!code) {\n throw new ValidationError(\n \"slack\",\n \"Missing 'code' query parameter in OAuth callback request.\"\n );\n }\n\n const redirectUri = url.searchParams.get(\"redirect_uri\") ?? undefined;\n\n const result = await this.client.oauth.v2.access({\n client_id: this.clientId,\n client_secret: this.clientSecret,\n code,\n redirect_uri: redirectUri,\n });\n\n if (!(result.ok && result.access_token && result.team?.id)) {\n throw new AuthenticationError(\n \"slack\",\n `Slack OAuth failed: ${result.error || \"missing access_token or team.id\"}`\n );\n }\n\n const teamId = result.team.id;\n const installation: SlackInstallation = {\n botToken: result.access_token,\n botUserId: result.bot_user_id,\n teamName: result.team.name,\n };\n\n await this.setInstallation(teamId, installation);\n\n return { teamId, installation };\n }\n\n /**\n * Remove a Slack workspace installation.\n */\n async deleteInstallation(teamId: string): Promise<void> {\n if (!this.chat) {\n throw new ValidationError(\n \"slack\",\n \"Adapter not initialized. Ensure chat.initialize() has been called first.\"\n );\n }\n\n const state = this.chat.getState();\n await state.delete(this.installationKey(teamId));\n this.logger.info(\"Slack installation deleted\", { teamId });\n }\n\n /**\n * Run a function with a specific bot token in context.\n * Use this for operations outside webhook handling (cron jobs, workflows).\n */\n withBotToken<T>(token: string, fn: () => T): T {\n return this.requestContext.run({ token }, fn);\n }\n\n // ===========================================================================\n // Private helpers\n // ===========================================================================\n\n /**\n * Resolve the bot token for a team from the state adapter.\n */\n private async resolveTokenForTeam(\n teamId: string\n ): Promise<{ token: string; botUserId?: string } | null> {\n try {\n const installation = await this.getInstallation(teamId);\n if (installation) {\n return {\n token: installation.botToken,\n botUserId: installation.botUserId,\n };\n }\n this.logger.warn(\"No installation found for team\", { teamId });\n return null;\n } catch (error) {\n this.logger.error(\"Failed to resolve token for team\", {\n teamId,\n error,\n });\n return null;\n }\n }\n\n /**\n * Extract team_id from an interactive payload (form-urlencoded).\n */\n private extractTeamIdFromInteractive(body: string): string | null {\n try {\n const params = new URLSearchParams(body);\n const payloadStr = params.get(\"payload\");\n if (!payloadStr) {\n return null;\n }\n const payload = JSON.parse(payloadStr);\n return payload.team?.id || payload.team_id || null;\n } catch {\n return null;\n }\n }\n\n /**\n * Look up user info from Slack API with caching via state adapter.\n * Returns display name and real name, or falls back to user ID.\n */\n private async lookupUser(\n userId: string\n ): Promise<{ displayName: string; realName: string }> {\n const cacheKey = `slack:user:${userId}`;\n\n // Check cache first (via state adapter for serverless compatibility)\n if (this.chat) {\n const cached = await this.chat.getState().get<CachedUser>(cacheKey);\n if (cached) {\n return { displayName: cached.displayName, realName: cached.realName };\n }\n }\n\n try {\n const result = await this.client.users.info(\n this.withToken({ user: userId })\n );\n const user = result.user as {\n name?: string;\n real_name?: string;\n profile?: { display_name?: string; real_name?: string };\n };\n\n // Slack user naming: profile.display_name > profile.real_name > real_name > name > userId\n const displayName =\n user?.profile?.display_name ||\n user?.profile?.real_name ||\n user?.real_name ||\n user?.name ||\n userId;\n const realName =\n user?.real_name || user?.profile?.real_name || displayName;\n\n // Cache the result via state adapter\n if (this.chat) {\n await this.chat\n .getState()\n .set<CachedUser>(\n cacheKey,\n { displayName, realName },\n SlackAdapter.USER_CACHE_TTL_MS\n );\n\n // Build reverse index: display name → user IDs (skip if already present)\n const normalizedName = displayName.toLowerCase();\n const reverseKey = `slack:user-by-name:${normalizedName}`;\n const existing = await this.chat.getState().getList<string>(reverseKey);\n if (!existing.includes(userId)) {\n await this.chat.getState().appendToList(reverseKey, userId, {\n maxLength: 50,\n ttlMs: SlackAdapter.REVERSE_INDEX_TTL_MS,\n });\n }\n }\n\n this.logger.debug(\"Fetched user info\", {\n userId,\n displayName,\n realName,\n });\n return { displayName, realName };\n } catch (error) {\n this.logger.warn(\"Could not fetch user info\", { userId, error });\n // Fall back to user ID\n return { displayName: userId, realName: userId };\n }\n }\n\n /**\n * Look up channel name from Slack API with caching via state adapter.\n * Returns channel name, or falls back to channel ID.\n */\n private async lookupChannel(channelId: string): Promise<string> {\n const cacheKey = `slack:channel:${channelId}`;\n\n // Check cache first (via state adapter for serverless compatibility)\n if (this.chat) {\n const cached = await this.chat.getState().get<CachedChannel>(cacheKey);\n if (cached) {\n return cached.name;\n }\n }\n\n try {\n const result = await this.client.conversations.info(\n this.withToken({ channel: channelId })\n );\n const name =\n (result.channel as { name?: string } | undefined)?.name || channelId;\n\n // Cache the result via state adapter\n if (this.chat) {\n await this.chat\n .getState()\n .set<CachedChannel>(\n cacheKey,\n { name },\n SlackAdapter.CHANNEL_CACHE_TTL_MS\n );\n }\n\n this.logger.debug(\"Fetched channel info\", { channelId, name });\n return name;\n } catch (error) {\n this.logger.warn(\"Could not fetch channel info\", { channelId, error });\n // Fall back to channel ID\n return channelId;\n }\n }\n\n async handleWebhook(\n request: Request,\n options?: WebhookOptions\n ): Promise<Response> {\n const body = await request.text();\n this.logger.debug(\"Slack webhook raw body\", { body });\n\n // Verify request signature\n const timestamp = request.headers.get(\"x-slack-request-timestamp\");\n const signature = request.headers.get(\"x-slack-signature\");\n\n if (!this.verifySignature(body, timestamp, signature)) {\n return new Response(\"Invalid signature\", { status: 401 });\n }\n\n // Check if this is a form-urlencoded payload\n const contentType = request.headers.get(\"content-type\") || \"\";\n if (contentType.includes(\"application/x-www-form-urlencoded\")) {\n const params = new URLSearchParams(body);\n if (params.has(\"command\") && !params.has(\"payload\")) {\n const teamId = params.get(\"team_id\");\n if (!this.defaultBotToken && teamId) {\n const ctx = await this.resolveTokenForTeam(teamId);\n if (ctx) {\n return this.requestContext.run(ctx, () =>\n this.handleSlashCommand(params, options)\n );\n }\n this.logger.warn(\"Could not resolve token for slash command\");\n }\n return this.handleSlashCommand(params, options);\n }\n // In multi-workspace mode, resolve token before processing\n if (!this.defaultBotToken) {\n const teamId = this.extractTeamIdFromInteractive(body);\n if (teamId) {\n const ctx = await this.resolveTokenForTeam(teamId);\n if (ctx) {\n return this.requestContext.run(ctx, () =>\n this.handleInteractivePayload(body, options)\n );\n }\n }\n this.logger.warn(\"Could not resolve token for interactive payload\");\n }\n return this.handleInteractivePayload(body, options);\n }\n\n // Parse the JSON payload\n let payload: SlackWebhookPayload;\n try {\n payload = JSON.parse(body);\n } catch {\n return new Response(\"Invalid JSON\", { status: 400 });\n }\n\n // Handle URL verification challenge (signature already verified above)\n if (payload.type === \"url_verification\" && payload.challenge) {\n return Response.json({ challenge: payload.challenge });\n }\n\n // In multi-workspace mode, resolve token from team_id before processing events\n if (!this.defaultBotToken && payload.type === \"event_callback\") {\n const teamId = payload.team_id;\n if (teamId) {\n const ctx = await this.resolveTokenForTeam(teamId);\n if (ctx) {\n return this.requestContext.run(ctx, () => {\n this.processEventPayload(payload, options);\n return new Response(\"ok\", { status: 200 });\n });\n }\n this.logger.warn(\"Could not resolve token for team\", { teamId });\n return new Response(\"ok\", { status: 200 });\n }\n }\n\n // Single-workspace mode or fallback\n this.processEventPayload(payload, options);\n return new Response(\"ok\", { status: 200 });\n }\n\n /** Extract and dispatch events from a validated payload */\n private processEventPayload(\n payload: SlackWebhookPayload,\n options?: WebhookOptions\n ): void {\n if (payload.type === \"event_callback\" && payload.event) {\n const event = payload.event;\n\n if (event.type === \"message\" || event.type === \"app_mention\") {\n const slackEvent = event as SlackEvent;\n if (!(slackEvent.team || slackEvent.team_id) && payload.team_id) {\n slackEvent.team_id = payload.team_id;\n }\n this.handleMessageEvent(slackEvent, options);\n } else if (\n event.type === \"reaction_added\" ||\n event.type === \"reaction_removed\"\n ) {\n this.handleReactionEvent(event as SlackReactionEvent, options);\n } else if (event.type === \"assistant_thread_started\") {\n this.handleAssistantThreadStarted(\n event as SlackAssistantThreadStartedEvent,\n options\n );\n } else if (event.type === \"assistant_thread_context_changed\") {\n this.handleAssistantContextChanged(\n event as SlackAssistantContextChangedEvent,\n options\n );\n } else if (\n event.type === \"app_home_opened\" &&\n (event as SlackAppHomeOpenedEvent).tab === \"home\"\n ) {\n this.handleAppHomeOpened(event as SlackAppHomeOpenedEvent, options);\n } else if (event.type === \"member_joined_channel\") {\n this.handleMemberJoinedChannel(\n event as SlackMemberJoinedChannelEvent,\n options\n );\n } else if (event.type === \"user_change\") {\n this.handleUserChange(event as SlackUserChangeEvent);\n }\n }\n }\n\n /**\n * Handle Slack interactive payloads (button clicks, view submissions, etc.).\n * These are sent as form-urlencoded with a `payload` JSON field.\n */\n private handleInteractivePayload(\n body: string,\n options?: WebhookOptions\n ): Response | Promise<Response> {\n const params = new URLSearchParams(body);\n const payloadStr = params.get(\"payload\");\n\n if (!payloadStr) {\n return new Response(\"Missing payload\", { status: 400 });\n }\n\n let payload: SlackInteractivePayload;\n try {\n payload = JSON.parse(payloadStr);\n } catch {\n return new Response(\"Invalid payload JSON\", { status: 400 });\n }\n\n switch (payload.type) {\n case \"block_actions\":\n this.handleBlockActions(payload, options);\n return new Response(\"\", { status: 200 });\n\n case \"view_submission\":\n return this.handleViewSubmission(payload, options);\n\n case \"view_closed\":\n this.handleViewClosed(payload, options);\n return new Response(\"\", { status: 200 });\n\n default:\n return new Response(\"\", { status: 200 });\n }\n }\n\n /**\n * Handle Slack slash command payloads.\n * Slash commands are sent as form-urlencoded with command, text, user_id, channel_id, etc.\n */\n private async handleSlashCommand(\n params: URLSearchParams,\n options?: WebhookOptions\n ): Promise<Response> {\n if (!this.chat) {\n this.logger.warn(\"Chat instance not initialized, ignoring slash command\");\n return new Response(\"\", { status: 200 });\n }\n\n const command = params.get(\"command\") || \"\";\n const text = params.get(\"text\") || \"\";\n const userId = params.get(\"user_id\") || \"\";\n const channelId = params.get(\"channel_id\") || \"\";\n const triggerId = params.get(\"trigger_id\") || undefined;\n\n this.logger.debug(\"Processing Slack slash command\", {\n command,\n text,\n userId,\n channelId,\n triggerId,\n });\n const userInfo = await this.lookupUser(userId);\n const event = {\n command,\n text,\n user: {\n userId,\n userName: userInfo.displayName,\n fullName: userInfo.realName,\n isBot: false,\n isMe: false,\n },\n adapter: this as Adapter,\n raw: Object.fromEntries(params),\n triggerId,\n channelId: channelId ? `slack:${channelId}` : \"\",\n };\n this.chat.processSlashCommand(event, options);\n return new Response(\"\", { status: 200 });\n }\n\n /**\n * Handle block_actions payload (button clicks in Block Kit).\n */\n private handleBlockActions(\n payload: SlackBlockActionsPayload,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\"Chat instance not initialized, ignoring action\");\n return;\n }\n\n const channel = payload.channel?.id || payload.container?.channel_id;\n const messageTs = payload.message?.ts || payload.container?.message_ts;\n const threadTs =\n payload.message?.thread_ts || payload.container?.thread_ts || messageTs;\n\n // Actions from Home tab views don't have channel/messageTs\n const isViewAction = payload.container?.type === \"view\";\n\n if (!(isViewAction || channel)) {\n this.logger.warn(\"Missing channel in block_actions\", { channel });\n return;\n }\n\n const threadId =\n channel && (threadTs || messageTs)\n ? this.encodeThreadId({\n channel,\n threadTs: threadTs || messageTs || \"\",\n })\n : \"\";\n\n const isEphemeral = payload.container?.is_ephemeral === true;\n const responseUrl = payload.response_url;\n const messageId =\n isEphemeral && responseUrl && messageTs\n ? this.encodeEphemeralMessageId(messageTs, responseUrl, payload.user.id)\n : messageTs || \"\";\n\n // Process each action (usually just one, but can be multiple)\n for (const action of payload.actions) {\n const actionValue = action.selected_option?.value ?? action.value;\n const actionEvent: Omit<ActionEvent, \"thread\" | \"openModal\"> & {\n adapter: SlackAdapter;\n } = {\n actionId: action.action_id,\n value: actionValue,\n user: {\n userId: payload.user.id,\n userName: payload.user.username || payload.user.name || \"unknown\",\n fullName: payload.user.name || payload.user.username || \"unknown\",\n isBot: false,\n isMe: false,\n },\n messageId,\n threadId,\n adapter: this,\n raw: payload,\n triggerId: payload.trigger_id,\n };\n\n this.logger.debug(\"Processing Slack block action\", {\n actionId: action.action_id,\n value: action.value,\n messageId: messageTs,\n threadId,\n triggerId: payload.trigger_id,\n });\n\n this.chat.processAction(actionEvent, options);\n }\n }\n\n private async handleViewSubmission(\n payload: SlackViewSubmissionPayload,\n options?: WebhookOptions\n ): Promise<Response> {\n if (!this.chat) {\n this.logger.warn(\n \"Chat instance not initialized, ignoring view submission\"\n );\n return new Response(\"\", { status: 200 });\n }\n\n // Flatten values from Slack's nested structure\n const values: Record<string, string> = {};\n for (const blockValues of Object.values(payload.view.state.values)) {\n for (const [actionId, input] of Object.entries(blockValues)) {\n values[actionId] = input.value ?? input.selected_option?.value ?? \"\";\n }\n }\n\n // Decode contextId and user privateMetadata from private_metadata\n const { contextId, privateMetadata } = decodeModalMetadata(\n payload.view.private_metadata || undefined\n );\n\n const event = {\n callbackId: payload.view.callback_id,\n viewId: payload.view.id,\n values,\n privateMetadata,\n user: {\n userId: payload.user.id,\n userName: payload.user.username || payload.user.name || \"unknown\",\n fullName: payload.user.name || payload.user.username || \"unknown\",\n isBot: false,\n isMe: false,\n },\n adapter: this as Adapter,\n raw: payload,\n };\n\n const response = await this.chat.processModalSubmit(\n event,\n contextId,\n options\n );\n\n if (response) {\n const slackResponse = this.modalResponseToSlack(response, contextId);\n return new Response(JSON.stringify(slackResponse), {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n return new Response(\"\", { status: 200 });\n }\n\n private handleViewClosed(\n payload: SlackViewClosedPayload,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\"Chat instance not initialized, ignoring view closed\");\n return;\n }\n\n // Decode contextId and user privateMetadata from private_metadata\n const { contextId, privateMetadata } = decodeModalMetadata(\n payload.view.private_metadata || undefined\n );\n\n const event = {\n callbackId: payload.view.callback_id,\n viewId: payload.view.id,\n privateMetadata,\n user: {\n userId: payload.user.id,\n userName: payload.user.username || payload.user.name || \"unknown\",\n fullName: payload.user.name || payload.user.username || \"unknown\",\n isBot: false,\n isMe: false,\n },\n adapter: this as Adapter,\n raw: payload,\n };\n\n this.chat.processModalClose(event, contextId, options);\n }\n\n private modalResponseToSlack(\n response: ModalResponse,\n contextId?: string\n ): SlackModalResponse {\n switch (response.action) {\n case \"close\":\n return {};\n case \"errors\":\n return { response_action: \"errors\", errors: response.errors };\n case \"update\": {\n const modal = this.convertModalJSX(response.modal);\n const metadata = encodeModalMetadata({\n contextId,\n privateMetadata: modal.privateMetadata,\n });\n const view = modalToSlackView(modal, metadata);\n return {\n response_action: \"update\",\n view,\n };\n }\n case \"push\": {\n const modal = this.convertModalJSX(response.modal);\n const metadata = encodeModalMetadata({\n contextId,\n privateMetadata: modal.privateMetadata,\n });\n const view = modalToSlackView(modal, metadata);\n return {\n response_action: \"push\",\n view,\n };\n }\n default:\n return {};\n }\n }\n\n private convertModalJSX(modal: ModalElement): ModalElement {\n if (isJSX(modal)) {\n const converted = toModalElement(modal);\n if (!converted) {\n throw new ValidationError(\n \"slack\",\n \"Invalid JSX element: must be a Modal element\"\n );\n }\n return converted;\n }\n return modal;\n }\n\n private verifySignature(\n body: string,\n timestamp: string | null,\n signature: string | null\n ): boolean {\n if (!(timestamp && signature)) {\n return false;\n }\n\n // Check timestamp is recent (within 5 minutes)\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - Number.parseInt(timestamp, 10)) > 300) {\n return false;\n }\n\n // Compute expected signature\n const sigBasestring = `v0:${timestamp}:${body}`;\n const expectedSignature =\n \"v0=\" +\n createHmac(\"sha256\", this.signingSecret)\n .update(sigBasestring)\n .digest(\"hex\");\n\n // Compare signatures using timing-safe comparison\n try {\n return timingSafeEqual(\n Buffer.from(signature),\n Buffer.from(expectedSignature)\n );\n } catch {\n return false;\n }\n }\n\n /**\n * Handle message events from Slack.\n * Bot message filtering (isMe) is handled centrally by the Chat class.\n */\n private handleMessageEvent(\n event: SlackEvent,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\"Chat instance not initialized, ignoring event\");\n return;\n }\n\n // Skip message subtypes that are system/meta events (edits, deletes, joins, etc.)\n // Allow through: bot_message, file_share, thread_broadcast, me_message, and\n // any other content-carrying subtypes. Chat class handles isMe filtering.\n const ignoredSubtypes = new Set([\n \"message_changed\",\n \"message_deleted\",\n \"message_replied\",\n \"channel_join\",\n \"channel_leave\",\n \"channel_topic\",\n \"channel_purpose\",\n \"channel_name\",\n \"channel_archive\",\n \"channel_unarchive\",\n \"group_join\",\n \"group_leave\",\n \"group_topic\",\n \"group_purpose\",\n \"group_name\",\n \"group_archive\",\n \"group_unarchive\",\n \"ekm_access_denied\",\n \"tombstone\",\n ]);\n\n if (event.subtype && ignoredSubtypes.has(event.subtype)) {\n this.logger.debug(\"Ignoring message subtype\", {\n subtype: event.subtype,\n });\n return;\n }\n\n if (!(event.channel && event.ts)) {\n this.logger.debug(\"Ignoring event without channel or ts\", {\n channel: event.channel,\n ts: event.ts,\n });\n return;\n }\n\n // For DMs: top-level messages use empty threadTs (matches openDM subscriptions),\n // thread replies use thread_ts for per-conversation isolation.\n // For channels: always use thread_ts or ts for per-thread IDs.\n const isDM = event.channel_type === \"im\";\n const threadTs = isDM ? event.thread_ts || \"\" : event.thread_ts || event.ts;\n const threadId = this.encodeThreadId({\n channel: event.channel,\n threadTs,\n });\n\n // Let Chat class handle async processing, waitUntil, and isMe filtering\n // Use factory function since parseSlackMessage is async (user lookup)\n //\n // In multi-workspace mode, the request context (token + botUserId) is set via\n // AsyncLocalStorage during synchronous webhook handling. processMessage creates\n // an async task (via waitUntil) that may run after requestContext.run() returns.\n // Node.js AsyncLocalStorage propagates context to async continuations as long as\n // the Promise is created within the run() callback. We call processMessage inside\n // run() so the async task and all its awaits inherit the context.\n const isMention = event.type === \"app_mention\";\n const factory = async (): Promise<Message<unknown>> => {\n const msg = await this.parseSlackMessage(event, threadId);\n if (isMention) {\n msg.isMention = true;\n }\n return msg;\n };\n\n this.chat.processMessage(this, threadId, factory, options);\n }\n\n /**\n * Handle reaction events from Slack (reaction_added, reaction_removed).\n */\n private async handleReactionEvent(\n event: SlackReactionEvent,\n options?: WebhookOptions\n ): Promise<void> {\n if (!this.chat) {\n this.logger.warn(\"Chat instance not initialized, ignoring reaction\");\n return;\n }\n\n // Only handle reactions to messages (not files, etc.)\n if (event.item.type !== \"message\") {\n this.logger.debug(\"Ignoring reaction to non-message item\", {\n itemType: event.item.type,\n });\n return;\n }\n\n // Resolve the parent thread ts — when a reaction is on a reply,\n // event.item.ts is the reply's ts, not the parent thread_ts.\n let parentTs = event.item.ts;\n try {\n const result = await this.client.conversations.replies(\n this.withToken({\n channel: event.item.channel,\n ts: event.item.ts,\n limit: 1,\n })\n );\n const firstMessage = (result.messages as { thread_ts?: string }[])?.[0];\n if (firstMessage?.thread_ts) {\n parentTs = firstMessage.thread_ts;\n }\n } catch (error) {\n this.logger.warn(\n \"Failed to resolve parent thread for reaction, using message ts\",\n {\n error: String(error),\n channel: event.item.channel,\n ts: event.item.ts,\n }\n );\n }\n\n // Build thread ID from the parent thread\n const threadId = this.encodeThreadId({\n channel: event.item.channel,\n threadTs: parentTs,\n });\n\n // Message ID is just the timestamp (Slack uses ts as message ID)\n const messageId = event.item.ts;\n\n // Normalize emoji\n const rawEmoji = event.reaction;\n const normalizedEmoji = defaultEmojiResolver.fromSlack(rawEmoji);\n\n // Check if reaction is from this bot (check request context for multi-workspace)\n const ctx = this.requestContext.getStore();\n const isMe =\n (ctx?.botUserId && event.user === ctx.botUserId) ||\n (this._botUserId !== null && event.user === this._botUserId) ||\n (this._botId !== null && event.user === this._botId);\n\n // Build reaction event\n const reactionEvent: Omit<ReactionEvent, \"adapter\" | \"thread\"> = {\n emoji: normalizedEmoji,\n rawEmoji,\n added: event.type === \"reaction_added\",\n user: {\n userId: event.user,\n userName: event.user, // Will be resolved below if possible\n fullName: event.user,\n isBot: false, // Users add reactions, not bots typically\n isMe,\n },\n messageId,\n threadId,\n raw: event,\n };\n\n // Process reaction\n this.chat.processReaction({ ...reactionEvent, adapter: this }, options);\n }\n\n /**\n * Handle assistant_thread_started events from Slack's Assistants API.\n * Fires when a user opens a new assistant thread (DM with the bot).\n */\n private handleAssistantThreadStarted(\n event: SlackAssistantThreadStartedEvent,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\n \"Chat instance not initialized, ignoring assistant_thread_started\"\n );\n return;\n }\n\n if (!event.assistant_thread) {\n this.logger.warn(\n \"Malformed assistant_thread_started: missing assistant_thread\"\n );\n return;\n }\n\n const { channel_id, thread_ts, user_id, context } = event.assistant_thread;\n const threadId = this.encodeThreadId({\n channel: channel_id,\n threadTs: thread_ts,\n });\n\n this.chat.processAssistantThreadStarted(\n {\n threadId,\n userId: user_id,\n channelId: channel_id,\n threadTs: thread_ts,\n context: {\n channelId: context.channel_id,\n teamId: context.team_id,\n enterpriseId: context.enterprise_id,\n threadEntryPoint: context.thread_entry_point,\n forceSearch: context.force_search,\n },\n adapter: this,\n },\n options\n );\n }\n\n /**\n * Handle assistant_thread_context_changed events from Slack's Assistants API.\n * Fires when a user navigates to a different channel with the assistant panel open.\n */\n private handleAssistantContextChanged(\n event: SlackAssistantContextChangedEvent,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\n \"Chat instance not initialized, ignoring assistant_thread_context_changed\"\n );\n return;\n }\n\n if (!event.assistant_thread) {\n this.logger.warn(\n \"Malformed assistant_thread_context_changed: missing assistant_thread\"\n );\n return;\n }\n\n const { channel_id, thread_ts, user_id, context } = event.assistant_thread;\n const threadId = this.encodeThreadId({\n channel: channel_id,\n threadTs: thread_ts,\n });\n\n this.chat.processAssistantContextChanged(\n {\n threadId,\n userId: user_id,\n channelId: channel_id,\n threadTs: thread_ts,\n context: {\n channelId: context.channel_id,\n teamId: context.team_id,\n enterpriseId: context.enterprise_id,\n threadEntryPoint: context.thread_entry_point,\n forceSearch: context.force_search,\n },\n adapter: this,\n },\n options\n );\n }\n\n /**\n * Handle app_home_opened events from Slack.\n * Fires when a user opens the bot's Home tab.\n */\n private handleAppHomeOpened(\n event: SlackAppHomeOpenedEvent,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\n \"Chat instance not initialized, ignoring app_home_opened\"\n );\n return;\n }\n\n this.chat.processAppHomeOpened(\n {\n userId: event.user,\n channelId: event.channel,\n adapter: this,\n },\n options\n );\n }\n\n /**\n * Handle member_joined_channel events from Slack.\n * Fires when a user (including the bot) joins a channel.\n */\n private handleMemberJoinedChannel(\n event: SlackMemberJoinedChannelEvent,\n options?: WebhookOptions\n ): void {\n if (!this.chat) {\n this.logger.warn(\n \"Chat instance not initialized, ignoring member_joined_channel\"\n );\n return;\n }\n\n this.chat.processMemberJoinedChannel(\n {\n userId: event.user,\n channelId: this.encodeThreadId({\n channel: event.channel,\n threadTs: \"\",\n }),\n inviterId: event.inviter,\n adapter: this,\n },\n options\n );\n }\n\n private async handleUserChange(event: SlackUserChangeEvent): Promise<void> {\n if (!this.chat) {\n return;\n }\n\n try {\n await this.chat.getState().delete(`slack:user:${event.user.id}`);\n } catch (error) {\n this.logger.warn(\"Failed to invalidate user cache\", {\n userId: event.user.id,\n error,\n });\n }\n }\n\n /**\n * Publish a Home tab view for a user.\n * Slack API: views.publish\n */\n async publishHomeView(\n userId: string,\n view: Record<string, unknown>\n ): Promise<void> {\n await this.client.views.publish(\n // biome-ignore lint/suspicious/noExplicitAny: view blocks are consumer-defined\n this.withToken({ user_id: userId, view }) as any\n );\n }\n\n /**\n * Set suggested prompts for an assistant thread.\n * Slack Assistants API: assistant.threads.setSuggestedPrompts\n */\n async setSuggestedPrompts(\n channelId: string,\n threadTs: string,\n prompts: Array<{ title: string; message: string }>,\n title?: string\n ): Promise<void> {\n await this.client.assistant.threads.setSuggestedPrompts(\n this.withToken({\n channel_id: channelId,\n thread_ts: threadTs,\n prompts,\n title,\n })\n );\n }\n\n /**\n * Set status/thinking indicator for an assistant thread.\n * Slack Assistants API: assistant.threads.setStatus\n */\n async setAssistantStatus(\n channelId: string,\n threadTs: string,\n status: string,\n loadingMessages?: string[]\n ): Promise<void> {\n await this.client.assistant.threads.setStatus(\n this.withToken({\n channel_id: channelId,\n thread_ts: threadTs,\n status,\n ...(loadingMessages && { loading_messages: loadingMessages }),\n })\n );\n }\n\n /**\n * Set title for an assistant thread (shown in History tab).\n * Slack Assistants API: assistant.threads.setTitle\n */\n async setAssistantTitle(\n channelId: string,\n threadTs: string,\n title: string\n ): Promise<void> {\n await this.client.assistant.threads.setTitle(\n this.withToken({\n channel_id: channelId,\n thread_ts: threadTs,\n title,\n })\n );\n }\n\n /**\n * Resolve inline user mentions in Slack mrkdwn text.\n * Converts <@U123> to <@U123|displayName> so that toAst/extractPlainText\n * renders them as @displayName instead of @U123.\n *\n * @param skipSelfMention - When true, skips the bot's own user ID so that\n * mention detection (which looks for @botUserId in the text) continues to\n * work. Set to false when parsing historical/channel messages where mention\n * detection doesn't apply.\n */\n private async resolveInlineMentions(\n text: string,\n skipSelfMention: boolean\n ): Promise<string> {\n const userIds = new Set<string>();\n const channelIds = new Set<string>();\n // Parse mentions by splitting on angle brackets to avoid ReDoS\n for (const segment of text.split(\"<\")) {\n const end = segment.indexOf(\">\");\n if (end === -1) {\n continue;\n }\n const inner = segment.slice(0, end);\n if (inner.startsWith(\"@\")) {\n const rest = inner.slice(1);\n const pipeIdx = rest.indexOf(\"|\");\n const uid = pipeIdx >= 0 ? rest.slice(0, pipeIdx) : rest;\n if (SLACK_USER_ID_PATTERN.test(uid)) {\n userIds.add(uid);\n }\n } else if (inner.startsWith(\"#\")) {\n const rest = inner.slice(1);\n const pipeIdx = rest.indexOf(\"|\");\n // Only collect bare channel IDs (no label already present)\n if (pipeIdx === -1 && SLACK_USER_ID_PATTERN.test(rest)) {\n channelIds.add(rest);\n }\n }\n }\n if (userIds.size === 0 && channelIds.size === 0) {\n return text;\n }\n\n // Don't resolve the bot's own mention when processing incoming webhooks —\n // detectMention needs @botUserId in the text\n if (skipSelfMention && this._botUserId) {\n userIds.delete(this._botUserId);\n }\n if (userIds.size === 0 && channelIds.size === 0) {\n return text;\n }\n\n // Look up all mentioned users and channels in parallel\n const [userLookups, channelLookups] = await Promise.all([\n Promise.all(\n [...userIds].map(async (uid) => {\n const info = await this.lookupUser(uid);\n return [uid, info.displayName] as const;\n })\n ),\n Promise.all(\n [...channelIds].map(async (cid) => {\n const name = await this.lookupChannel(cid);\n return [cid, name] as const;\n })\n ),\n ]);\n const userNameMap = new Map(userLookups);\n const channelNameMap = new Map(channelLookups);\n\n // Replace <@U123>, <@U123|old>, and <#C123> with resolved names\n // Use split-based approach to avoid ReDoS on user-controlled input\n let result = \"\";\n let remaining = text;\n let startIdx = findNextMention(remaining);\n while (startIdx !== -1) {\n result += remaining.slice(0, startIdx);\n remaining = remaining.slice(startIdx);\n const endIdx = remaining.indexOf(\">\");\n if (endIdx === -1) {\n break;\n }\n const prefix = remaining[1]; // '@' or '#'\n const inner = remaining.slice(2, endIdx); // after \"<@\" or \"<#\"\n const pipeIdx = inner.indexOf(\"|\");\n const id = pipeIdx >= 0 ? inner.slice(0, pipeIdx) : inner;\n if (prefix === \"@\" && SLACK_USER_ID_PATTERN.test(id)) {\n const name = userNameMap.get(id);\n result += name ? `<@${id}|${name}>` : `<@${id}>`;\n } else if (prefix === \"#\" && pipeIdx === -1 && channelNameMap.has(id)) {\n const name = channelNameMap.get(id);\n result += `<#${id}|${name}>`;\n } else {\n result += remaining.slice(0, endIdx + 1);\n }\n remaining = remaining.slice(endIdx + 1);\n startIdx = findNextMention(remaining);\n }\n return result + remaining;\n }\n\n /**\n * Extract link URLs from a Slack event.\n * Uses the `blocks` field (rich_text blocks with link elements) when available,\n * falling back to parsing `<url>` patterns from the text field.\n */\n private extractLinks(event: SlackEvent): LinkPreview[] {\n const urls = new Set<string>();\n\n // Try blocks first - they contain structured link elements\n if (event.blocks) {\n for (const block of event.blocks) {\n if (block.type === \"rich_text\" && block.elements) {\n for (const section of block.elements) {\n if (section.elements) {\n for (const element of section.elements) {\n if (element.type === \"link\" && element.url) {\n urls.add(element.url);\n }\n }\n }\n }\n }\n }\n }\n\n // Fallback: parse <url> and <url|label> from text\n if (urls.size === 0 && event.text) {\n const urlPattern = /<(https?:\\/\\/[^>]+)>/g;\n for (const match of event.text.matchAll(urlPattern)) {\n // Strip optional \"|label\" suffix (Slack format: <url|label>)\n const raw = match[1] as string;\n const pipeIdx = raw.indexOf(\"|\");\n urls.add(pipeIdx >= 0 ? raw.slice(0, pipeIdx) : raw);\n }\n }\n\n return [...urls].map((url) => this.createLinkPreview(url));\n }\n\n /**\n * Create a LinkPreview for a URL. If the URL points to a Slack message,\n * includes a `fetchMessage` callback that fetches and parses the linked message.\n */\n private createLinkPreview(url: string): LinkPreview {\n const match = SLACK_MESSAGE_URL_PATTERN.exec(url);\n if (!match) {\n return { url };\n }\n\n const channel = match[1] as string;\n const rawTs = match[2] as string;\n // Convert URL timestamp to Slack ts format: insert dot before last 6 digits\n const ts = `${rawTs.slice(0, rawTs.length - 6)}.${rawTs.slice(rawTs.length - 6)}`;\n const threadId = this.encodeThreadId({ channel, threadTs: ts });\n\n return {\n url,\n fetchMessage: async () => {\n const result = await this.client.conversations.history(\n this.withToken({\n channel,\n latest: ts,\n inclusive: true,\n limit: 1,\n })\n );\n\n const messages = (result.messages || []) as SlackEvent[];\n const target = messages.find((msg) => msg.ts === ts);\n if (!target) {\n throw new Error(`Message not found: ${url}`);\n }\n\n return this.parseSlackMessage(target, threadId);\n },\n };\n }\n\n private async parseSlackMessage(\n event: SlackEvent,\n threadId: string,\n options?: { skipSelfMention?: boolean }\n ): Promise<Message<unknown>> {\n const isMe = this.isMessageFromSelf(event);\n const skipSelfMention = options?.skipSelfMention ?? true;\n\n const rawText = event.text || \"\";\n\n // Get user info - for human users we need to look up the display name\n // since Slack events only include the user ID, not the username\n let userName = event.username || \"unknown\";\n let fullName = event.username || \"unknown\";\n\n // If we have a user ID but no username, look up the user info\n if (event.user && !event.username) {\n const userInfo = await this.lookupUser(event.user);\n userName = userInfo.displayName;\n fullName = userInfo.realName;\n }\n\n // Track thread participants for outgoing mention resolution (skip dupes)\n if (event.user && this.chat) {\n try {\n const participantKey = `slack:thread-participants:${threadId}`;\n const participants = await this.chat\n .getState()\n .getList<string>(participantKey);\n if (!participants.includes(event.user)) {\n await this.chat.getState().appendToList(participantKey, event.user, {\n maxLength: 100,\n ttlMs: SlackAdapter.REVERSE_INDEX_TTL_MS,\n });\n }\n } catch (error) {\n this.logger.warn(\"Failed to track thread participant\", {\n threadId,\n userId: event.user,\n error,\n });\n }\n }\n\n // Resolve inline @mentions to display names\n const text = await this.resolveInlineMentions(rawText, skipSelfMention);\n\n return new Message({\n id: event.ts || \"\",\n threadId,\n text: this.formatConverter.extractPlainText(text),\n formatted: this.formatConverter.toAst(text),\n raw: event,\n author: {\n userId: event.user || event.bot_id || \"unknown\",\n userName,\n fullName,\n isBot: !!event.bot_id,\n isMe,\n },\n metadata: {\n dateSent: new Date(Number.parseFloat(event.ts || \"0\") * 1000),\n edited: !!event.edited,\n editedAt: event.edited\n ? new Date(Number.parseFloat(event.edited.ts) * 1000)\n : undefined,\n },\n attachments: (event.files || []).map((file) =>\n this.createAttachment(file)\n ),\n links: this.extractLinks(event),\n });\n }\n\n /**\n * Create an Attachment object from a Slack file.\n * Includes a fetchData method that uses the bot token for auth.\n */\n private createAttachment(file: {\n id?: string;\n mimetype?: string;\n url_private?: string;\n name?: string;\n size?: number;\n original_w?: number;\n original_h?: number;\n }): Attachment {\n const url = file.url_private;\n // Capture token at attachment creation time (during webhook processing context)\n const botToken = this.getToken();\n\n // Determine type based on mimetype\n let type: Attachment[\"type\"] = \"file\";\n if (file.mimetype?.startsWith(\"image/\")) {\n type = \"image\";\n } else if (file.mimetype?.startsWith(\"video/\")) {\n type = \"video\";\n } else if (file.mimetype?.startsWith(\"audio/\")) {\n type = \"audio\";\n }\n\n return {\n type,\n url,\n name: file.name,\n mimeType: file.mimetype,\n size: file.size,\n width: file.original_w,\n height: file.original_h,\n fetchData: url\n ? async () => {\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${botToken}`,\n },\n });\n if (!response.ok) {\n throw new NetworkError(\n \"slack\",\n `Failed to fetch file: ${response.status} ${response.statusText}`\n );\n }\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"text/html\")) {\n throw new NetworkError(\n \"slack\",\n \"Failed to download file from Slack: received HTML login page instead of file data. \" +\n `Ensure your Slack app has the \"files:read\" OAuth scope. ` +\n `URL: ${url}`\n );\n }\n const arrayBuffer = await response.arrayBuffer();\n return Buffer.from(arrayBuffer);\n }\n : undefined,\n };\n }\n\n /**\n * Resolve @name mentions in text to Slack <@USER_ID> format using the\n * reverse user cache. When multiple users share a display name, prefers\n * the one who is a participant in the given thread.\n */\n private async resolveOutgoingMentions(\n text: string,\n threadId: string\n ): Promise<string> {\n if (!this.chat) {\n return text;\n }\n const state = this.chat.getState();\n\n // Find all @word patterns that aren't already wrapped in <@...>\n const mentionPattern = /@(\\w+)/g;\n const mentions = new Map<string, string[]>();\n\n for (const match of text.matchAll(mentionPattern)) {\n const name = match[1];\n // Skip if already a Slack user ID format or inside <@...>\n if (SLACK_USER_ID_EXACT_PATTERN.test(name)) {\n continue;\n }\n // Check the character before @ to skip <@...> patterns\n const idx = match.index;\n if (idx > 0 && text[idx - 1] === \"<\") {\n continue;\n }\n if (!mentions.has(name.toLowerCase())) {\n mentions.set(name.toLowerCase(), []);\n }\n }\n\n if (mentions.size === 0) {\n return text;\n }\n\n // Look up user IDs for each mentioned name\n for (const name of mentions.keys()) {\n const userIds = await state.getList<string>(`slack:user-by-name:${name}`);\n // Dedup\n const unique = [...new Set(userIds)];\n mentions.set(name, unique);\n }\n\n // Load thread participants only if needed (ambiguous mentions)\n let participants: Set<string> | null = null;\n const needsParticipants = [...mentions.values()].some(\n (ids) => ids.length > 1\n );\n if (needsParticipants) {\n const participantList = await state.getList<string>(\n `slack:thread-participants:${threadId}`\n );\n participants = new Set(participantList);\n }\n\n // Replace mentions in text\n return text.replace(\n mentionPattern,\n (match, name: string, offset: number) => {\n if (offset > 0 && text[offset - 1] === \"<\") {\n return match;\n }\n if (SLACK_USER_ID_EXACT_PATTERN.test(name)) {\n return match;\n }\n\n const userIds = mentions.get(name.toLowerCase());\n if (!userIds || userIds.length === 0) {\n return match;\n }\n if (userIds.length === 1) {\n return `<@${userIds[0]}>`;\n }\n // Disambiguate using thread participants\n if (participants) {\n const inThread = userIds.filter((id) => participants.has(id));\n if (inThread.length === 1) {\n return `<@${inThread[0]}>`;\n }\n }\n // Still ambiguous — leave as plain text\n return match;\n }\n );\n }\n\n /**\n * Pre-process an outgoing message to resolve @name mentions before rendering.\n */\n private async resolveMessageMentions(\n message: AdapterPostableMessage,\n threadId: string\n ): Promise<AdapterPostableMessage> {\n if (!this.chat) {\n return message;\n }\n if (typeof message === \"string\") {\n return this.resolveOutgoingMentions(message, threadId);\n }\n if (typeof message === \"object\" && message !== null) {\n if (\n \"raw\" in message &&\n typeof (message as { raw: unknown }).raw === \"string\"\n ) {\n return {\n ...message,\n raw: await this.resolveOutgoingMentions(\n (message as { raw: string }).raw,\n threadId\n ),\n };\n }\n if (\n \"markdown\" in message &&\n typeof (message as { markdown: unknown }).markdown === \"string\"\n ) {\n return {\n ...message,\n markdown: await this.resolveOutgoingMentions(\n (message as { markdown: string }).markdown,\n threadId\n ),\n };\n }\n }\n // AST, Card, or other formats — pass through unchanged\n return message;\n }\n\n /**\n * Try to render a message using native Slack table blocks.\n * Returns blocks + fallback text if the message contains tables, null otherwise.\n */\n private renderWithTableBlocks(\n message: AdapterPostableMessage\n ): { text: string; blocks: SlackBlock[] } | null {\n let ast: Root | null = null;\n if (typeof message === \"object\" && message !== null) {\n if (\"ast\" in message) {\n ast = (message as { ast: Root }).ast;\n } else if (\"markdown\" in message) {\n ast = parseMarkdown((message as { markdown: string }).markdown);\n }\n }\n if (!ast) {\n return null;\n }\n\n const blocks = this.formatConverter.toBlocksWithTable(ast);\n if (!blocks) {\n return null;\n }\n\n // Use regular rendering as fallback text for notifications\n const fallbackText = convertEmojiPlaceholders(\n this.formatConverter.renderPostable(message),\n \"slack\"\n );\n return { text: fallbackText, blocks };\n }\n\n async postMessage(\n threadId: string,\n _message: AdapterPostableMessage\n ): Promise<RawMessage<unknown>> {\n const message = await this.resolveMessageMentions(_message, threadId);\n const { channel, threadTs } = this.decodeThreadId(threadId);\n\n try {\n // Check for files to upload\n const files = extractFiles(message);\n if (files.length > 0) {\n // Upload files first (they're shared to the channel automatically)\n await this.uploadFiles(files, channel, threadTs || undefined);\n\n // If message only has files (no text/card), return early\n const hasText =\n typeof message === \"string\" ||\n (typeof message === \"object\" &&\n message !== null &&\n ((\"raw\" in message && message.raw) ||\n (\"markdown\" in message && message.markdown) ||\n (\"ast\" in message && message.ast)));\n const card = extractCard(message);\n\n if (!(hasText || card)) {\n // Return a synthetic message ID since files.uploadV2 handles sharing\n return {\n id: `file-${Date.now()}`,\n threadId,\n raw: { files },\n };\n }\n }\n\n // Check if message contains a card\n const card = extractCard(message);\n\n if (card) {\n // Render card as Block Kit\n const blocks = cardToBlockKit(card);\n const fallbackText = cardToFallbackText(card);\n\n this.logger.debug(\"Slack API: chat.postMessage (blocks)\", {\n channel,\n threadTs,\n blockCount: blocks.length,\n });\n\n const result = await this.client.chat.postMessage(\n this.withToken({\n channel,\n thread_ts: threadTs,\n text: fallbackText, // Fallback for notifications\n blocks,\n unfurl_links: false,\n unfurl_media: false,\n })\n );\n\n this.logger.debug(\"Slack API: chat.postMessage response\", {\n messageId: result.ts,\n ok: result.ok,\n });\n\n return {\n id: result.ts as string,\n threadId,\n raw: result,\n };\n }\n\n // Check for tables in markdown/AST messages → use native table blocks\n const tableResult = this.renderWithTableBlocks(message);\n if (tableResult) {\n this.logger.debug(\"Slack API: chat.postMessage (table blocks)\", {\n channel,\n threadTs,\n blockCount: tableResult.blocks.length,\n });\n\n const result = await this.client.chat.postMessage(\n this.withToken({\n channel,\n thread_ts: threadTs,\n text: tableResult.text,\n blocks: tableResult.blocks,\n unfurl_links: false,\n unfurl_media: false,\n })\n );\n\n this.logger.debug(\"Slack API: chat.postMessage response\", {\n messageId: result.ts,\n ok: result.ok,\n });\n\n return {\n id: result.ts as string,\n threadId,\n raw: result,\n };\n }\n\n // Regular text message\n const text = convertEmojiPlaceholders(\n this.formatConverter.renderPostable(message),\n \"slack\"\n );\n\n this.logger.debug(\"Slack API: chat.postMessage\", {\n channel,\n threadTs,\n textLength: text.length,\n });\n\n const result = await this.client.chat.postMessage(\n this.withToken({\n channel,\n thread_ts: threadTs,\n text,\n unfurl_links: false,\n unfurl_media: false,\n })\n );\n\n this.logger.debug(\"Slack API: chat.postMessage response\", {\n messageId: result.ts,\n ok: result.ok,\n });\n\n return {\n id: result.ts as string,\n threadId,\n raw: result,\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async postEphemeral(\n threadId: string,\n userId: string,\n _message: AdapterPostableMessage\n ): Promise<EphemeralMessage> {\n const message = await this.resolveMessageMentions(_message, threadId);\n const { channel, threadTs } = this.decodeThreadId(threadId);\n\n try {\n // Check if message contains a card\n const card = extractCard(message);\n\n if (card) {\n // Render card as Block Kit\n const blocks = cardToBlockKit(card);\n const fallbackText = cardToFallbackText(card);\n\n this.logger.debug(\"Slack API: chat.postEphemeral (blocks)\", {\n channel,\n threadTs,\n userId,\n blockCount: blocks.length,\n });\n\n const result = await this.client.chat.postEphemeral(\n this.withToken({\n channel,\n thread_ts: threadTs || undefined,\n user: userId,\n text: fallbackText,\n blocks,\n })\n );\n\n this.logger.debug(\"Slack API: chat.postEphemeral response\", {\n messageTs: result.message_ts,\n ok: result.ok,\n });\n\n return {\n id: result.message_ts || \"\",\n threadId,\n usedFallback: false,\n raw: result,\n };\n }\n\n // Check for tables in markdown/AST messages → use native table blocks\n const tableResult = this.renderWithTableBlocks(message);\n if (tableResult) {\n this.logger.debug(\"Slack API: chat.postEphemeral (table blocks)\", {\n channel,\n threadTs,\n userId,\n blockCount: tableResult.blocks.length,\n });\n\n const result = await this.client.chat.postEphemeral(\n this.withToken({\n channel,\n thread_ts: threadTs || undefined,\n user: userId,\n text: tableResult.text,\n blocks: tableResult.blocks,\n })\n );\n\n this.logger.debug(\"Slack API: chat.postEphemeral response\", {\n messageTs: result.message_ts,\n ok: result.ok,\n });\n\n return {\n id: result.message_ts || \"\",\n threadId,\n usedFallback: false,\n raw: result,\n };\n }\n\n // Regular text message\n const text = convertEmojiPlaceholders(\n this.formatConverter.renderPostable(message),\n \"slack\"\n );\n\n this.logger.debug(\"Slack API: chat.postEphemeral\", {\n channel,\n threadTs,\n userId,\n textLength: text.length,\n });\n\n const result = await this.client.chat.postEphemeral(\n this.withToken({\n channel,\n thread_ts: threadTs || undefined,\n user: userId,\n text,\n })\n );\n\n this.logger.debug(\"Slack API: chat.postEphemeral response\", {\n messageTs: result.message_ts,\n ok: result.ok,\n });\n\n return {\n id: result.message_ts || \"\",\n threadId,\n usedFallback: false,\n raw: result,\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async scheduleMessage(\n threadId: string,\n _message: AdapterPostableMessage,\n options: { postAt: Date }\n ): Promise<ScheduledMessage> {\n const message = await this.resolveMessageMentions(_message, threadId);\n const { channel, threadTs } = this.decodeThreadId(threadId);\n const postAtUnix = Math.floor(options.postAt.getTime() / 1000);\n\n if (postAtUnix <= Math.floor(Date.now() / 1000)) {\n throw new ValidationError(\"slack\", \"postAt must be in the future\");\n }\n\n // File uploads are not supported by chat.scheduleMessage\n const files = extractFiles(message);\n if (files.length > 0) {\n throw new ValidationError(\n \"slack\",\n \"File uploads are not supported in scheduled messages\"\n );\n }\n\n // Capture token now so cancel() works outside request context\n const token = this.getToken();\n\n try {\n const card = extractCard(message);\n\n if (card) {\n const blocks = cardToBlockKit(card);\n const fallbackText = cardToFallbackText(card);\n\n this.logger.debug(\"Slack API: chat.scheduleMessage (blocks)\", {\n channel,\n threadTs,\n postAt: postAtUnix,\n blockCount: blocks.length,\n });\n\n const result = await this.client.chat.scheduleMessage({\n token,\n channel,\n thread_ts: threadTs || undefined,\n post_at: postAtUnix,\n text: fallbackText,\n blocks,\n unfurl_links: false,\n unfurl_media: false,\n });\n\n const scheduledMessageId = result.scheduled_message_id as string;\n const adapter = this;\n\n return {\n scheduledMessageId,\n channelId: channel,\n postAt: options.postAt,\n raw: result,\n async cancel() {\n await adapter.client.chat.deleteScheduledMessage({\n token,\n channel,\n scheduled_message_id: scheduledMessageId,\n });\n },\n };\n }\n\n // Regular text message\n const text = convertEmojiPlaceholders(\n this.formatConverter.renderPostable(message),\n \"slack\"\n );\n\n this.logger.debug(\"Slack API: chat.scheduleMessage\", {\n channel,\n threadTs,\n postAt: postAtUnix,\n textLength: text.length,\n });\n\n const result = await this.client.chat.scheduleMessage({\n token,\n channel,\n thread_ts: threadTs || undefined,\n post_at: postAtUnix,\n text,\n unfurl_links: false,\n unfurl_media: false,\n });\n\n const scheduledMessageId = result.scheduled_message_id as string;\n const adapter = this;\n\n return {\n scheduledMessageId,\n channelId: channel,\n postAt: options.postAt,\n raw: result,\n async cancel() {\n await adapter.client.chat.deleteScheduledMessage({\n token,\n channel,\n scheduled_message_id: scheduledMessageId,\n });\n },\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async openModal(\n triggerId: string,\n modal: ModalElement,\n contextId?: string\n ): Promise<{ viewId: string }> {\n const metadata = encodeModalMetadata({\n contextId,\n privateMetadata: modal.privateMetadata,\n });\n const view = modalToSlackView(modal, metadata);\n\n this.logger.debug(\"Slack API: views.open\", {\n triggerId,\n callbackId: modal.callbackId,\n });\n\n try {\n const result = await this.client.views.open(\n this.withToken({\n trigger_id: triggerId,\n view,\n })\n );\n\n this.logger.debug(\"Slack API: views.open response\", {\n viewId: result.view?.id,\n ok: result.ok,\n });\n\n return { viewId: result.view?.id as string };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async updateModal(\n viewId: string,\n modal: ModalElement\n ): Promise<{ viewId: string }> {\n const view = modalToSlackView(modal);\n\n this.logger.debug(\"Slack API: views.update\", {\n viewId,\n callbackId: modal.callbackId,\n });\n\n try {\n const result = await this.client.views.update(\n this.withToken({\n view_id: viewId,\n view,\n })\n );\n\n this.logger.debug(\"Slack API: views.update response\", {\n viewId: result.view?.id,\n ok: result.ok,\n });\n\n return { viewId: result.view?.id as string };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n /**\n * Upload files to Slack and share them to a channel.\n * Returns the file IDs of uploaded files.\n */\n private async uploadFiles(\n files: FileUpload[],\n channel: string,\n threadTs?: string\n ): Promise<string[]> {\n const bufferResults = await Promise.all(\n files.map(async (file) => {\n try {\n const fileBuffer = await toBuffer(file.data, { platform: \"slack\" });\n if (!fileBuffer) {\n return null;\n }\n return { file: fileBuffer, filename: file.filename };\n } catch (error) {\n this.logger.error(\"Failed to convert file to buffer\", {\n filename: file.filename,\n error,\n });\n return null;\n }\n })\n );\n const fileUploads = bufferResults.filter(\n (result): result is NonNullable<typeof result> => result !== null\n );\n if (fileUploads.length === 0) {\n return [];\n }\n this.logger.debug(\"Slack API: files.uploadV2 (batch)\", {\n fileCount: fileUploads.length,\n filenames: fileUploads.map((f) => f.filename),\n });\n\n // biome-ignore lint/suspicious/noExplicitAny: Slack API types don't match actual usage\n const uploadArgs: any = { channel_id: channel, file_uploads: fileUploads };\n if (threadTs) {\n uploadArgs.thread_ts = threadTs;\n }\n uploadArgs.token = this.getToken();\n const result = (await this.client.files.uploadV2(uploadArgs)) as {\n ok: boolean;\n files?: Array<{ files?: Array<{ id?: string }> }>;\n };\n this.logger.debug(\"Slack API: files.uploadV2 response\", { ok: result.ok });\n const fileIds: string[] = [];\n if (result.files?.[0]?.files) {\n for (const uploadedFile of result.files[0].files) {\n if (uploadedFile.id) {\n fileIds.push(uploadedFile.id);\n }\n }\n }\n\n return fileIds;\n }\n\n async editMessage(\n threadId: string,\n messageId: string,\n _message: AdapterPostableMessage\n ): Promise<RawMessage<unknown>> {\n const message = await this.resolveMessageMentions(_message, threadId);\n const ephemeral = this.decodeEphemeralMessageId(messageId);\n if (ephemeral) {\n const { threadTs } = this.decodeThreadId(threadId);\n const result = await this.sendToResponseUrl(\n ephemeral.responseUrl,\n \"replace\",\n {\n message,\n threadTs,\n }\n );\n return {\n id: ephemeral.messageTs,\n threadId,\n raw: { ephemeral: true, ...result },\n };\n }\n\n const { channel } = this.decodeThreadId(threadId);\n\n try {\n // Check if message contains a card\n const card = extractCard(message);\n\n if (card) {\n // Render card as Block Kit\n const blocks = cardToBlockKit(card);\n const fallbackText = cardToFallbackText(card);\n\n this.logger.debug(\"Slack API: chat.update (blocks)\", {\n channel,\n messageId,\n blockCount: blocks.length,\n });\n\n const result = await this.client.chat.update(\n this.withToken({\n channel,\n ts: messageId,\n text: fallbackText,\n blocks,\n })\n );\n\n this.logger.debug(\"Slack API: chat.update response\", {\n messageId: result.ts,\n ok: result.ok,\n });\n\n return {\n id: result.ts as string,\n threadId,\n raw: result,\n };\n }\n\n // Check for tables in markdown/AST messages → use native table blocks\n const tableResult = this.renderWithTableBlocks(message);\n if (tableResult) {\n this.logger.debug(\"Slack API: chat.update (table blocks)\", {\n channel,\n messageId,\n blockCount: tableResult.blocks.length,\n });\n\n const result = await this.client.chat.update(\n this.withToken({\n channel,\n ts: messageId,\n text: tableResult.text,\n blocks: tableResult.blocks,\n })\n );\n\n this.logger.debug(\"Slack API: chat.update response\", {\n messageId: result.ts,\n ok: result.ok,\n });\n\n return {\n id: result.ts as string,\n threadId,\n raw: result,\n };\n }\n\n // Regular text message\n const text = convertEmojiPlaceholders(\n this.formatConverter.renderPostable(message),\n \"slack\"\n );\n\n this.logger.debug(\"Slack API: chat.update\", {\n channel,\n messageId,\n textLength: text.length,\n });\n\n const result = await this.client.chat.update(\n this.withToken({\n channel,\n ts: messageId,\n text,\n })\n );\n\n this.logger.debug(\"Slack API: chat.update response\", {\n messageId: result.ts,\n ok: result.ok,\n });\n\n return {\n id: result.ts as string,\n threadId,\n raw: result,\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async deleteMessage(threadId: string, messageId: string): Promise<void> {\n const ephemeral = this.decodeEphemeralMessageId(messageId);\n if (ephemeral) {\n await this.sendToResponseUrl(ephemeral.responseUrl, \"delete\");\n return;\n }\n const { channel } = this.decodeThreadId(threadId);\n\n try {\n this.logger.debug(\"Slack API: chat.delete\", { channel, messageId });\n\n await this.client.chat.delete(\n this.withToken({\n channel,\n ts: messageId,\n })\n );\n\n this.logger.debug(\"Slack API: chat.delete response\", { ok: true });\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async addReaction(\n threadId: string,\n messageId: string,\n emoji: EmojiValue | string\n ): Promise<void> {\n const { channel } = this.decodeThreadId(threadId);\n // Convert emoji (EmojiValue or string) to Slack format, strip colons\n const slackEmoji = defaultEmojiResolver.toSlack(emoji);\n const name = slackEmoji.replace(/:/g, \"\");\n\n try {\n this.logger.debug(\"Slack API: reactions.add\", {\n channel,\n messageId,\n emoji: name,\n });\n\n await this.client.reactions.add(\n this.withToken({\n channel,\n timestamp: messageId,\n name,\n })\n );\n\n this.logger.debug(\"Slack API: reactions.add response\", { ok: true });\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async removeReaction(\n threadId: string,\n messageId: string,\n emoji: EmojiValue | string\n ): Promise<void> {\n const { channel } = this.decodeThreadId(threadId);\n // Convert emoji (EmojiValue or string) to Slack format, strip colons\n const slackEmoji = defaultEmojiResolver.toSlack(emoji);\n const name = slackEmoji.replace(/:/g, \"\");\n\n try {\n this.logger.debug(\"Slack API: reactions.remove\", {\n channel,\n messageId,\n emoji: name,\n });\n\n await this.client.reactions.remove(\n this.withToken({\n channel,\n timestamp: messageId,\n name,\n })\n );\n\n this.logger.debug(\"Slack API: reactions.remove response\", { ok: true });\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n /**\n * Show typing indicator with optional custom status.\n *\n * When status is provided, uses Slack's assistant.threads.setStatus API\n * to show custom loading text (requires Agents & AI Apps feature and assistant:write scope).\n * The status auto-clears when a message is posted to the thread.\n *\n * When status is not provided, defaults to \"Typing...\" with default loading messages.\n *\n * @param threadId - The thread to show the indicator in\n * @param status - Optional custom status message (e.g., \"Searching documents...\")\n */\n async startTyping(threadId: string, status?: string): Promise<void> {\n const { channel, threadTs } = this.decodeThreadId(threadId);\n if (!threadTs) {\n this.logger.debug(\"Slack: startTyping skipped - no thread context\");\n return;\n }\n this.logger.debug(\"Slack API: assistant.threads.setStatus\", {\n channel,\n threadTs,\n status,\n });\n try {\n await this.client.assistant.threads.setStatus(\n this.withToken({\n channel_id: channel,\n thread_ts: threadTs,\n status: status ?? \"Typing...\",\n loading_messages: [status ?? \"Typing...\"],\n })\n );\n } catch (error) {\n this.logger.warn(\"Slack API: assistant.threads.setStatus failed\", {\n channel,\n threadTs,\n error,\n });\n }\n }\n\n /**\n * Stream a message using Slack's native streaming API.\n *\n * Consumes an async iterable of text chunks and/or structured StreamChunk\n * objects (task_update, plan_update, markdown_text) and streams them to Slack.\n *\n * Plain strings are rendered through StreamingMarkdownRenderer for safe\n * incremental markdown. StreamChunk objects are passed directly to Slack's\n * streaming API as chunk payloads, enabling native task progress cards\n * and plan displays in the Slack AI Assistant UI.\n *\n * Requires `recipientUserId` and `recipientTeamId` in options.\n */\n async stream(\n threadId: string,\n textStream: AsyncIterable<string | StreamChunk>,\n options?: StreamOptions\n ): Promise<RawMessage<unknown>> {\n if (!(options?.recipientUserId && options?.recipientTeamId)) {\n throw new ValidationError(\n \"slack\",\n \"Slack streaming requires recipientUserId and recipientTeamId in options\"\n );\n }\n const { channel, threadTs } = this.decodeThreadId(threadId);\n this.logger.debug(\"Slack: starting stream\", { channel, threadTs });\n\n const token = this.getToken();\n const streamer = this.client.chatStream({\n channel,\n thread_ts: threadTs,\n recipient_user_id: options.recipientUserId,\n recipient_team_id: options.recipientTeamId,\n ...(options.taskDisplayMode && {\n task_display_mode: options.taskDisplayMode,\n }),\n });\n\n let first = true;\n let lastAppended = \"\";\n const renderer = new StreamingMarkdownRenderer();\n\n /**\n * Helper to flush markdown text delta to the stream.\n * Handles first-append token passing and empty-delta skipping.\n */\n const flushMarkdownDelta = async (delta: string): Promise<void> => {\n if (delta.length === 0) {\n return;\n }\n if (first) {\n // Pass token on first append so the streamer uses it for all subsequent calls\n // biome-ignore lint/suspicious/noExplicitAny: ChatStreamer types don't include token\n await streamer.append({ markdown_text: delta, token } as any);\n first = false;\n } else {\n await streamer.append({ markdown_text: delta });\n }\n };\n\n /**\n * Helper to send a structured chunk (task_update, plan_update, etc.)\n * directly to Slack's streaming API. Any buffered markdown text is\n * flushed first to maintain correct ordering.\n *\n * If the Slack API rejects the chunk (e.g. missing assistant:write scope,\n * older @slack/web-api version, or Assistant features not enabled in the\n * app manifest), the error is logged and the chunk is silently skipped.\n * Text streaming continues unaffected.\n */\n let structuredChunksSupported = true;\n const sendStructuredChunk = async (chunk: StreamChunk): Promise<void> => {\n if (!structuredChunksSupported) {\n return;\n }\n\n // Flush any buffered markdown before sending the structured chunk\n const committable = renderer.getCommittableText();\n const delta = committable.slice(lastAppended.length);\n await flushMarkdownDelta(delta);\n lastAppended = committable;\n\n try {\n // Send the chunk directly — Slack's API accepts chunks array\n if (first) {\n // biome-ignore lint/suspicious/noExplicitAny: ChatStreamer types don't include token or chunks\n await streamer.append({ chunks: [chunk], token } as any);\n first = false;\n } else {\n // biome-ignore lint/suspicious/noExplicitAny: chunks not in ChatAppendStreamArguments for older @slack/web-api\n await streamer.append({ chunks: [chunk] } as any);\n }\n } catch (error) {\n // Structured chunks may fail if the app doesn't have the required\n // Assistant scopes/features. Disable for the rest of this stream\n // to avoid repeated failures and log once.\n structuredChunksSupported = false;\n this.logger.warn(\n \"Structured streaming chunk failed, falling back to text-only streaming. \" +\n \"Ensure your Slack app manifest includes assistant_view, assistant:write scope, \" +\n \"and @slack/web-api >= 7.14.0\",\n { chunkType: chunk.type, error }\n );\n }\n };\n\n const pushTextAndFlush = async (text: string): Promise<void> => {\n renderer.push(text);\n const committable = renderer.getCommittableText();\n const delta = committable.slice(lastAppended.length);\n await flushMarkdownDelta(delta);\n lastAppended = committable;\n };\n\n for await (const chunk of textStream) {\n if (typeof chunk === \"string\") {\n await pushTextAndFlush(chunk);\n } else if (chunk.type === \"markdown_text\") {\n await pushTextAndFlush(chunk.text);\n } else {\n // Structured chunk (task_update, plan_update) — send directly to Slack\n await sendStructuredChunk(chunk);\n }\n }\n\n // Flush any remaining buffered content (e.g. held table rows at end of stream).\n renderer.finish();\n const finalCommittable = renderer.getCommittableText();\n const finalDelta = finalCommittable.slice(lastAppended.length);\n await flushMarkdownDelta(finalDelta);\n\n const result = await streamer.stop(\n // biome-ignore lint/suspicious/noExplicitAny: stopBlocks are platform-specific Block Kit elements\n options?.stopBlocks ? { blocks: options.stopBlocks as any[] } : undefined\n );\n const messageTs = (result.message?.ts ?? result.ts) as string;\n\n this.logger.debug(\"Slack: stream complete\", { messageId: messageTs });\n\n return {\n id: messageTs,\n threadId,\n raw: result,\n };\n }\n\n /**\n * Open a direct message conversation with a user.\n * Returns a thread ID that can be used to post messages.\n */\n async openDM(userId: string): Promise<string> {\n try {\n this.logger.debug(\"Slack API: conversations.open\", { userId });\n\n const result = await this.client.conversations.open(\n this.withToken({ users: userId })\n );\n\n if (!result.channel?.id) {\n throw new NetworkError(\n \"slack\",\n \"Failed to open DM - no channel returned\"\n );\n }\n\n const channelId = result.channel.id;\n\n this.logger.debug(\"Slack API: conversations.open response\", {\n channelId,\n ok: result.ok,\n });\n\n // Encode as thread ID (no threadTs for new DM - messages will start new threads)\n return this.encodeThreadId({\n channel: channelId,\n threadTs: \"\", // Empty threadTs indicates top-level channel messages\n });\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n async fetchMessages(\n threadId: string,\n options: FetchOptions = {}\n ): Promise<FetchResult<unknown>> {\n const { channel, threadTs } = this.decodeThreadId(threadId);\n const direction = options.direction ?? \"backward\";\n const limit = options.limit || 100;\n\n try {\n if (direction === \"forward\") {\n // Forward direction: fetch oldest messages first, cursor moves to newer\n // Uses native Slack cursor pagination which is efficient\n return await this.fetchMessagesForward(\n channel,\n threadTs,\n threadId,\n limit,\n options.cursor\n );\n }\n // Backward direction: fetch most recent messages first, cursor moves to older\n // Slack API returns oldest-first, so we need to work around this\n return await this.fetchMessagesBackward(\n channel,\n threadTs,\n threadId,\n limit,\n options.cursor\n );\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n /**\n * Fetch messages in forward direction (oldest first, efficient).\n * Uses native Slack cursor pagination.\n */\n private async fetchMessagesForward(\n channel: string,\n threadTs: string,\n threadId: string,\n limit: number,\n cursor?: string\n ): Promise<FetchResult<unknown>> {\n this.logger.debug(\"Slack API: conversations.replies (forward)\", {\n channel,\n threadTs,\n limit,\n cursor,\n });\n\n const result = await this.client.conversations.replies(\n this.withToken({\n channel,\n ts: threadTs,\n limit,\n cursor,\n })\n );\n\n const slackMessages = (result.messages || []) as SlackEvent[];\n const nextCursor = (\n result as { response_metadata?: { next_cursor?: string } }\n ).response_metadata?.next_cursor;\n\n this.logger.debug(\"Slack API: conversations.replies response\", {\n messageCount: slackMessages.length,\n ok: result.ok,\n hasNextCursor: !!nextCursor,\n });\n\n const messages = await Promise.all(\n slackMessages.map((msg) => this.parseSlackMessage(msg, threadId))\n );\n\n return {\n messages,\n nextCursor: nextCursor || undefined,\n };\n }\n\n /**\n * Fetch messages in backward direction (most recent first).\n *\n * Slack's API returns oldest-first, so for backward direction we:\n * 1. Use `latest` parameter to fetch messages before a timestamp (cursor)\n * 2. Fetch up to 1000 messages (API limit) and take the last N\n * 3. Return messages in chronological order (oldest first within the page)\n *\n * Note: For very large threads (>1000 messages), the first backward call\n * may not return the absolute most recent messages. This is a Slack API limitation.\n */\n private async fetchMessagesBackward(\n channel: string,\n threadTs: string,\n threadId: string,\n limit: number,\n cursor?: string\n ): Promise<FetchResult<unknown>> {\n // Cursor is a timestamp - fetch messages before this time\n // For the initial call (no cursor), we want the most recent messages\n const latest = cursor || undefined;\n\n this.logger.debug(\"Slack API: conversations.replies (backward)\", {\n channel,\n threadTs,\n limit,\n latest,\n });\n\n // Fetch a larger batch to ensure we can return the last `limit` messages\n // Slack API max is 1000 messages per request\n const fetchLimit = Math.min(1000, Math.max(limit * 2, 200));\n\n const result = await this.client.conversations.replies(\n this.withToken({\n channel,\n ts: threadTs,\n limit: fetchLimit,\n latest,\n inclusive: false, // Don't include the cursor message itself\n })\n );\n\n const slackMessages = (result.messages || []) as SlackEvent[];\n\n this.logger.debug(\"Slack API: conversations.replies response (backward)\", {\n messageCount: slackMessages.length,\n ok: result.ok,\n hasMore: result.has_more,\n });\n\n // If we have more messages than requested, take the last `limit`\n // This gives us the most recent messages\n const startIndex = Math.max(0, slackMessages.length - limit);\n const selectedMessages = slackMessages.slice(startIndex);\n\n const messages = await Promise.all(\n selectedMessages.map((msg) => this.parseSlackMessage(msg, threadId))\n );\n\n // For backward pagination, nextCursor points to older messages\n // Use the timestamp of the oldest message we're NOT returning\n let nextCursor: string | undefined;\n if (startIndex > 0 || result.has_more) {\n // There are more (older) messages available\n // Use the timestamp of the oldest message in our selection as the cursor\n const oldestSelected = selectedMessages[0];\n if (oldestSelected?.ts) {\n nextCursor = oldestSelected.ts;\n }\n }\n\n return {\n messages,\n nextCursor,\n };\n }\n\n async fetchThread(threadId: string): Promise<ThreadInfo> {\n const { channel, threadTs } = this.decodeThreadId(threadId);\n\n try {\n this.logger.debug(\"Slack API: conversations.info\", { channel });\n\n const result = await this.client.conversations.info(\n this.withToken({ channel })\n );\n const channelInfo = result.channel as { name?: string } | undefined;\n\n this.logger.debug(\"Slack API: conversations.info response\", {\n channelName: channelInfo?.name,\n ok: result.ok,\n });\n\n return {\n id: threadId,\n channelId: channel,\n channelName: channelInfo?.name,\n metadata: {\n threadTs,\n channel: result.channel,\n },\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n /**\n * Fetch a single message by ID (timestamp).\n */\n async fetchMessage(\n threadId: string,\n messageId: string\n ): Promise<Message<unknown> | null> {\n const { channel, threadTs } = this.decodeThreadId(threadId);\n\n try {\n const result = await this.client.conversations.replies(\n this.withToken({\n channel,\n ts: threadTs,\n oldest: messageId,\n inclusive: true,\n limit: 1,\n })\n );\n\n const messages = (result.messages || []) as SlackEvent[];\n const target = messages.find((msg) => msg.ts === messageId);\n if (!target) {\n return null;\n }\n\n return this.parseSlackMessage(target, threadId);\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n encodeThreadId(platformData: SlackThreadId): string {\n return `slack:${platformData.channel}:${platformData.threadTs}`;\n }\n\n /**\n * Check if a thread is a direct message conversation.\n * Slack DM channel IDs start with 'D'.\n */\n isDM(threadId: string): boolean {\n const { channel } = this.decodeThreadId(threadId);\n return channel.startsWith(\"D\");\n }\n\n decodeThreadId(threadId: string): SlackThreadId {\n const parts = threadId.split(\":\");\n if (parts.length < 2 || parts.length > 3 || parts[0] !== \"slack\") {\n throw new ValidationError(\n \"slack\",\n `Invalid Slack thread ID: ${threadId}`\n );\n }\n return {\n channel: parts[1] as string,\n threadTs: parts.length === 3 ? (parts[2] as string) : \"\",\n };\n }\n\n parseMessage(raw: SlackEvent): Message<unknown> {\n const event = raw;\n const threadTs = event.thread_ts || event.ts || \"\";\n const threadId = this.encodeThreadId({\n channel: event.channel || \"\",\n threadTs,\n });\n // Use synchronous version without user lookup for interface compliance\n return this.parseSlackMessageSync(event, threadId);\n }\n\n /**\n * Synchronous message parsing without user lookup.\n * Used for parseMessage interface - falls back to user ID for username.\n */\n private parseSlackMessageSync(\n event: SlackEvent,\n threadId: string\n ): Message<unknown> {\n const isMe = this.isMessageFromSelf(event);\n\n const text = event.text || \"\";\n // Without async lookup, fall back to user ID for human users\n const userName = event.username || event.user || \"unknown\";\n const fullName = event.username || event.user || \"unknown\";\n\n return new Message({\n id: event.ts || \"\",\n threadId,\n text: this.formatConverter.extractPlainText(text),\n formatted: this.formatConverter.toAst(text),\n raw: event,\n author: {\n userId: event.user || event.bot_id || \"unknown\",\n userName,\n fullName,\n isBot: !!event.bot_id,\n isMe,\n },\n metadata: {\n dateSent: new Date(Number.parseFloat(event.ts || \"0\") * 1000),\n edited: !!event.edited,\n editedAt: event.edited\n ? new Date(Number.parseFloat(event.edited.ts) * 1000)\n : undefined,\n },\n attachments: (event.files || []).map((file) =>\n this.createAttachment(file)\n ),\n links: this.extractLinks(event),\n });\n }\n\n // =========================================================================\n // Channel-level methods\n // =========================================================================\n\n /**\n * Derive channel ID from a Slack thread ID.\n * Slack thread IDs are \"slack:CHANNEL:THREAD_TS\", channel ID is \"slack:CHANNEL\".\n */\n channelIdFromThreadId(threadId: string): string {\n const { channel } = this.decodeThreadId(threadId);\n return `slack:${channel}`;\n }\n\n /**\n * Fetch channel-level messages (conversations.history, not thread replies).\n */\n async fetchChannelMessages(\n channelId: string,\n options: FetchOptions = {}\n ): Promise<FetchResult<unknown>> {\n // Channel ID format: \"slack:CHANNEL\"\n const channel = channelId.split(\":\")[1];\n if (!channel) {\n throw new ValidationError(\n \"slack\",\n `Invalid Slack channel ID: ${channelId}`\n );\n }\n\n const direction = options.direction ?? \"backward\";\n const limit = options.limit || 100;\n\n try {\n if (direction === \"forward\") {\n return await this.fetchChannelMessagesForward(\n channel,\n limit,\n options.cursor\n );\n }\n return await this.fetchChannelMessagesBackward(\n channel,\n limit,\n options.cursor\n );\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n private async fetchChannelMessagesForward(\n channel: string,\n limit: number,\n cursor?: string\n ): Promise<FetchResult<unknown>> {\n this.logger.debug(\"Slack API: conversations.history (forward)\", {\n channel,\n limit,\n cursor,\n });\n\n const result = await this.client.conversations.history(\n this.withToken({\n channel,\n limit,\n oldest: cursor,\n inclusive: cursor ? false : undefined,\n })\n );\n\n const slackMessages = ((result.messages || []) as SlackEvent[]).reverse(); // Slack returns newest-first, we want oldest-first\n\n const messages = await Promise.all(\n slackMessages.map((msg) => {\n const threadTs = msg.thread_ts || msg.ts || \"\";\n const threadId = `slack:${channel}:${threadTs}`;\n return this.parseSlackMessage(msg, threadId, {\n skipSelfMention: false,\n });\n })\n );\n\n // For forward pagination, cursor points to newer messages\n let nextCursor: string | undefined;\n if (result.has_more && slackMessages.length > 0) {\n const newest = slackMessages.at(-1);\n if (newest?.ts) {\n nextCursor = newest.ts;\n }\n }\n\n return {\n messages,\n nextCursor,\n };\n }\n\n private async fetchChannelMessagesBackward(\n channel: string,\n limit: number,\n cursor?: string\n ): Promise<FetchResult<unknown>> {\n this.logger.debug(\"Slack API: conversations.history (backward)\", {\n channel,\n limit,\n cursor,\n });\n\n const result = await this.client.conversations.history(\n this.withToken({\n channel,\n limit,\n latest: cursor,\n inclusive: cursor ? false : undefined,\n })\n );\n\n const slackMessages = (result.messages || []) as SlackEvent[];\n // Slack returns newest-first for conversations.history; reverse for chronological\n const chronological = [...slackMessages].reverse();\n\n const messages = await Promise.all(\n chronological.map((msg) => {\n const threadTs = msg.thread_ts || msg.ts || \"\";\n const threadId = `slack:${channel}:${threadTs}`;\n return this.parseSlackMessage(msg, threadId, {\n skipSelfMention: false,\n });\n })\n );\n\n // For backward pagination, cursor points to older messages\n let nextCursor: string | undefined;\n if (result.has_more && chronological.length > 0) {\n const oldest = chronological[0];\n if (oldest?.ts) {\n nextCursor = oldest.ts;\n }\n }\n\n return {\n messages,\n nextCursor,\n };\n }\n\n /**\n * List threads in a Slack channel.\n * Fetches channel history and filters for messages with replies.\n */\n async listThreads(\n channelId: string,\n options: ListThreadsOptions = {}\n ): Promise<ListThreadsResult<unknown>> {\n const channel = channelId.split(\":\")[1];\n if (!channel) {\n throw new ValidationError(\n \"slack\",\n `Invalid Slack channel ID: ${channelId}`\n );\n }\n\n const limit = options.limit || 50;\n\n try {\n this.logger.debug(\"Slack API: conversations.history (listThreads)\", {\n channel,\n limit,\n cursor: options.cursor,\n });\n\n const result = await this.client.conversations.history(\n this.withToken({\n channel,\n limit: Math.min(limit * 3, 200), // Fetch extra since not all have threads\n cursor: options.cursor,\n })\n );\n\n const slackMessages = (result.messages || []) as SlackEvent[];\n\n // Filter messages that have replies (they are thread parents)\n const threadMessages = slackMessages.filter(\n (msg) => (msg.reply_count ?? 0) > 0\n );\n\n // Take up to `limit` threads\n const selected = threadMessages.slice(0, limit);\n\n const threads: ThreadSummary[] = await Promise.all(\n selected.map(async (msg) => {\n const threadTs = msg.ts || \"\";\n const threadId = `slack:${channel}:${threadTs}`;\n const rootMessage = await this.parseSlackMessage(msg, threadId, {\n skipSelfMention: false,\n });\n\n return {\n id: threadId,\n rootMessage,\n replyCount: msg.reply_count,\n lastReplyAt: msg.latest_reply\n ? new Date(Number.parseFloat(msg.latest_reply) * 1000)\n : undefined,\n };\n })\n );\n\n const nextCursor = (\n result as { response_metadata?: { next_cursor?: string } }\n ).response_metadata?.next_cursor;\n\n return {\n threads,\n nextCursor: nextCursor || undefined,\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n /**\n * Fetch Slack channel info/metadata.\n */\n async fetchChannelInfo(channelId: string): Promise<ChannelInfo> {\n const channel = channelId.split(\":\")[1];\n if (!channel) {\n throw new ValidationError(\n \"slack\",\n `Invalid Slack channel ID: ${channelId}`\n );\n }\n\n try {\n this.logger.debug(\"Slack API: conversations.info (channel)\", { channel });\n\n const result = await this.client.conversations.info(\n this.withToken({ channel })\n );\n\n const info = result.channel as {\n id?: string;\n name?: string;\n is_im?: boolean;\n is_mpim?: boolean;\n num_members?: number;\n purpose?: { value?: string };\n topic?: { value?: string };\n };\n\n return {\n id: channelId,\n name: info?.name ? `#${info.name}` : undefined,\n isDM: Boolean(info?.is_im || info?.is_mpim),\n memberCount: info?.num_members,\n metadata: {\n purpose: info?.purpose?.value,\n topic: info?.topic?.value,\n },\n };\n } catch (error) {\n this.handleSlackError(error);\n }\n }\n\n /**\n * Post a top-level message to a channel (not in a thread).\n */\n async postChannelMessage(\n channelId: string,\n message: AdapterPostableMessage\n ): Promise<RawMessage<unknown>> {\n const channel = channelId.split(\":\")[1];\n if (!channel) {\n throw new ValidationError(\n \"slack\",\n `Invalid Slack channel ID: ${channelId}`\n );\n }\n\n // Use the existing postMessage logic but with no threadTs\n // Build a synthetic thread ID with empty threadTs\n const syntheticThreadId = `slack:${channel}:`;\n return await this.postMessage(syntheticThreadId, message);\n }\n\n renderFormatted(content: FormattedContent): string {\n return this.formatConverter.fromAst(content);\n }\n\n /**\n * Check if a Slack event is from this bot.\n *\n * Slack messages can come from:\n * - User messages: have `user` field (U_xxx format)\n * - Bot messages: have `bot_id` field (B_xxx format)\n *\n * We check both because:\n * - _botUserId is the user ID (U_xxx) - matches event.user\n * - _botId is the bot ID (B_xxx) - matches event.bot_id\n */\n private isMessageFromSelf(event: SlackEvent): boolean {\n // Check request context first (multi-workspace)\n const ctx = this.requestContext.getStore();\n if (ctx?.botUserId && event.user === ctx.botUserId) {\n return true;\n }\n\n // Primary check: user ID match (for messages sent as the bot user)\n if (this._botUserId && event.user === this._botUserId) {\n return true;\n }\n\n // Secondary check: bot ID match (for bot_message subtypes)\n if (this._botId && event.bot_id === this._botId) {\n return true;\n }\n\n return false;\n }\n\n private handleSlackError(error: unknown): never {\n const slackError = error as { data?: { error?: string }; code?: string };\n\n if (\n slackError.code === \"slack_webapi_platform_error\" &&\n slackError.data?.error === \"ratelimited\"\n ) {\n throw new AdapterRateLimitError(\"slack\");\n }\n\n throw error;\n }\n\n /**\n * Encode response_url and userId into messageId for ephemeral messages.\n * This allows edit/delete operations to work via response_url.\n */\n private encodeEphemeralMessageId(\n messageTs: string,\n responseUrl: string,\n userId: string\n ): string {\n const data = JSON.stringify({ responseUrl, userId });\n return `ephemeral:${messageTs}:${btoa(data)}`;\n }\n\n /**\n * Decode ephemeral messageId to extract messageTs, responseUrl, and userId.\n * Returns null if the messageId is not an ephemeral encoding.\n */\n private decodeEphemeralMessageId(\n messageId: string\n ): { messageTs: string; responseUrl: string; userId: string } | null {\n if (!messageId.startsWith(\"ephemeral:\")) {\n return null;\n }\n const parts = messageId.split(\":\");\n if (parts.length < 3) {\n return null;\n }\n const messageTs = parts[1];\n const encodedData = parts.slice(2).join(\":\");\n try {\n const decoded = atob(encodedData);\n try {\n const data = JSON.parse(decoded);\n if (data.responseUrl && data.userId) {\n return {\n messageTs,\n responseUrl: data.responseUrl,\n userId: data.userId,\n };\n }\n } catch {\n return { messageTs, responseUrl: decoded, userId: \"\" };\n }\n return null;\n } catch {\n this.logger.warn(\"Failed to decode ephemeral messageId\", { messageId });\n return null;\n }\n }\n\n /**\n * Send a request to Slack's response_url to modify an ephemeral message.\n */\n private async sendToResponseUrl(\n responseUrl: string,\n action: \"replace\" | \"delete\",\n options?: { message?: AdapterPostableMessage; threadTs?: string }\n ): Promise<Record<string, unknown>> {\n let payload: Record<string, unknown>;\n\n if (action === \"delete\") {\n payload = { delete_original: true };\n } else {\n const message = options?.message;\n if (!message) {\n throw new ValidationError(\n \"slack\",\n \"Message required for replace action\"\n );\n }\n const card = extractCard(message);\n if (card) {\n payload = {\n replace_original: true,\n text: cardToFallbackText(card),\n blocks: cardToBlockKit(card),\n };\n } else {\n const tableResult = this.renderWithTableBlocks(message);\n if (tableResult) {\n payload = {\n replace_original: true,\n text: tableResult.text,\n blocks: tableResult.blocks,\n };\n } else {\n payload = {\n replace_original: true,\n text: convertEmojiPlaceholders(\n this.formatConverter.renderPostable(message),\n \"slack\"\n ),\n };\n }\n }\n if (options?.threadTs) {\n payload.thread_ts = options.threadTs;\n }\n }\n this.logger.debug(\"Slack response_url request\", {\n action,\n threadTs: options?.threadTs,\n });\n const response = await fetch(responseUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n this.logger.error(\"Slack response_url failed\", {\n action,\n status: response.status,\n body: errorText,\n });\n throw new NetworkError(\n \"slack\",\n `Failed to ${action} via response_url: ${errorText}`\n );\n }\n const responseText = await response.text();\n if (responseText) {\n try {\n return JSON.parse(responseText) as Record<string, unknown>;\n } catch {\n return { raw: responseText };\n }\n }\n return {};\n }\n}\n\nexport function createSlackAdapter(config?: SlackAdapterConfig): SlackAdapter {\n return new SlackAdapter(config ?? {});\n}\n\n// Re-export card converter for advanced use\nexport { cardToBlockKit, cardToFallbackText } from \"./cards\";\nexport type { EncryptedTokenData } from \"./crypto\";\n// Re-export crypto utilities for advanced use\nexport { decodeKey } from \"./crypto\";\n// Re-export format converter for advanced use\nexport {\n SlackFormatConverter,\n SlackFormatConverter as SlackMarkdownConverter,\n} from \"./markdown\";\n","/**\n * Slack Block Kit converter for cross-platform cards.\n *\n * Converts CardElement to Slack Block Kit blocks.\n * @see https://api.slack.com/block-kit\n */\n\nimport {\n createEmojiConverter,\n mapButtonStyle,\n cardToFallbackText as sharedCardToFallbackText,\n} from \"@chat-adapter/shared\";\nimport type {\n ActionsElement,\n ButtonElement,\n CardChild,\n CardElement,\n DividerElement,\n FieldsElement,\n ImageElement,\n LinkButtonElement,\n LinkElement,\n RadioSelectElement,\n SectionElement,\n SelectElement,\n TableElement,\n TextElement,\n} from \"chat\";\nimport { cardChildToFallbackText, tableElementToAscii } from \"chat\";\n\n/**\n * Convert emoji placeholders in text to Slack format.\n */\nconst convertEmoji = createEmojiConverter(\"slack\");\n\n// Slack Block Kit types (simplified)\nexport interface SlackBlock {\n block_id?: string;\n type: string;\n [key: string]: unknown;\n}\n\ninterface SlackTextObject {\n emoji?: boolean;\n text: string;\n type: \"plain_text\" | \"mrkdwn\";\n}\n\ninterface SlackButtonElement {\n action_id: string;\n style?: \"primary\" | \"danger\";\n text: SlackTextObject;\n type: \"button\";\n value?: string;\n}\n\ninterface SlackLinkButtonElement {\n action_id: string;\n style?: \"primary\" | \"danger\";\n text: SlackTextObject;\n type: \"button\";\n url: string;\n}\n\ninterface SlackOptionObject {\n description?: SlackTextObject;\n text: SlackTextObject;\n value: string;\n}\n\ninterface SlackSelectElement {\n action_id: string;\n initial_option?: SlackOptionObject;\n options: SlackOptionObject[];\n placeholder?: SlackTextObject;\n type: \"static_select\";\n}\n\ninterface SlackRadioSelectElement {\n action_id: string;\n initial_option?: SlackOptionObject;\n options: SlackOptionObject[];\n type: \"radio_buttons\";\n}\n\n/**\n * Convert a CardElement to Slack Block Kit blocks.\n */\nexport function cardToBlockKit(card: CardElement): SlackBlock[] {\n const blocks: SlackBlock[] = [];\n\n // Add header if title is present\n if (card.title) {\n blocks.push({\n type: \"header\",\n text: {\n type: \"plain_text\",\n text: convertEmoji(card.title),\n emoji: true,\n },\n });\n }\n\n // Add subtitle as context if present\n if (card.subtitle) {\n blocks.push({\n type: \"context\",\n elements: [\n {\n type: \"mrkdwn\",\n text: convertEmoji(card.subtitle),\n },\n ],\n });\n }\n\n // Add header image if present\n if (card.imageUrl) {\n blocks.push({\n type: \"image\",\n image_url: card.imageUrl,\n alt_text: card.title || \"Card image\",\n });\n }\n\n // Convert children — track whether native table block has been used\n // (Slack allows at most one table block per message)\n const state = { usedNativeTable: false };\n for (const child of card.children) {\n const childBlocks = convertChildToBlocks(child, state);\n blocks.push(...childBlocks);\n }\n\n return blocks;\n}\n\n/**\n * Convert a card child element to Slack blocks.\n */\nfunction convertChildToBlocks(\n child: CardChild,\n state: { usedNativeTable: boolean }\n): SlackBlock[] {\n switch (child.type) {\n case \"text\":\n return [convertTextToBlock(child)];\n case \"image\":\n return [convertImageToBlock(child)];\n case \"divider\":\n return [convertDividerToBlock(child)];\n case \"actions\":\n return [convertActionsToBlock(child)];\n case \"section\":\n return convertSectionToBlocks(child, state);\n case \"fields\":\n return [convertFieldsToBlock(child)];\n case \"link\":\n return [convertLinkToBlock(child)];\n case \"table\":\n return convertTableToBlocks(child, state);\n default: {\n const text = cardChildToFallbackText(child);\n if (text) {\n return [{ type: \"section\", text: { type: \"mrkdwn\", text } }];\n }\n return [];\n }\n }\n}\n\n/** Convert standard Markdown formatting to Slack mrkdwn */\nfunction markdownToMrkdwn(text: string): string {\n // **bold** → *bold*\n return text.replace(/\\*\\*(.+?)\\*\\*/g, \"*$1*\");\n}\n\nexport function convertTextToBlock(element: TextElement): SlackBlock {\n const text = markdownToMrkdwn(convertEmoji(element.content));\n let formattedText = text;\n\n // Apply style\n if (element.style === \"bold\") {\n formattedText = `*${text}*`;\n } else if (element.style === \"muted\") {\n // Slack doesn't have a muted style, use context block\n return {\n type: \"context\",\n elements: [{ type: \"mrkdwn\", text }],\n };\n }\n\n return {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: formattedText,\n },\n };\n}\n\nfunction convertLinkToBlock(element: LinkElement): SlackBlock {\n return {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `<${element.url}|${convertEmoji(element.label)}>`,\n },\n };\n}\n\nfunction convertImageToBlock(element: ImageElement): SlackBlock {\n return {\n type: \"image\",\n image_url: element.url,\n alt_text: element.alt || \"Image\",\n };\n}\n\nfunction convertDividerToBlock(_element: DividerElement): SlackBlock {\n return { type: \"divider\" };\n}\n\ntype SlackActionElement =\n | SlackButtonElement\n | SlackLinkButtonElement\n | SlackSelectElement\n | SlackRadioSelectElement;\n\nfunction convertActionsToBlock(element: ActionsElement): SlackBlock {\n const elements: SlackActionElement[] = element.children.map((child) => {\n if (child.type === \"link-button\") {\n return convertLinkButtonToElement(child);\n }\n if (child.type === \"select\") {\n return convertSelectToElement(child);\n }\n if (child.type === \"radio_select\") {\n return convertRadioSelectToElement(child);\n }\n return convertButtonToElement(child);\n });\n\n return {\n type: \"actions\",\n elements,\n };\n}\n\nfunction convertButtonToElement(button: ButtonElement): SlackButtonElement {\n const element: SlackButtonElement = {\n type: \"button\",\n text: {\n type: \"plain_text\",\n text: convertEmoji(button.label),\n emoji: true,\n },\n action_id: button.id,\n };\n\n if (button.value) {\n element.value = button.value;\n }\n\n const style = mapButtonStyle(button.style, \"slack\");\n if (style) {\n element.style = style as \"primary\" | \"danger\";\n }\n\n return element;\n}\n\nfunction convertLinkButtonToElement(\n button: LinkButtonElement\n): SlackLinkButtonElement {\n const element: SlackLinkButtonElement = {\n type: \"button\",\n text: {\n type: \"plain_text\",\n text: convertEmoji(button.label),\n emoji: true,\n },\n action_id: `link-${button.url.slice(0, 200)}`,\n url: button.url,\n };\n\n const style = mapButtonStyle(button.style, \"slack\");\n if (style) {\n element.style = style as \"primary\" | \"danger\";\n }\n\n return element;\n}\n\nfunction convertSelectToElement(select: SelectElement): SlackSelectElement {\n const options: SlackOptionObject[] = select.options.map((opt) => {\n const option: SlackOptionObject = {\n text: { type: \"plain_text\" as const, text: convertEmoji(opt.label) },\n value: opt.value,\n };\n if (opt.description) {\n option.description = {\n type: \"plain_text\",\n text: convertEmoji(opt.description),\n };\n }\n return option;\n });\n const element: SlackSelectElement = {\n type: \"static_select\",\n action_id: select.id,\n options,\n };\n if (select.placeholder) {\n element.placeholder = {\n type: \"plain_text\",\n text: convertEmoji(select.placeholder),\n };\n }\n if (select.initialOption) {\n const initialOpt = options.find((o) => o.value === select.initialOption);\n if (initialOpt) {\n element.initial_option = initialOpt;\n }\n }\n return element;\n}\n\nfunction convertRadioSelectToElement(\n radioSelect: RadioSelectElement\n): SlackRadioSelectElement {\n const limitedOptions = radioSelect.options.slice(0, 10);\n const options: SlackOptionObject[] = limitedOptions.map((opt) => {\n const option: SlackOptionObject = {\n text: { type: \"mrkdwn\" as const, text: convertEmoji(opt.label) },\n value: opt.value,\n };\n if (opt.description) {\n option.description = {\n type: \"mrkdwn\",\n text: convertEmoji(opt.description),\n };\n }\n return option;\n });\n\n const element: SlackRadioSelectElement = {\n type: \"radio_buttons\",\n action_id: radioSelect.id,\n options,\n };\n if (radioSelect.initialOption) {\n const initialOpt = options.find(\n (o) => o.value === radioSelect.initialOption\n );\n if (initialOpt) {\n element.initial_option = initialOpt;\n }\n }\n return element;\n}\n\n/**\n * Convert a table element to Slack Block Kit blocks.\n * Uses Block Kit Table block for tables within limits (100 rows, 20 columns),\n * falls back to code block for larger tables.\n */\n/**\n * Convert a table element to Slack Block Kit blocks.\n * Uses the native table block with first-row-as-headers schema.\n * Falls back to code block for tables exceeding Slack limits (100 rows, 20 columns)\n * or when a native table block has already been used in this message.\n * @see https://docs.slack.dev/reference/block-kit/blocks/table-block/\n */\nfunction convertTableToBlocks(\n element: TableElement,\n state: { usedNativeTable: boolean }\n): SlackBlock[] {\n const MAX_ROWS = 100;\n const MAX_COLS = 20;\n\n if (\n state.usedNativeTable ||\n element.rows.length > MAX_ROWS ||\n element.headers.length > MAX_COLS\n ) {\n // Fall back to ASCII table in a code block\n return [\n {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `\\`\\`\\`\\n${tableElementToAscii(element.headers, element.rows)}\\n\\`\\`\\``,\n },\n },\n ];\n }\n\n state.usedNativeTable = true;\n\n // First row is headers, subsequent rows are data\n const headerRow = element.headers.map((header) => ({\n type: \"raw_text\" as const,\n text: convertEmoji(header),\n }));\n\n const dataRows = element.rows.map((row) =>\n row.map((cell) => ({\n type: \"raw_text\" as const,\n text: convertEmoji(cell),\n }))\n );\n\n return [\n {\n type: \"table\",\n rows: [headerRow, ...dataRows],\n },\n ];\n}\n\nfunction convertSectionToBlocks(\n element: SectionElement,\n state: { usedNativeTable: boolean }\n): SlackBlock[] {\n // Flatten section children into blocks\n const blocks: SlackBlock[] = [];\n for (const child of element.children) {\n blocks.push(...convertChildToBlocks(child, state));\n }\n return blocks;\n}\n\nexport function convertFieldsToBlock(element: FieldsElement): SlackBlock {\n const fields: SlackTextObject[] = [];\n\n for (const field of element.children) {\n // Add label and value as separate field items\n fields.push({\n type: \"mrkdwn\",\n text: `*${markdownToMrkdwn(convertEmoji(field.label))}*\\n${markdownToMrkdwn(convertEmoji(field.value))}`,\n });\n }\n\n return {\n type: \"section\",\n fields,\n };\n}\n\n/**\n * Generate fallback text from a card element.\n * Used when blocks aren't supported or for notifications.\n */\nexport function cardToFallbackText(card: CardElement): string {\n return sharedCardToFallbackText(card, {\n boldFormat: \"*\",\n lineBreak: \"\\n\",\n platform: \"slack\",\n });\n}\n","import crypto from \"node:crypto\";\n\nconst ALGORITHM = \"aes-256-gcm\";\nconst IV_LENGTH = 12;\nconst AUTH_TAG_LENGTH = 16;\nconst HEX_KEY_PATTERN = /^[0-9a-fA-F]{64}$/;\n\nexport interface EncryptedTokenData {\n data: string;\n iv: string;\n tag: string;\n}\n\nexport function encryptToken(\n plaintext: string,\n key: Buffer\n): EncryptedTokenData {\n const iv = crypto.randomBytes(IV_LENGTH);\n const cipher = crypto.createCipheriv(ALGORITHM, key, iv, {\n authTagLength: AUTH_TAG_LENGTH,\n });\n const ciphertext = Buffer.concat([\n cipher.update(plaintext, \"utf8\"),\n cipher.final(),\n ]);\n const tag = cipher.getAuthTag();\n\n return {\n iv: iv.toString(\"base64\"),\n data: ciphertext.toString(\"base64\"),\n tag: tag.toString(\"base64\"),\n };\n}\n\nexport function decryptToken(\n encrypted: EncryptedTokenData,\n key: Buffer\n): string {\n const iv = Buffer.from(encrypted.iv, \"base64\");\n const ciphertext = Buffer.from(encrypted.data, \"base64\");\n const tag = Buffer.from(encrypted.tag, \"base64\");\n\n const decipher = crypto.createDecipheriv(ALGORITHM, key, iv, {\n authTagLength: AUTH_TAG_LENGTH,\n });\n decipher.setAuthTag(tag);\n\n return Buffer.concat([\n decipher.update(ciphertext),\n decipher.final(),\n ]).toString(\"utf8\");\n}\n\nexport function isEncryptedTokenData(\n value: unknown\n): value is EncryptedTokenData {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const obj = value as Record<string, unknown>;\n return (\n typeof obj.iv === \"string\" &&\n typeof obj.data === \"string\" &&\n typeof obj.tag === \"string\"\n );\n}\n\nexport function decodeKey(rawKey: string): Buffer {\n const trimmed = rawKey.trim();\n // Detect hex encoding: 64 hex chars = 32 bytes\n const isHex = HEX_KEY_PATTERN.test(trimmed);\n const key = Buffer.from(trimmed, isHex ? \"hex\" : \"base64\");\n if (key.length !== 32) {\n throw new Error(\n `Encryption key must decode to exactly 32 bytes (received ${key.length}). Use a 64-char hex string or 44-char base64 string.`\n );\n }\n return key;\n}\n","/**\n * Slack-specific format conversion using AST-based parsing.\n *\n * Slack uses \"mrkdwn\" format which is similar but not identical to markdown:\n * - Bold: *text* (not **text**)\n * - Italic: _text_ (same)\n * - Strikethrough: ~text~ (not ~~text~~)\n * - Links: <url|text> (not [text](url))\n * - User mentions: <@U123>\n * - Channel mentions: <#C123|name>\n */\n\nimport {\n type AdapterPostableMessage,\n BaseFormatConverter,\n type Content,\n getNodeChildren,\n isBlockquoteNode,\n isCodeNode,\n isDeleteNode,\n isEmphasisNode,\n isInlineCodeNode,\n isLinkNode,\n isListNode,\n isParagraphNode,\n isStrongNode,\n isTableNode,\n isTextNode,\n type MdastTable,\n parseMarkdown,\n type Root,\n tableToAscii,\n} from \"chat\";\nimport type { SlackBlock } from \"./cards\";\n\nexport class SlackFormatConverter extends BaseFormatConverter {\n /**\n * Convert @mentions to Slack format in plain text.\n * @name → <@name>\n */\n private convertMentionsToSlack(text: string): string {\n return text.replace(/(?<!<)@(\\w+)/g, \"<@$1>\");\n }\n\n /**\n * Override renderPostable to convert @mentions in plain strings.\n */\n override renderPostable(message: AdapterPostableMessage): string {\n if (typeof message === \"string\") {\n return this.convertMentionsToSlack(message);\n }\n if (\"raw\" in message) {\n return this.convertMentionsToSlack(message.raw);\n }\n if (\"markdown\" in message) {\n return this.fromAst(parseMarkdown(message.markdown));\n }\n if (\"ast\" in message) {\n return this.fromAst(message.ast);\n }\n return \"\";\n }\n\n /**\n * Render an AST to Slack mrkdwn format.\n */\n fromAst(ast: Root): string {\n return this.fromAstWithNodeConverter(ast, (node) =>\n this.nodeToMrkdwn(node)\n );\n }\n\n /**\n * Parse Slack mrkdwn into an AST.\n */\n toAst(mrkdwn: string): Root {\n // Convert Slack mrkdwn to standard markdown string, then parse\n let markdown = mrkdwn;\n\n // User mentions: <@U123|name> -> @name or <@U123> -> @U123\n markdown = markdown.replace(/<@([A-Z0-9_]+)\\|([^>]+)>/g, \"@$2\");\n markdown = markdown.replace(/<@([A-Z0-9_]+)>/g, \"@$1\");\n\n // Channel mentions: <#C123|name> -> #name\n markdown = markdown.replace(/<#[A-Z0-9_]+\\|([^>]+)>/g, \"#$1\");\n markdown = markdown.replace(/<#([A-Z0-9_]+)>/g, \"#$1\");\n\n // Links: <url|text> -> [text](url)\n markdown = markdown.replace(/<(https?:\\/\\/[^|>]+)\\|([^>]+)>/g, \"[$2]($1)\");\n\n // Bare links: <url> -> url\n markdown = markdown.replace(/<(https?:\\/\\/[^>]+)>/g, \"$1\");\n\n // Bold: *text* -> **text** (but be careful with emphasis)\n // This is tricky because Slack uses * for bold, not emphasis\n markdown = markdown.replace(/(?<![_*\\\\])\\*([^*\\n]+)\\*(?![_*])/g, \"**$1**\");\n\n // Strikethrough: ~text~ -> ~~text~~\n markdown = markdown.replace(/(?<!~)~([^~\\n]+)~(?!~)/g, \"~~$1~~\");\n\n return parseMarkdown(markdown);\n }\n\n /**\n * Convert AST to Slack blocks, using a native table block for the first table.\n * Returns null if the AST contains no tables (caller should use regular text).\n * Slack allows at most one table block per message; additional tables use ASCII.\n */\n toBlocksWithTable(ast: Root): SlackBlock[] | null {\n const hasTable = ast.children.some((node) => isTableNode(node as Content));\n if (!hasTable) {\n return null;\n }\n\n const blocks: SlackBlock[] = [];\n let usedNativeTable = false;\n let textBuffer: string[] = [];\n\n const flushText = () => {\n if (textBuffer.length > 0) {\n const text = textBuffer.join(\"\\n\\n\");\n if (text.trim()) {\n blocks.push({\n type: \"section\",\n text: { type: \"mrkdwn\", text },\n });\n }\n textBuffer = [];\n }\n };\n\n for (const child of ast.children) {\n const node = child as Content;\n if (isTableNode(node)) {\n flushText();\n if (usedNativeTable) {\n // Additional tables fall back to ASCII in a code block\n blocks.push({\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `\\`\\`\\`\\n${tableToAscii(node)}\\n\\`\\`\\``,\n },\n });\n } else {\n blocks.push(\n mdastTableToSlackBlock(node, this.nodeToMrkdwn.bind(this))\n );\n usedNativeTable = true;\n }\n } else {\n textBuffer.push(this.nodeToMrkdwn(node));\n }\n }\n\n flushText();\n return blocks;\n }\n\n private nodeToMrkdwn(node: Content): string {\n // Use type guards for type-safe node handling\n if (isParagraphNode(node)) {\n return getNodeChildren(node)\n .map((child) => this.nodeToMrkdwn(child))\n .join(\"\");\n }\n\n if (isTextNode(node)) {\n // Convert @mentions to Slack format <@mention>\n return node.value.replace(/(?<!<)@(\\w+)/g, \"<@$1>\");\n }\n\n if (isStrongNode(node)) {\n // Markdown **text** -> Slack *text*\n const content = getNodeChildren(node)\n .map((child) => this.nodeToMrkdwn(child))\n .join(\"\");\n return `*${content}*`;\n }\n\n if (isEmphasisNode(node)) {\n // Both use _text_\n const content = getNodeChildren(node)\n .map((child) => this.nodeToMrkdwn(child))\n .join(\"\");\n return `_${content}_`;\n }\n\n if (isDeleteNode(node)) {\n // Markdown ~~text~~ -> Slack ~text~\n const content = getNodeChildren(node)\n .map((child) => this.nodeToMrkdwn(child))\n .join(\"\");\n return `~${content}~`;\n }\n\n if (isInlineCodeNode(node)) {\n return `\\`${node.value}\\``;\n }\n\n if (isCodeNode(node)) {\n return `\\`\\`\\`${node.lang || \"\"}\\n${node.value}\\n\\`\\`\\``;\n }\n\n if (isLinkNode(node)) {\n const linkText = getNodeChildren(node)\n .map((child) => this.nodeToMrkdwn(child))\n .join(\"\");\n // Markdown [text](url) -> Slack <url|text>\n return `<${node.url}|${linkText}>`;\n }\n\n if (isBlockquoteNode(node)) {\n return getNodeChildren(node)\n .map((child) => `> ${this.nodeToMrkdwn(child)}`)\n .join(\"\\n\");\n }\n\n if (isListNode(node)) {\n return this.renderList(node, 0, (child) => this.nodeToMrkdwn(child), \"•\");\n }\n\n if (node.type === \"break\") {\n return \"\\n\";\n }\n\n if (node.type === \"thematicBreak\") {\n return \"---\";\n }\n\n if (isTableNode(node)) {\n return `\\`\\`\\`\\n${tableToAscii(node)}\\n\\`\\`\\``;\n }\n\n return this.defaultNodeToText(node, (child) => this.nodeToMrkdwn(child));\n }\n}\n\n/**\n * Convert an mdast Table node to a Slack table block.\n * Uses the table block schema: first row = headers, cells are raw_text,\n * column_settings carries alignment from mdast.\n * @see https://docs.slack.dev/reference/block-kit/blocks/table-block/\n */\nfunction mdastTableToSlackBlock(\n node: MdastTable,\n cellConverter: (node: Content) => string\n): SlackBlock {\n const rows: Array<Array<{ type: \"raw_text\"; text: string }>> = [];\n\n for (const row of node.children) {\n const cells = getNodeChildren(row).map((cell) => ({\n type: \"raw_text\" as const,\n text: getNodeChildren(cell).map(cellConverter).join(\"\"),\n }));\n rows.push(cells);\n }\n\n const block: SlackBlock = { type: \"table\", rows };\n\n if (node.align) {\n const columnSettings = node.align.map(\n (a: \"left\" | \"center\" | \"right\" | null) => ({\n align: a || \"left\",\n })\n );\n block.column_settings = columnSettings;\n }\n\n return block;\n}\n\n// Backwards compatibility alias\nexport { SlackFormatConverter as SlackMarkdownConverter };\n","/**\n * Slack modal (view) converter.\n * Converts ModalElement to Slack Block Kit view format.\n */\n\nimport type {\n ModalChild,\n ModalElement,\n RadioSelectElement,\n SelectElement,\n TextInputElement,\n} from \"chat\";\nimport {\n convertFieldsToBlock,\n convertTextToBlock,\n type SlackBlock,\n} from \"./cards\";\n\nexport interface SlackView {\n blocks: SlackBlock[];\n callback_id: string;\n close?: { type: \"plain_text\"; text: string };\n notify_on_close?: boolean;\n private_metadata?: string;\n submit?: { type: \"plain_text\"; text: string };\n title: { type: \"plain_text\"; text: string };\n type: \"modal\";\n}\n\nexport interface SlackModalResponse {\n errors?: Record<string, string>;\n response_action?: \"errors\" | \"update\" | \"push\" | \"clear\";\n view?: SlackView;\n}\n\n// ============================================================================\n// Private metadata encoding\n// ============================================================================\n\nexport interface ModalMetadata {\n contextId?: string;\n privateMetadata?: string;\n}\n\n/**\n * Encode contextId and user privateMetadata into a single string\n * for Slack's private_metadata field.\n */\nexport function encodeModalMetadata(meta: ModalMetadata): string | undefined {\n if (!(meta.contextId || meta.privateMetadata)) {\n return undefined;\n }\n return JSON.stringify({ c: meta.contextId, m: meta.privateMetadata });\n}\n\n/**\n * Decode Slack's private_metadata back into contextId and user privateMetadata.\n * Falls back to treating the raw string as a plain contextId for backward compat.\n */\nexport function decodeModalMetadata(raw?: string): ModalMetadata {\n if (!raw) {\n return {};\n }\n try {\n const parsed = JSON.parse(raw);\n if (\n typeof parsed === \"object\" &&\n parsed !== null &&\n (\"c\" in parsed || \"m\" in parsed)\n ) {\n return {\n contextId: parsed.c || undefined,\n privateMetadata: parsed.m || undefined,\n };\n }\n } catch {\n // Not JSON — treat as legacy plain contextId\n }\n return { contextId: raw };\n}\n\n// ============================================================================\n// Modal view conversion\n// ============================================================================\n\nexport function modalToSlackView(\n modal: ModalElement,\n contextId?: string\n): SlackView {\n return {\n type: \"modal\",\n callback_id: modal.callbackId,\n title: { type: \"plain_text\", text: modal.title.slice(0, 24) },\n submit: modal.submitLabel\n ? { type: \"plain_text\", text: modal.submitLabel }\n : { type: \"plain_text\", text: \"Submit\" },\n close: modal.closeLabel\n ? { type: \"plain_text\", text: modal.closeLabel }\n : { type: \"plain_text\", text: \"Cancel\" },\n notify_on_close: modal.notifyOnClose,\n private_metadata: contextId,\n blocks: modal.children.map(modalChildToBlock),\n };\n}\n\nfunction modalChildToBlock(child: ModalChild): SlackBlock {\n switch (child.type) {\n case \"text_input\":\n return textInputToBlock(child);\n case \"select\":\n return selectToBlock(child);\n case \"radio_select\":\n return radioSelectToBlock(child);\n case \"text\":\n return convertTextToBlock(child);\n case \"fields\":\n return convertFieldsToBlock(child);\n default:\n throw new Error(\n `Unknown modal child type: ${(child as { type: string }).type}`\n );\n }\n}\n\nfunction textInputToBlock(input: TextInputElement): SlackBlock {\n const element: Record<string, unknown> = {\n type: \"plain_text_input\",\n action_id: input.id,\n multiline: input.multiline ?? false,\n };\n\n if (input.placeholder) {\n element.placeholder = { type: \"plain_text\", text: input.placeholder };\n }\n if (input.initialValue) {\n element.initial_value = input.initialValue;\n }\n if (input.maxLength) {\n element.max_length = input.maxLength;\n }\n\n return {\n type: \"input\",\n block_id: input.id,\n optional: input.optional ?? false,\n label: { type: \"plain_text\", text: input.label },\n element,\n };\n}\n\nfunction selectToBlock(select: SelectElement): SlackBlock {\n const options = select.options.map((opt) => {\n const option: Record<string, unknown> = {\n text: { type: \"plain_text\" as const, text: opt.label },\n value: opt.value,\n };\n if (opt.description) {\n option.description = { type: \"plain_text\", text: opt.description };\n }\n return option;\n });\n\n const element: Record<string, unknown> = {\n type: \"static_select\",\n action_id: select.id,\n options,\n };\n\n if (select.placeholder) {\n element.placeholder = { type: \"plain_text\", text: select.placeholder };\n }\n\n if (select.initialOption) {\n const initialOpt = options.find(\n (o) => (o as { value: string }).value === select.initialOption\n );\n if (initialOpt) {\n element.initial_option = initialOpt;\n }\n }\n\n return {\n type: \"input\",\n block_id: select.id,\n optional: select.optional ?? false,\n label: { type: \"plain_text\", text: select.label },\n element,\n };\n}\n\nfunction radioSelectToBlock(radioSelect: RadioSelectElement): SlackBlock {\n const limitedOptions = radioSelect.options.slice(0, 10);\n const options = limitedOptions.map((opt) => {\n const option: Record<string, unknown> = {\n text: { type: \"mrkdwn\" as const, text: opt.label },\n value: opt.value,\n };\n if (opt.description) {\n option.description = { type: \"mrkdwn\", text: opt.description };\n }\n return option;\n });\n\n const element: Record<string, unknown> = {\n type: \"radio_buttons\",\n action_id: radioSelect.id,\n options,\n };\n if (radioSelect.initialOption) {\n const initialOpt = options.find(\n (o) => (o as { value: string }).value === radioSelect.initialOption\n );\n if (initialOpt) {\n element.initial_option = initialOpt;\n }\n }\n return {\n type: \"input\",\n block_id: radioSelect.id,\n optional: radioSelect.optional ?? false,\n label: { type: \"plain_text\", text: radioSelect.label },\n element,\n };\n}\n"],"mappings":"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","names":["parseMarkdown","parseMarkdown","card","result","scheduledMessageId","adapter"]}