@ai-devkit/channel-connector 0.13.1 → 0.13.3

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.
Files changed (77) hide show
  1. package/dist/{ConfigStore.d.ts → ChannelConfigRepository.d.ts} +2 -2
  2. package/dist/ChannelConfigRepository.d.ts.map +1 -0
  3. package/dist/{ConfigStore.js → ChannelConfigRepository.js} +2 -2
  4. package/dist/ChannelConfigRepository.js.map +1 -0
  5. package/dist/__tests__/{ConfigStore.test.js → ChannelConfigRepository.test.js} +6 -6
  6. package/dist/__tests__/ChannelConfigRepository.test.js.map +1 -0
  7. package/dist/__tests__/adapters/{SlackAdapter.test.js → slack/SlackAdapter.test.js} +1 -1
  8. package/dist/__tests__/adapters/slack/SlackAdapter.test.js.map +1 -0
  9. package/dist/__tests__/{utils/SlackDeliveryQueue.test.js → adapters/slack/SlackMessageDelivery.test.js} +11 -11
  10. package/dist/__tests__/adapters/slack/SlackMessageDelivery.test.js.map +1 -0
  11. package/dist/__tests__/{utils → adapters/slack}/slackMarkdown.test.js +1 -1
  12. package/dist/__tests__/adapters/slack/slackMarkdown.test.js.map +1 -0
  13. package/dist/__tests__/adapters/slack/slackQuestion.test.js +88 -0
  14. package/dist/__tests__/adapters/slack/slackQuestion.test.js.map +1 -0
  15. package/dist/__tests__/adapters/{TelegramAdapter.test.js → telegram/TelegramAdapter.test.js} +2 -2
  16. package/dist/__tests__/adapters/telegram/TelegramAdapter.test.js.map +1 -0
  17. package/dist/__tests__/{utils → adapters/telegram}/telegramHtml.test.js +1 -1
  18. package/dist/__tests__/adapters/telegram/telegramHtml.test.js.map +1 -0
  19. package/dist/adapters/{SlackAdapter.d.ts → slack/SlackAdapter.d.ts} +2 -2
  20. package/dist/adapters/slack/SlackAdapter.d.ts.map +1 -0
  21. package/dist/adapters/{SlackAdapter.js → slack/SlackAdapter.js} +4 -41
  22. package/dist/adapters/slack/SlackAdapter.js.map +1 -0
  23. package/dist/{utils/SlackDeliveryQueue.d.ts → adapters/slack/SlackMessageDelivery.d.ts} +3 -3
  24. package/dist/adapters/slack/SlackMessageDelivery.d.ts.map +1 -0
  25. package/dist/{utils/SlackDeliveryQueue.js → adapters/slack/SlackMessageDelivery.js} +3 -3
  26. package/dist/adapters/slack/SlackMessageDelivery.js.map +1 -0
  27. package/dist/adapters/slack/slackMarkdown.d.ts.map +1 -0
  28. package/dist/adapters/slack/slackMarkdown.js.map +1 -0
  29. package/dist/adapters/slack/slackQuestion.d.ts +30 -0
  30. package/dist/adapters/slack/slackQuestion.d.ts.map +1 -0
  31. package/dist/adapters/slack/slackQuestion.js +44 -0
  32. package/dist/adapters/slack/slackQuestion.js.map +1 -0
  33. package/dist/adapters/{TelegramAdapter.d.ts → telegram/TelegramAdapter.d.ts} +4 -4
  34. package/dist/adapters/telegram/TelegramAdapter.d.ts.map +1 -0
  35. package/dist/adapters/telegram/TelegramAdapter.js +120 -0
  36. package/dist/adapters/telegram/TelegramAdapter.js.map +1 -0
  37. package/dist/adapters/telegram/TelegramMessageDelivery.d.ts +11 -0
  38. package/dist/adapters/telegram/TelegramMessageDelivery.d.ts.map +1 -0
  39. package/dist/adapters/telegram/TelegramMessageDelivery.js +38 -0
  40. package/dist/adapters/telegram/TelegramMessageDelivery.js.map +1 -0
  41. package/dist/adapters/telegram/telegramHtml.d.ts.map +1 -0
  42. package/dist/adapters/telegram/telegramHtml.js.map +1 -0
  43. package/dist/adapters/telegram/telegramKeyboard.d.ts +7 -0
  44. package/dist/adapters/telegram/telegramKeyboard.d.ts.map +1 -0
  45. package/dist/adapters/telegram/telegramKeyboard.js +8 -0
  46. package/dist/adapters/telegram/telegramKeyboard.js.map +1 -0
  47. package/dist/adapters/telegram/telegramMarkdown.d.ts +13 -0
  48. package/dist/adapters/telegram/telegramMarkdown.d.ts.map +1 -0
  49. package/dist/adapters/{TelegramAdapter.js → telegram/telegramMarkdown.js} +6 -151
  50. package/dist/adapters/telegram/telegramMarkdown.js.map +1 -0
  51. package/dist/index.d.ts +5 -7
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +3 -5
  54. package/dist/index.js.map +1 -1
  55. package/package.json +1 -1
  56. package/dist/ConfigStore.d.ts.map +0 -1
  57. package/dist/ConfigStore.js.map +0 -1
  58. package/dist/__tests__/ConfigStore.test.js.map +0 -1
  59. package/dist/__tests__/adapters/SlackAdapter.test.js.map +0 -1
  60. package/dist/__tests__/adapters/TelegramAdapter.test.js.map +0 -1
  61. package/dist/__tests__/utils/SlackDeliveryQueue.test.js.map +0 -1
  62. package/dist/__tests__/utils/slackMarkdown.test.js.map +0 -1
  63. package/dist/__tests__/utils/telegramHtml.test.js.map +0 -1
  64. package/dist/adapters/SlackAdapter.d.ts.map +0 -1
  65. package/dist/adapters/SlackAdapter.js.map +0 -1
  66. package/dist/adapters/TelegramAdapter.d.ts.map +0 -1
  67. package/dist/adapters/TelegramAdapter.js.map +0 -1
  68. package/dist/utils/SlackDeliveryQueue.d.ts.map +0 -1
  69. package/dist/utils/SlackDeliveryQueue.js.map +0 -1
  70. package/dist/utils/slackMarkdown.d.ts.map +0 -1
  71. package/dist/utils/slackMarkdown.js.map +0 -1
  72. package/dist/utils/telegramHtml.d.ts.map +0 -1
  73. package/dist/utils/telegramHtml.js.map +0 -1
  74. /package/dist/{utils → adapters/slack}/slackMarkdown.d.ts +0 -0
  75. /package/dist/{utils → adapters/slack}/slackMarkdown.js +0 -0
  76. /package/dist/{utils → adapters/telegram}/telegramHtml.d.ts +0 -0
  77. /package/dist/{utils → adapters/telegram}/telegramHtml.js +0 -0
@@ -1,161 +1,16 @@
1
- import { Telegraf } from 'telegraf';
2
1
  import { Marked } from 'marked';
3
- import { markdownToTelegramHtml } from '../utils/telegramHtml.js';
4
- export const TELEGRAM_CHANNEL_TYPE = 'telegram';
5
- export const TELEGRAM_MAX_MESSAGE_LENGTH = 4096;
6
- const TELEGRAM_PARSE_MODE = 'HTML';
2
+ import { markdownToTelegramHtml } from './telegramHtml.js';
7
3
  const markdownLexer = new Marked();
8
- /**
9
- * Telegram Bot API adapter using telegraf with long polling.
10
- */ export class TelegramAdapter {
11
- type = TELEGRAM_CHANNEL_TYPE;
12
- bot;
13
- messageHandler = null;
14
- callbackHandler = null;
15
- running = false;
16
- constructor(options){
17
- this.bot = new Telegraf(options.botToken);
18
- }
19
- async start() {
20
- this.bot.on('text', async (ctx)=>{
21
- if (!this.messageHandler) return;
22
- const msg = {
23
- channelType: TELEGRAM_CHANNEL_TYPE,
24
- chatId: String(ctx.message.chat.id),
25
- userId: String(ctx.message.from.id),
26
- text: ctx.message.text,
27
- timestamp: new Date(ctx.message.date * 1000)
28
- };
29
- try {
30
- await this.messageHandler(msg);
31
- } catch (error) {
32
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
33
- await ctx.reply(`Error processing message: ${errorMessage}`);
34
- }
35
- });
36
- this.bot.on('callback_query', async (ctx)=>{
37
- if (!this.callbackHandler) {
38
- try {
39
- await ctx.answerCbQuery();
40
- } catch {}
41
- return;
42
- }
43
- const query = ctx.callbackQuery;
44
- const data = typeof query.data === 'string' ? query.data : '';
45
- if (!query.message) {
46
- try {
47
- await ctx.answerCbQuery();
48
- } catch {}
49
- return;
50
- }
51
- const cb = {
52
- channelType: TELEGRAM_CHANNEL_TYPE,
53
- chatId: String(query.message.chat.id),
54
- userId: String(query.from.id),
55
- messageId: query.message.message_id,
56
- callbackData: data,
57
- callbackQueryId: query.id,
58
- timestamp: new Date()
59
- };
60
- try {
61
- await this.callbackHandler(cb);
62
- } catch {
63
- try {
64
- await ctx.answerCbQuery('Error');
65
- } catch {}
66
- }
67
- });
68
- await this.bot.launch();
69
- this.running = true;
70
- }
71
- async stop() {
72
- this.running = false;
73
- await this.bot.stop();
74
- }
75
- /**
76
- * Input is treated as markdown and rendered as Telegram-compatible HTML.
77
- * Long messages are chunked as markdown source before rendering so each
78
- * Telegram HTML payload is independently valid.
79
- */ async sendMessage(chatId, text) {
80
- let chunks;
81
- try {
82
- chunks = chunkMarkdownForTelegram(text, TELEGRAM_MAX_MESSAGE_LENGTH);
83
- } catch {
84
- for (const chunk of chunkMessage(text, TELEGRAM_MAX_MESSAGE_LENGTH)){
85
- await this.bot.telegram.sendMessage(chatId, chunk);
86
- }
87
- return;
88
- }
89
- for (const chunk of chunks){
90
- if (!chunk.html) {
91
- await this.bot.telegram.sendMessage(chatId, chunk.text);
92
- continue;
93
- }
94
- try {
95
- await this.bot.telegram.sendMessage(chatId, chunk.text, {
96
- parse_mode: TELEGRAM_PARSE_MODE
97
- });
98
- } catch (error) {
99
- if (!isParseEntitiesError(error)) throw error;
100
- // Telegram rejected the rendered HTML — fall back to plain text
101
- // so the user still gets the content (just unformatted).
102
- await this.bot.telegram.sendMessage(chatId, htmlToPlainText(chunk.text));
103
- }
104
- }
105
- }
106
- onMessage(handler) {
107
- this.messageHandler = handler;
108
- }
109
- onCallback(handler) {
110
- this.callbackHandler = handler;
111
- }
112
- /**
113
- * Send a message with an inline keyboard. `html` is sent verbatim with
114
- * parse_mode=HTML — callers must pre-escape any user-controlled fields.
115
- * Returns the Telegram message_id of the sent message.
116
- */ async sendInlineKeyboard(chatId, html, keyboard) {
117
- const result = await this.bot.telegram.sendMessage(chatId, html, {
118
- parse_mode: TELEGRAM_PARSE_MODE,
119
- reply_markup: {
120
- inline_keyboard: toTelegrafKeyboard(keyboard)
121
- }
122
- });
123
- return result.message_id;
124
- }
125
- /**
126
- * Replace the inline keyboard on an existing message. Pass `null` to remove
127
- * the keyboard entirely.
128
- */ async editInlineKeyboard(chatId, messageId, keyboard) {
129
- await this.bot.telegram.editMessageReplyMarkup(chatId, messageId, undefined, keyboard ? {
130
- inline_keyboard: toTelegrafKeyboard(keyboard)
131
- } : undefined);
132
- }
133
- /**
134
- * Acknowledge a callback_query. Without this Telegram leaves a spinner on
135
- * the tapped button. Pass `text` to show a transient toast.
136
- */ async answerCallback(callbackQueryId, text) {
137
- await this.bot.telegram.answerCbQuery(callbackQueryId, text);
138
- }
139
- async isHealthy() {
140
- return this.running;
141
- }
142
- }
143
- function toTelegrafKeyboard(keyboard) {
144
- return keyboard.map((row)=>row.map((btn)=>({
145
- text: btn.text,
146
- callback_data: btn.callbackData
147
- })));
148
- }
149
- function isParseEntitiesError(error) {
4
+ export function isParseEntitiesError(error) {
150
5
  if (!error || typeof error !== 'object') return false;
151
6
  const description = error.description;
152
7
  const message = error.message;
153
8
  return ((description ?? '') + (message ?? '')).includes("can't parse entities");
154
9
  }
155
- function htmlToPlainText(html) {
10
+ export function htmlToPlainText(html) {
156
11
  return html.replace(/<[^>]+>/g, '').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&amp;/g, '&');
157
12
  }
158
- function chunkMarkdownForTelegram(markdown, maxLen) {
13
+ export function chunkMarkdownForTelegram(markdown, maxLen) {
159
14
  const markdownChunks = splitMarkdownSource(markdown, maxLen);
160
15
  const chunks = [];
161
16
  for (const markdownChunk of markdownChunks){
@@ -376,7 +231,7 @@ function renderedLengthFits(markdown, maxLen) {
376
231
  /**
377
232
  * Split text into chunks of maxLen or fewer characters. Prefers paragraph
378
233
  * boundaries (\n\n), then single newlines (\n), then hard-splits at maxLen.
379
- */ function chunkMessage(text, maxLen) {
234
+ */ export function chunkMessage(text, maxLen) {
380
235
  const chunks = [];
381
236
  let remaining = text;
382
237
  while(remaining.length > 0){
@@ -400,4 +255,4 @@ function renderedLengthFits(markdown, maxLen) {
400
255
  return chunks;
401
256
  }
402
257
 
403
- //# sourceMappingURL=TelegramAdapter.js.map
258
+ //# sourceMappingURL=telegramMarkdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/telegram/telegramMarkdown.ts"],"sourcesContent":["import { Marked, type Token, type Tokens } from 'marked';\nimport { markdownToTelegramHtml } from './telegramHtml.js';\n\nconst markdownLexer = new Marked();\n\nexport type TelegramMessageChunk = {\n text: string;\n html: boolean;\n};\n\nexport function isParseEntitiesError(error: unknown): boolean {\n if (!error || typeof error !== 'object') return false;\n const description = (error as { description?: string }).description;\n const message = (error as { message?: string }).message;\n return ((description ?? '') + (message ?? '')).includes(\"can't parse entities\");\n}\n\nexport function htmlToPlainText(html: string): string {\n return html\n .replace(/<[^>]+>/g, '')\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&amp;/g, '&');\n}\n\nexport function chunkMarkdownForTelegram(markdown: string, maxLen: number): TelegramMessageChunk[] {\n const markdownChunks = splitMarkdownSource(markdown, maxLen);\n const chunks: TelegramMessageChunk[] = [];\n\n for (const markdownChunk of markdownChunks) {\n const html = markdownToTelegramHtml(markdownChunk);\n if (html.length <= maxLen) {\n if (html.length > 0) chunks.push({ text: html, html: true });\n continue;\n }\n\n for (const plainChunk of chunkMessage(markdownChunk, maxLen)) {\n if (plainChunk.length > 0) chunks.push({ text: plainChunk, html: false });\n }\n }\n\n return chunks;\n}\n\nfunction splitMarkdownSource(markdown: string, maxLen: number, depth = 0): string[] {\n if (markdown.length === 0) return [];\n if (renderedLengthFits(markdown, maxLen)) return [markdown];\n if (depth > 6) return splitPlainMarkdownText(markdown, maxLen);\n\n const chunks: string[] = [];\n let current = '';\n const tokens = markdownLexer.lexer(markdown);\n\n for (const token of tokens) {\n const raw = token.raw ?? '';\n if (raw.length === 0) continue;\n\n const candidate = current + raw;\n if (candidate.length > 0 && renderedLengthFits(candidate, maxLen)) {\n current = candidate;\n continue;\n }\n\n if (current.length > 0) {\n chunks.push(current);\n current = '';\n }\n\n if (renderedLengthFits(raw, maxLen)) {\n current = raw;\n } else {\n chunks.push(...splitOversizedToken(token, maxLen, depth + 1));\n }\n }\n\n if (current.length > 0) chunks.push(current);\n return chunks.flatMap((chunk) => renderedLengthFits(chunk, maxLen) ? [chunk] : splitPlainMarkdownText(chunk, maxLen));\n}\n\nfunction splitOversizedToken(token: Token, maxLen: number, depth: number): string[] {\n switch (token.type) {\n case 'code':\n return splitCodeToken(token as Tokens.Code, maxLen);\n case 'list':\n return splitListToken(token as Tokens.List, maxLen, depth);\n case 'paragraph':\n case 'text':\n return splitPlainMarkdownText(token.raw, maxLen);\n default:\n if ('tokens' in token && Array.isArray(token.tokens) && token.raw !== undefined) {\n return splitMarkdownSource(token.raw, maxLen, depth);\n }\n return splitPlainMarkdownText(token.raw ?? '', maxLen);\n }\n}\n\nfunction splitListToken(token: Tokens.List, maxLen: number, depth: number): string[] {\n const chunks: string[] = [];\n let current = '';\n\n for (const item of token.items) {\n const raw = item.raw;\n const candidate = current + raw;\n if (candidate.length > 0 && renderedLengthFits(candidate, maxLen)) {\n current = candidate;\n continue;\n }\n\n if (current.length > 0) {\n chunks.push(current);\n current = '';\n }\n\n if (renderedLengthFits(raw, maxLen)) {\n current = raw;\n } else {\n chunks.push(...splitMarkdownSource(raw, maxLen, depth + 1));\n }\n }\n\n if (current.length > 0) chunks.push(current);\n return chunks;\n}\n\nfunction splitCodeToken(token: Tokens.Code, maxLen: number): string[] {\n const fence = token.raw.startsWith('~~~') ? '~~~' : '```';\n const lang = token.lang ? token.lang.split(/\\s/)[0] : '';\n const lines = token.text.split('\\n');\n const chunks: string[] = [];\n let currentLines: string[] = [];\n\n const renderFence = (codeLines: string[]): string =>\n `${fence}${lang}\\n${codeLines.join('\\n')}\\n${fence}\\n\\n`;\n\n for (const line of lines) {\n const candidateLines = [...currentLines, line];\n if (renderedLengthFits(renderFence(candidateLines), maxLen)) {\n currentLines = candidateLines;\n continue;\n }\n\n if (currentLines.length > 0) {\n chunks.push(renderFence(currentLines));\n currentLines = [];\n }\n\n if (renderedLengthFits(renderFence([line]), maxLen)) {\n currentLines = [line];\n } else {\n for (const segment of splitCodeLine(line, fence, lang, maxLen)) {\n chunks.push(renderFence([segment]));\n }\n }\n }\n\n if (currentLines.length > 0) chunks.push(renderFence(currentLines));\n return chunks;\n}\n\nfunction splitCodeLine(line: string, fence: string, lang: string, maxLen: number): string[] {\n const segments: string[] = [];\n let current = '';\n const renderFence = (value: string): string => `${fence}${lang}\\n${value}\\n${fence}\\n\\n`;\n\n for (const char of Array.from(line)) {\n const candidate = current + char;\n if (renderedLengthFits(renderFence(candidate), maxLen)) {\n current = candidate;\n continue;\n }\n\n if (current.length > 0) {\n segments.push(current);\n current = '';\n }\n\n if (renderedLengthFits(renderFence(char), maxLen)) {\n current = char;\n } else {\n segments.push(char);\n }\n }\n\n if (current.length > 0) segments.push(current);\n return segments;\n}\n\nfunction splitPlainMarkdownText(markdown: string, maxLen: number): string[] {\n if (markdown.length === 0) return [];\n if (renderedLengthFits(markdown, maxLen)) return [markdown];\n\n const newlineUnits = markdown.split(/(?<=\\n)/u);\n if (newlineUnits.length > 1) {\n return packMarkdownUnits(newlineUnits, maxLen, splitPlainMarkdownText);\n }\n\n const sentenceUnits = markdown.match(/[^.!?]+[.!?]+(?:\\s+|$)|[^.!?]+$/gu);\n if (sentenceUnits && sentenceUnits.length > 1) {\n return packMarkdownUnits(sentenceUnits, maxLen, splitPlainMarkdownText);\n }\n\n const wordUnits = markdown.match(/\\S+\\s*/gu);\n if (wordUnits && wordUnits.length > 1) {\n return packMarkdownUnits(wordUnits, maxLen, splitPlainMarkdownText);\n }\n\n return splitByCodePoint(markdown, maxLen);\n}\n\nfunction packMarkdownUnits(\n units: string[],\n maxLen: number,\n splitOversized: (unit: string, maxLen: number) => string[],\n): string[] {\n const chunks: string[] = [];\n let current = '';\n\n for (const unit of units) {\n const candidate = current + unit;\n if (renderedLengthFits(candidate, maxLen)) {\n current = candidate;\n continue;\n }\n\n if (current.length > 0) {\n chunks.push(current);\n current = '';\n }\n\n if (renderedLengthFits(unit, maxLen)) {\n current = unit;\n } else {\n chunks.push(...splitOversized(unit, maxLen));\n }\n }\n\n if (current.length > 0) chunks.push(current);\n return chunks;\n}\n\nfunction splitByCodePoint(text: string, maxLen: number): string[] {\n const chunks: string[] = [];\n let current = '';\n\n for (const char of Array.from(text)) {\n const candidate = current + char;\n if (renderedLengthFits(candidate, maxLen)) {\n current = candidate;\n continue;\n }\n\n if (current.length > 0) {\n chunks.push(current);\n current = '';\n }\n\n if (renderedLengthFits(char, maxLen)) {\n current = char;\n } else {\n chunks.push(char);\n }\n }\n\n if (current.length > 0) chunks.push(current);\n return chunks;\n}\n\nfunction renderedLengthFits(markdown: string, maxLen: number): boolean {\n return markdownToTelegramHtml(markdown).length <= maxLen;\n}\n\n/**\n * Split text into chunks of maxLen or fewer characters. Prefers paragraph\n * boundaries (\\n\\n), then single newlines (\\n), then hard-splits at maxLen.\n */\nexport function chunkMessage(text: string, maxLen: number): string[] {\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= maxLen) {\n chunks.push(remaining);\n break;\n }\n\n const lastParagraph = remaining.lastIndexOf('\\n\\n', maxLen - 2);\n const lastNewline = remaining.lastIndexOf('\\n', maxLen - 1);\n\n let splitAt: number;\n if (lastParagraph > 0) {\n splitAt = lastParagraph + 2;\n } else if (lastNewline > 0) {\n splitAt = lastNewline + 1;\n } else {\n splitAt = maxLen;\n }\n\n chunks.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt);\n }\n\n return chunks;\n}\n"],"names":["Marked","markdownToTelegramHtml","markdownLexer","isParseEntitiesError","error","description","message","includes","htmlToPlainText","html","replace","chunkMarkdownForTelegram","markdown","maxLen","markdownChunks","splitMarkdownSource","chunks","markdownChunk","length","push","text","plainChunk","chunkMessage","depth","renderedLengthFits","splitPlainMarkdownText","current","tokens","lexer","token","raw","candidate","splitOversizedToken","flatMap","chunk","type","splitCodeToken","splitListToken","Array","isArray","undefined","item","items","fence","startsWith","lang","split","lines","currentLines","renderFence","codeLines","join","line","candidateLines","segment","splitCodeLine","segments","value","char","from","newlineUnits","packMarkdownUnits","sentenceUnits","match","wordUnits","splitByCodePoint","units","splitOversized","unit","remaining","lastParagraph","lastIndexOf","lastNewline","splitAt","slice"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,11 +1,9 @@
1
1
  export { ChannelManager } from './ChannelManager.js';
2
- export { ConfigStore } from './ConfigStore.js';
3
- export { TelegramAdapter, TELEGRAM_CHANNEL_TYPE, TELEGRAM_MAX_MESSAGE_LENGTH } from './adapters/TelegramAdapter.js';
4
- export { SlackAdapter, SLACK_CHANNEL_TYPE, validateSlackAppToken, validateSlackCredentials, } from './adapters/SlackAdapter.js';
5
- export type { SlackIdentity } from './adapters/SlackAdapter.js';
6
- export { SLACK_MAX_MESSAGE_LENGTH, chunkMarkdownForSlack, escapeSlackText, markdownToSlackMrkdwn, } from './utils/slackMarkdown.js';
7
- export { SlackDeliveryQueue } from './utils/SlackDeliveryQueue.js';
8
- export type { TelegramAdapterOptions } from './adapters/TelegramAdapter.js';
2
+ export { ChannelConfigRepository } from './ChannelConfigRepository.js';
3
+ export { TelegramAdapter, TELEGRAM_CHANNEL_TYPE } from './adapters/telegram/TelegramAdapter.js';
4
+ export { SlackAdapter, SLACK_CHANNEL_TYPE, validateSlackAppToken, validateSlackCredentials, } from './adapters/slack/SlackAdapter.js';
5
+ export type { SlackIdentity } from './adapters/slack/SlackAdapter.js';
6
+ export type { TelegramAdapterOptions } from './adapters/telegram/TelegramAdapter.js';
9
7
  export { isInteractiveChannelAdapter } from './adapters/ChannelAdapter.js';
10
8
  export type { ChannelAdapter, InteractiveChannelAdapter } from './adapters/ChannelAdapter.js';
11
9
  export type { IncomingMessage, MessageHandler, ChannelConfig, ChannelEntry, ChannelType, TelegramConfig, SlackConfig, SlackChannelEntry, SendMessageOptions, SentMessage, ChannelQuestion, ChannelQuestionOption, IncomingInteraction, InteractionHandler, InlineKeyboardButton, InlineKeyboard, IncomingCallback, CallbackHandler, } from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AACpH,OAAO,EACH,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,GAC3B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EACH,wBAAwB,EACxB,qBAAqB,EACrB,eAAe,EACf,qBAAqB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,YAAY,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAE5E,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,YAAY,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAE9F,YAAY,EACR,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,WAAW,EACX,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,eAAe,GAClB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAChG,OAAO,EACH,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,GAC3B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACtE,YAAY,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAErF,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,YAAY,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAE9F,YAAY,EACR,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,WAAW,EACX,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,eAAe,GAClB,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  export { ChannelManager } from './ChannelManager.js';
2
- export { ConfigStore } from './ConfigStore.js';
3
- export { TelegramAdapter, TELEGRAM_CHANNEL_TYPE, TELEGRAM_MAX_MESSAGE_LENGTH } from './adapters/TelegramAdapter.js';
4
- export { SlackAdapter, SLACK_CHANNEL_TYPE, validateSlackAppToken, validateSlackCredentials } from './adapters/SlackAdapter.js';
5
- export { SLACK_MAX_MESSAGE_LENGTH, chunkMarkdownForSlack, escapeSlackText, markdownToSlackMrkdwn } from './utils/slackMarkdown.js';
6
- export { SlackDeliveryQueue } from './utils/SlackDeliveryQueue.js';
2
+ export { ChannelConfigRepository } from './ChannelConfigRepository.js';
3
+ export { TelegramAdapter, TELEGRAM_CHANNEL_TYPE } from './adapters/telegram/TelegramAdapter.js';
4
+ export { SlackAdapter, SLACK_CHANNEL_TYPE, validateSlackAppToken, validateSlackCredentials } from './adapters/slack/SlackAdapter.js';
7
5
  export { isInteractiveChannelAdapter } from './adapters/ChannelAdapter.js';
8
6
 
9
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { ChannelManager } from './ChannelManager.js';\nexport { ConfigStore } from './ConfigStore.js';\nexport { TelegramAdapter, TELEGRAM_CHANNEL_TYPE, TELEGRAM_MAX_MESSAGE_LENGTH } from './adapters/TelegramAdapter.js';\nexport {\n SlackAdapter,\n SLACK_CHANNEL_TYPE,\n validateSlackAppToken,\n validateSlackCredentials,\n} from './adapters/SlackAdapter.js';\nexport type { SlackIdentity } from './adapters/SlackAdapter.js';\nexport {\n SLACK_MAX_MESSAGE_LENGTH,\n chunkMarkdownForSlack,\n escapeSlackText,\n markdownToSlackMrkdwn,\n} from './utils/slackMarkdown.js';\nexport { SlackDeliveryQueue } from './utils/SlackDeliveryQueue.js';\nexport type { TelegramAdapterOptions } from './adapters/TelegramAdapter.js';\n\nexport { isInteractiveChannelAdapter } from './adapters/ChannelAdapter.js';\nexport type { ChannelAdapter, InteractiveChannelAdapter } from './adapters/ChannelAdapter.js';\n\nexport type {\n IncomingMessage,\n MessageHandler,\n ChannelConfig,\n ChannelEntry,\n ChannelType,\n TelegramConfig,\n SlackConfig,\n SlackChannelEntry,\n SendMessageOptions,\n SentMessage,\n ChannelQuestion,\n ChannelQuestionOption,\n IncomingInteraction,\n InteractionHandler,\n InlineKeyboardButton,\n InlineKeyboard,\n IncomingCallback,\n CallbackHandler,\n} from './types.js';\n"],"names":["ChannelManager","ConfigStore","TelegramAdapter","TELEGRAM_CHANNEL_TYPE","TELEGRAM_MAX_MESSAGE_LENGTH","SlackAdapter","SLACK_CHANNEL_TYPE","validateSlackAppToken","validateSlackCredentials","SLACK_MAX_MESSAGE_LENGTH","chunkMarkdownForSlack","escapeSlackText","markdownToSlackMrkdwn","SlackDeliveryQueue","isInteractiveChannelAdapter"],"mappings":"AAAA,SAASA,cAAc,QAAQ,sBAAsB;AACrD,SAASC,WAAW,QAAQ,mBAAmB;AAC/C,SAASC,eAAe,EAAEC,qBAAqB,EAAEC,2BAA2B,QAAQ,gCAAgC;AACpH,SACIC,YAAY,EACZC,kBAAkB,EAClBC,qBAAqB,EACrBC,wBAAwB,QACrB,6BAA6B;AAEpC,SACIC,wBAAwB,EACxBC,qBAAqB,EACrBC,eAAe,EACfC,qBAAqB,QAClB,2BAA2B;AAClC,SAASC,kBAAkB,QAAQ,gCAAgC;AAGnE,SAASC,2BAA2B,QAAQ,+BAA+B"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { ChannelManager } from './ChannelManager.js';\nexport { ChannelConfigRepository } from './ChannelConfigRepository.js';\nexport { TelegramAdapter, TELEGRAM_CHANNEL_TYPE } from './adapters/telegram/TelegramAdapter.js';\nexport {\n SlackAdapter,\n SLACK_CHANNEL_TYPE,\n validateSlackAppToken,\n validateSlackCredentials,\n} from './adapters/slack/SlackAdapter.js';\nexport type { SlackIdentity } from './adapters/slack/SlackAdapter.js';\nexport type { TelegramAdapterOptions } from './adapters/telegram/TelegramAdapter.js';\n\nexport { isInteractiveChannelAdapter } from './adapters/ChannelAdapter.js';\nexport type { ChannelAdapter, InteractiveChannelAdapter } from './adapters/ChannelAdapter.js';\n\nexport type {\n IncomingMessage,\n MessageHandler,\n ChannelConfig,\n ChannelEntry,\n ChannelType,\n TelegramConfig,\n SlackConfig,\n SlackChannelEntry,\n SendMessageOptions,\n SentMessage,\n ChannelQuestion,\n ChannelQuestionOption,\n IncomingInteraction,\n InteractionHandler,\n InlineKeyboardButton,\n InlineKeyboard,\n IncomingCallback,\n CallbackHandler,\n} from './types.js';\n"],"names":["ChannelManager","ChannelConfigRepository","TelegramAdapter","TELEGRAM_CHANNEL_TYPE","SlackAdapter","SLACK_CHANNEL_TYPE","validateSlackAppToken","validateSlackCredentials","isInteractiveChannelAdapter"],"mappings":"AAAA,SAASA,cAAc,QAAQ,sBAAsB;AACrD,SAASC,uBAAuB,QAAQ,+BAA+B;AACvE,SAASC,eAAe,EAAEC,qBAAqB,QAAQ,yCAAyC;AAChG,SACIC,YAAY,EACZC,kBAAkB,EAClBC,qBAAqB,EACrBC,wBAAwB,QACrB,mCAAmC;AAI1C,SAASC,2BAA2B,QAAQ,+BAA+B"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "nx": {
4
4
  "name": "channel-connector"
5
5
  },
6
- "version": "0.13.1",
6
+ "version": "0.13.3",
7
7
  "type": "module",
8
8
  "description": "Generic messaging bridge for connecting to external communication platforms",
9
9
  "main": "dist/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"file":"ConfigStore.d.ts","sourceRoot":"","sources":["../src/ConfigStore.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK9D;;;;GAIG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,CAAC,EAAE,MAAM;IAI/B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,aAAa,CAAC;IASzC;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAMnE;;OAEG;IACG,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhD;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;YAKnD,WAAW;CAM5B"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ConfigStore.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport type { ChannelConfig, ChannelEntry } from './types.js';\n\nconst DEFAULT_CONFIG_PATH = path.join(os.homedir(), '.ai-devkit', 'channels.json');\nconst DEFAULT_CONFIG: ChannelConfig = { channels: {} };\n\n/**\n * Persists channel configurations to disk.\n * Default location: ~/.ai-devkit/channels.json\n * File permissions are set to 0600 to protect tokens.\n */\nexport class ConfigStore {\n private configPath: string;\n\n constructor(configPath?: string) {\n this.configPath = configPath ?? DEFAULT_CONFIG_PATH;\n }\n\n /**\n * Read the full config. Returns default empty config if file is missing or corrupt.\n */\n async getConfig(): Promise<ChannelConfig> {\n try {\n const raw = fs.readFileSync(this.configPath, 'utf-8');\n return JSON.parse(raw) as ChannelConfig;\n } catch {\n return { ...DEFAULT_CONFIG, channels: {} };\n }\n }\n\n /**\n * Save a channel entry. Creates the file and parent directory if needed.\n */\n async saveChannel(name: string, entry: ChannelEntry): Promise<void> {\n const config = await this.getConfig();\n config.channels[name] = entry;\n await this.writeConfig(config);\n }\n\n /**\n * Remove a channel entry by name.\n */\n async removeChannel(name: string): Promise<void> {\n const config = await this.getConfig();\n delete config.channels[name];\n await this.writeConfig(config);\n }\n\n /**\n * Get a single channel entry by name.\n */\n async getChannel(name: string): Promise<ChannelEntry | undefined> {\n const config = await this.getConfig();\n return config.channels[name];\n }\n\n private async writeConfig(config: ChannelConfig): Promise<void> {\n const dir = path.dirname(this.configPath);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(this.configPath, JSON.stringify(config, null, 2), { mode: 0o600 });\n fs.chmodSync(this.configPath, 0o600);\n }\n}\n"],"names":["fs","path","os","DEFAULT_CONFIG_PATH","join","homedir","DEFAULT_CONFIG","channels","ConfigStore","configPath","getConfig","raw","readFileSync","JSON","parse","saveChannel","name","entry","config","writeConfig","removeChannel","getChannel","dir","dirname","mkdirSync","recursive","writeFileSync","stringify","mode","chmodSync"],"mappings":"AAAA,YAAYA,QAAQ,KAAK;AACzB,YAAYC,UAAU,OAAO;AAC7B,YAAYC,QAAQ,KAAK;AAGzB,MAAMC,sBAAsBF,KAAKG,IAAI,CAACF,GAAGG,OAAO,IAAI,cAAc;AAClE,MAAMC,iBAAgC;IAAEC,UAAU,CAAC;AAAE;AAErD;;;;CAIC,GACD,OAAO,MAAMC;IACDC,WAAmB;IAE3B,YAAYA,UAAmB,CAAE;QAC7B,IAAI,CAACA,UAAU,GAAGA,cAAcN;IACpC;IAEA;;KAEC,GACD,MAAMO,YAAoC;QACtC,IAAI;YACA,MAAMC,MAAMX,GAAGY,YAAY,CAAC,IAAI,CAACH,UAAU,EAAE;YAC7C,OAAOI,KAAKC,KAAK,CAACH;QACtB,EAAE,OAAM;YACJ,OAAO;gBAAE,GAAGL,cAAc;gBAAEC,UAAU,CAAC;YAAE;QAC7C;IACJ;IAEA;;KAEC,GACD,MAAMQ,YAAYC,IAAY,EAAEC,KAAmB,EAAiB;QAChE,MAAMC,SAAS,MAAM,IAAI,CAACR,SAAS;QACnCQ,OAAOX,QAAQ,CAACS,KAAK,GAAGC;QACxB,MAAM,IAAI,CAACE,WAAW,CAACD;IAC3B;IAEA;;KAEC,GACD,MAAME,cAAcJ,IAAY,EAAiB;QAC7C,MAAME,SAAS,MAAM,IAAI,CAACR,SAAS;QACnC,OAAOQ,OAAOX,QAAQ,CAACS,KAAK;QAC5B,MAAM,IAAI,CAACG,WAAW,CAACD;IAC3B;IAEA;;KAEC,GACD,MAAMG,WAAWL,IAAY,EAAqC;QAC9D,MAAME,SAAS,MAAM,IAAI,CAACR,SAAS;QACnC,OAAOQ,OAAOX,QAAQ,CAACS,KAAK;IAChC;IAEA,MAAcG,YAAYD,MAAqB,EAAiB;QAC5D,MAAMI,MAAMrB,KAAKsB,OAAO,CAAC,IAAI,CAACd,UAAU;QACxCT,GAAGwB,SAAS,CAACF,KAAK;YAAEG,WAAW;QAAK;QACpCzB,GAAG0B,aAAa,CAAC,IAAI,CAACjB,UAAU,EAAEI,KAAKc,SAAS,CAACT,QAAQ,MAAM,IAAI;YAAEU,MAAM;QAAM;QACjF5B,GAAG6B,SAAS,CAAC,IAAI,CAACpB,UAAU,EAAE;IAClC;AACJ"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/__tests__/ConfigStore.test.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { ConfigStore } from '../ConfigStore.js';\nimport { isSlackEntry } from '../types.js';\nimport type { ChannelEntry } from '../types.js';\n\ndescribe('ConfigStore', () => {\n let tmpDir: string;\n let configPath: string;\n let store: ConfigStore;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'channel-connector-test-'));\n configPath = path.join(tmpDir, 'channels.json');\n store = new ConfigStore(configPath);\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n const sampleEntry: ChannelEntry = {\n type: 'telegram',\n enabled: true,\n createdAt: '2026-04-11T00:00:00Z',\n config: {\n botToken: 'test-token-123',\n botUsername: 'test_bot',\n },\n };\n\n const slackEntry: ChannelEntry = {\n type: 'slack',\n enabled: true,\n createdAt: '2026-08-06T00:00:00Z',\n config: {\n appToken: 'xapp-fake',\n botToken: 'xoxb-fake',\n appId: 'A123',\n botUserId: 'U-BOT',\n workspaceId: 'T123',\n workspaceName: 'Sandbox',\n transport: 'socket-mode',\n audience: 'dm',\n },\n };\n\n describe('constructor', () => {\n it('should use default path when no configPath provided', async () => {\n const defaultStore = new ConfigStore();\n // Should not throw — just uses default path\n const config = await defaultStore.getConfig();\n expect(config).toBeDefined();\n });\n });\n\n describe('getConfig', () => {\n it('narrows provider configuration from the channel type', () => {\n expect(isSlackEntry(slackEntry)).toBe(true);\n if (!isSlackEntry(slackEntry)) throw new Error('expected Slack entry');\n expect(slackEntry.config.workspaceId).toBe('T123');\n });\n\n it('should return default empty config when file does not exist', async () => {\n const config = await store.getConfig();\n expect(config).toEqual({ channels: {} });\n });\n\n it('should return parsed config when file exists', async () => {\n fs.writeFileSync(configPath, JSON.stringify({\n channels: { telegram: sampleEntry }\n }));\n\n const config = await store.getConfig();\n expect(config.channels.telegram).toEqual(sampleEntry);\n });\n\n it('should handle corrupted JSON gracefully', async () => {\n fs.writeFileSync(configPath, 'not valid json{{{');\n\n const config = await store.getConfig();\n expect(config).toEqual({ channels: {} });\n });\n });\n\n describe('saveChannel', () => {\n it('should create config file with channel entry', async () => {\n await store.saveChannel('telegram', sampleEntry);\n\n const raw = fs.readFileSync(configPath, 'utf-8');\n const config = JSON.parse(raw);\n expect(config.channels.telegram).toEqual(sampleEntry);\n });\n\n it('should create parent directory if missing', async () => {\n const nestedPath = path.join(tmpDir, 'nested', 'dir', 'channels.json');\n const nestedStore = new ConfigStore(nestedPath);\n\n await nestedStore.saveChannel('telegram', sampleEntry);\n\n expect(fs.existsSync(nestedPath)).toBe(true);\n });\n\n it('should set file permissions to 0600', async () => {\n await store.saveChannel('telegram', sampleEntry);\n\n const stats = fs.statSync(configPath);\n const mode = (stats.mode & 0o777).toString(8);\n expect(mode).toBe('600');\n });\n\n it('should repair permissive permissions on an existing config file', async () => {\n fs.writeFileSync(configPath, JSON.stringify({ channels: {} }), { mode: 0o644 });\n fs.chmodSync(configPath, 0o644);\n\n await store.saveChannel('slack', slackEntry);\n\n expect(fs.statSync(configPath).mode & 0o777).toBe(0o600);\n });\n\n it('should preserve existing channels when adding a new one', async () => {\n await store.saveChannel('telegram', sampleEntry);\n await store.saveChannel('slack', slackEntry);\n\n const config = await store.getConfig();\n expect(Object.keys(config.channels)).toEqual(['telegram', 'slack']);\n expect(config.channels.slack).toEqual(slackEntry);\n });\n\n it('should preserve separate Telegram configs by channel name', async () => {\n await store.saveChannel('personal', {\n ...sampleEntry,\n config: {\n botToken: 'personal-token',\n botUsername: 'personal_bot',\n authorizedChatId: 111,\n },\n });\n await store.saveChannel('work', {\n ...sampleEntry,\n config: {\n botToken: 'work-token',\n botUsername: 'work_bot',\n authorizedChatId: 222,\n },\n });\n\n const config = await store.getConfig();\n expect(config.channels.personal.config).toEqual({\n botToken: 'personal-token',\n botUsername: 'personal_bot',\n authorizedChatId: 111,\n });\n expect(config.channels.work.config).toEqual({\n botToken: 'work-token',\n botUsername: 'work_bot',\n authorizedChatId: 222,\n });\n });\n });\n\n describe('removeChannel', () => {\n it('should remove a channel entry', async () => {\n await store.saveChannel('telegram', sampleEntry);\n await store.removeChannel('telegram');\n\n const config = await store.getConfig();\n expect(config.channels.telegram).toBeUndefined();\n });\n\n it('should not throw when removing non-existent channel', async () => {\n await expect(store.removeChannel('nonexistent')).resolves.toBeUndefined();\n });\n });\n\n describe('getChannel', () => {\n it('should return the channel entry', async () => {\n await store.saveChannel('telegram', sampleEntry);\n\n const entry = await store.getChannel('telegram');\n expect(entry).toEqual(sampleEntry);\n });\n\n it('should return undefined for non-existent channel', async () => {\n const entry = await store.getChannel('slack');\n expect(entry).toBeUndefined();\n });\n });\n});\n"],"names":["fs","path","os","ConfigStore","isSlackEntry","describe","tmpDir","configPath","store","beforeEach","mkdtempSync","join","tmpdir","afterEach","rmSync","recursive","force","sampleEntry","type","enabled","createdAt","config","botToken","botUsername","slackEntry","appToken","appId","botUserId","workspaceId","workspaceName","transport","audience","it","defaultStore","getConfig","expect","toBeDefined","toBe","Error","toEqual","channels","writeFileSync","JSON","stringify","telegram","saveChannel","raw","readFileSync","parse","nestedPath","nestedStore","existsSync","stats","statSync","mode","toString","chmodSync","Object","keys","slack","authorizedChatId","personal","work","removeChannel","toBeUndefined","resolves","entry","getChannel"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/__tests__/adapters/SlackAdapter.test.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\nimport { SlackAdapter, validateSlackAppToken, validateSlackCredentials } from '../../adapters/SlackAdapter.js';\nimport type { SlackConfig } from '../../types.js';\n\nclass FakeSocketClient extends EventEmitter {\n start = vi.fn().mockResolvedValue(undefined);\n disconnect = vi.fn().mockResolvedValue(undefined);\n}\n\nconst config: SlackConfig = {\n appToken: 'xapp-fake',\n botToken: 'xoxb-fake',\n appId: 'A123',\n botUserId: 'U-BOT',\n workspaceId: 'T123',\n transport: 'socket-mode',\n audience: 'dm',\n};\n\nfunction envelope(overrides: Record<string, unknown> = {}) {\n return {\n type: 'events_api',\n ack: vi.fn().mockResolvedValue(undefined),\n body: {\n team_id: 'T123',\n event_id: 'Ev123',\n event: {\n type: 'message',\n channel_type: 'im',\n channel: 'D123',\n user: 'U123',\n text: 'run tests',\n ts: '100.1',\n event_ts: '100.1',\n ...overrides,\n },\n },\n };\n}\n\ndescribe('SlackAdapter', () => {\n it('validates bot identity without returning either credential', async () => {\n const authTest = vi.fn().mockResolvedValue({ ok: true, app_id: 'A123', user_id: 'U-BOT', team_id: 'T123', team: 'Sandbox' });\n await expect(validateSlackCredentials('xoxb-fake', { authTest })).resolves.toEqual({\n appId: 'A123', botUserId: 'U-BOT', workspaceId: 'T123', workspaceName: 'Sandbox',\n });\n });\n\n it('accepts Slack documented bot identity without an app ID', async () => {\n const authTest = vi.fn().mockResolvedValue({\n ok: true,\n bot_id: 'B123',\n user_id: 'U-BOT',\n team_id: 'T123',\n team: 'Sandbox',\n });\n await expect(validateSlackCredentials('xoxb-fake', { authTest })).resolves.toEqual({\n botUserId: 'U-BOT',\n workspaceId: 'T123',\n workspaceName: 'Sandbox',\n });\n });\n\n it('rejects incomplete Slack credential identity', async () => {\n const authTest = vi.fn().mockResolvedValue({ ok: true, team_id: 'T123' });\n await expect(validateSlackCredentials('xoxb-fake', { authTest })).rejects.toThrow('Slack bot token returned incomplete identity');\n });\n\n it('validates an app token through apps.connections.open', async () => {\n const open = vi.fn().mockResolvedValue({ ok: true, url: 'wss://wss-primary.slack.com/link/' });\n await expect(validateSlackAppToken('xapp-fake', { open })).resolves.toBeUndefined();\n expect(open).toHaveBeenCalledOnce();\n });\n\n it('rejects an app token that cannot open Socket Mode', async () => {\n const open = vi.fn().mockResolvedValue({ ok: false });\n await expect(validateSlackAppToken('xapp-fake', { open })).rejects.toThrow('Slack app token cannot open Socket Mode');\n });\n\n it('starts and stops the official Socket Mode client and reports health', async () => {\n const socket = new FakeSocketClient();\n const adapter = new SlackAdapter(config, { socketClient: socket, webClient: { chat: { postMessage: vi.fn() } } });\n expect(await adapter.isHealthy()).toBe(false);\n await adapter.start();\n expect(socket.start).toHaveBeenCalledOnce();\n expect(await adapter.isHealthy()).toBe(true);\n await adapter.stop();\n expect(socket.disconnect).toHaveBeenCalledOnce();\n expect(await adapter.isHealthy()).toBe(false);\n });\n\n it('does not register duplicate listeners across restarts', async () => {\n const socket = new FakeSocketClient();\n const adapter = new SlackAdapter(config, { socketClient: socket, webClient: { chat: { postMessage: vi.fn() } } });\n await adapter.start();\n await adapter.stop();\n await adapter.start();\n expect(socket.listenerCount('slack_event')).toBe(1);\n expect(socket.listenerCount('interactive')).toBe(1);\n socket.emit('disconnected');\n expect(await adapter.isHealthy()).toBe(false);\n socket.emit('connected');\n expect(await adapter.isHealthy()).toBe(true);\n });\n\n it('acknowledges before delivering one normalized workspace DM event', async () => {\n const socket = new FakeSocketClient();\n const adapter = new SlackAdapter(config, { socketClient: socket, webClient: { chat: { postMessage: vi.fn() } } });\n const order: string[] = [];\n adapter.onMessage(vi.fn(async (message) => {\n order.push('handler');\n expect(message).toMatchObject({\n channelType: 'slack', chatId: 'D123', userId: 'U123', workspaceId: 'T123', messageId: 'Ev123', text: 'run tests',\n });\n }));\n await adapter.start();\n const item = envelope();\n item.ack.mockImplementation(async () => { order.push('ack'); });\n socket.emit('slack_event', item);\n await vi.waitFor(() => expect(order).toEqual(['ack', 'handler']));\n socket.emit('slack_event', item);\n await new Promise((resolve) => setTimeout(resolve, 0));\n expect(order).toEqual(['ack', 'handler', 'ack']);\n });\n\n it.each([\n ['wrong workspace', {}, { team_id: 'T999' }],\n ['bot message', { bot_id: 'B123' }, {}],\n ['self message', { user: 'U-BOT' }, {}],\n ['subtype', { subtype: 'message_changed' }, {}],\n ['non-DM', { channel_type: 'channel' }, {}],\n ])('ignores %s events', async (_name, eventOverrides, bodyOverrides) => {\n const socket = new FakeSocketClient();\n const handler = vi.fn();\n const adapter = new SlackAdapter(config, { socketClient: socket, webClient: { chat: { postMessage: vi.fn() } } });\n adapter.onMessage(handler);\n await adapter.start();\n const item = envelope(eventOverrides);\n Object.assign(item.body, bodyOverrides);\n socket.emit('slack_event', item);\n await vi.waitFor(() => expect(item.ack).toHaveBeenCalled());\n expect(handler).not.toHaveBeenCalled();\n });\n\n it('delivers an ordinary workspace DM immediately without pairing', async () => {\n const socket = new FakeSocketClient();\n const handler = vi.fn();\n const adapter = new SlackAdapter(config, {\n socketClient: socket,\n webClient: { chat: { postMessage: vi.fn() } },\n });\n adapter.onMessage(handler);\n await adapter.start();\n\n socket.emit('slack_event', envelope({ text: 'run tests' }));\n\n await vi.waitFor(() => expect(handler).toHaveBeenCalledWith(expect.objectContaining({\n chatId: 'D123', userId: 'U123', text: 'run tests', workspaceId: 'T123',\n })));\n });\n\n it('sends an accessible Block Kit question and finalizes its actions', async () => {\n const socket = new FakeSocketClient();\n const postMessage = vi.fn().mockResolvedValue({ ok: true, ts: '400.1' });\n const update = vi.fn().mockResolvedValue({ ok: true });\n const adapter = new SlackAdapter(config, { socketClient: socket, webClient: { chat: { postMessage, update } } });\n await expect(adapter.sendQuestion('D123', {\n id: 'q1', header: 'Scope', question: 'Choose one', allowSkip: true,\n options: [{ label: 'Safe', description: 'Read only', value: '1' }],\n })).resolves.toEqual({ messageId: '400.1' });\n expect(postMessage).toHaveBeenCalledWith(expect.objectContaining({\n channel: 'D123', text: 'Scope: Choose one', blocks: expect.any(Array),\n }));\n await adapter.finalizeInteraction('D123', '400.1');\n expect(update).toHaveBeenCalledWith({ channel: 'D123', ts: '400.1', blocks: [] });\n });\n\n it('escapes Slack control syntax in question fallback text', async () => {\n const postMessage = vi.fn().mockResolvedValue({ ok: true, ts: '400.1' });\n const adapter = new SlackAdapter(config, {\n socketClient: new FakeSocketClient(),\n webClient: { chat: { postMessage } },\n });\n await adapter.sendQuestion('D123', {\n id: 'q1', header: '<!channel>', question: 'Choose <one> & continue', allowSkip: false,\n options: [{ label: 'Safe', value: '1' }],\n });\n expect(postMessage).toHaveBeenCalledWith(expect.objectContaining({\n text: '&lt;!channel&gt;: Choose &lt;one&gt; &amp; continue',\n }));\n });\n\n it('acknowledges and delivers one valid workspace block action', async () => {\n const socket = new FakeSocketClient();\n const handler = vi.fn();\n const adapter = new SlackAdapter(config, { socketClient: socket, webClient: { chat: { postMessage: vi.fn() } } });\n adapter.onInteraction(handler);\n await adapter.start();\n const item = {\n ack: vi.fn().mockResolvedValue(undefined),\n body: {\n type: 'block_actions', team: { id: 'T123' }, user: { id: 'U123' },\n channel: { id: 'D123' }, container: { message_ts: '400.1' },\n actions: [{ action_id: 'ai_devkit_question', action_ts: '401.1', value: 'q1:1' }],\n },\n };\n socket.emit('interactive', item);\n await vi.waitFor(() => expect(handler).toHaveBeenCalledOnce());\n expect(item.ack).toHaveBeenCalledOnce();\n expect(handler).toHaveBeenCalledWith(expect.objectContaining({\n workspaceId: 'T123', chatId: 'D123', userId: 'U123', messageId: '400.1', value: 'q1:1',\n }));\n socket.emit('interactive', item);\n await new Promise((resolve) => setTimeout(resolve, 0));\n expect(handler).toHaveBeenCalledOnce();\n expect(item.ack).toHaveBeenCalledTimes(2);\n });\n\n it('does not acknowledge interactive envelopes a second time on the generic event stream', async () => {\n const socket = new FakeSocketClient();\n const adapter = new SlackAdapter(config, { socketClient: socket, webClient: { chat: { postMessage: vi.fn() } } });\n await adapter.start();\n const ack = vi.fn().mockResolvedValue(undefined);\n socket.emit('slack_event', { type: 'interactive', ack, body: {} });\n await new Promise((resolve) => setTimeout(resolve, 0));\n expect(ack).not.toHaveBeenCalled();\n });\n\n it('acknowledges malformed and wrong-workspace block actions without delivery', async () => {\n const socket = new FakeSocketClient();\n const handler = vi.fn();\n const adapter = new SlackAdapter(config, { socketClient: socket, webClient: { chat: { postMessage: vi.fn() } } });\n adapter.onInteraction(handler);\n await adapter.start();\n const ack = vi.fn().mockResolvedValue(undefined);\n socket.emit('interactive', { ack, body: { type: 'block_actions', team: { id: 'T999' }, actions: [] } });\n await vi.waitFor(() => expect(ack).toHaveBeenCalled());\n expect(handler).not.toHaveBeenCalled();\n });\n});\n"],"names":["EventEmitter","SlackAdapter","validateSlackAppToken","validateSlackCredentials","FakeSocketClient","start","vi","fn","mockResolvedValue","undefined","disconnect","config","appToken","botToken","appId","botUserId","workspaceId","transport","audience","envelope","overrides","type","ack","body","team_id","event_id","event","channel_type","channel","user","text","ts","event_ts","describe","it","authTest","ok","app_id","user_id","team","expect","resolves","toEqual","workspaceName","bot_id","rejects","toThrow","open","url","toBeUndefined","toHaveBeenCalledOnce","socket","adapter","socketClient","webClient","chat","postMessage","isHealthy","toBe","stop","listenerCount","emit","order","onMessage","message","push","toMatchObject","channelType","chatId","userId","messageId","item","mockImplementation","waitFor","Promise","resolve","setTimeout","each","subtype","_name","eventOverrides","bodyOverrides","handler","Object","assign","toHaveBeenCalled","not","toHaveBeenCalledWith","objectContaining","update","sendQuestion","id","header","question","allowSkip","options","label","description","value","blocks","any","Array","finalizeInteraction","onInteraction","container","message_ts","actions","action_id","action_ts","toHaveBeenCalledTimes"],"mappings":"AAAA,SAASA,YAAY,QAAQ,cAAc;AAC3C,SAASC,YAAY,EAAEC,qBAAqB,EAAEC,wBAAwB,QAAQ,iCAAiC;AAG/G,IAAA,AAAMC,mBAAN,MAAMA,yBAAyBJ;IAC3BK,QAAQC,GAAGC,EAAE,GAAGC,iBAAiB,CAACC,WAAW;IAC7CC,aAAaJ,GAAGC,EAAE,GAAGC,iBAAiB,CAACC,WAAW;AACtD;AAEA,MAAME,SAAsB;IACxBC,UAAU;IACVC,UAAU;IACVC,OAAO;IACPC,WAAW;IACXC,aAAa;IACbC,WAAW;IACXC,UAAU;AACd;AAEA,SAASC,SAASC,YAAqC,CAAC,CAAC;IACrD,OAAO;QACHC,MAAM;QACNC,KAAKhB,GAAGC,EAAE,GAAGC,iBAAiB,CAACC;QAC/Bc,MAAM;YACFC,SAAS;YACTC,UAAU;YACVC,OAAO;gBACHL,MAAM;gBACNM,cAAc;gBACdC,SAAS;gBACTC,MAAM;gBACNC,MAAM;gBACNC,IAAI;gBACJC,UAAU;gBACV,GAAGZ,SAAS;YAChB;QACJ;IACJ;AACJ;AAEAa,SAAS,gBAAgB;IACrBC,GAAG,8DAA8D;QAC7D,MAAMC,WAAW7B,GAAGC,EAAE,GAAGC,iBAAiB,CAAC;YAAE4B,IAAI;YAAMC,QAAQ;YAAQC,SAAS;YAASd,SAAS;YAAQe,MAAM;QAAU;QAC1H,MAAMC,OAAOrC,yBAAyB,aAAa;YAAEgC;QAAS,IAAIM,QAAQ,CAACC,OAAO,CAAC;YAC/E5B,OAAO;YAAQC,WAAW;YAASC,aAAa;YAAQ2B,eAAe;QAC3E;IACJ;IAEAT,GAAG,2DAA2D;QAC1D,MAAMC,WAAW7B,GAAGC,EAAE,GAAGC,iBAAiB,CAAC;YACvC4B,IAAI;YACJQ,QAAQ;YACRN,SAAS;YACTd,SAAS;YACTe,MAAM;QACV;QACA,MAAMC,OAAOrC,yBAAyB,aAAa;YAAEgC;QAAS,IAAIM,QAAQ,CAACC,OAAO,CAAC;YAC/E3B,WAAW;YACXC,aAAa;YACb2B,eAAe;QACnB;IACJ;IAEAT,GAAG,gDAAgD;QAC/C,MAAMC,WAAW7B,GAAGC,EAAE,GAAGC,iBAAiB,CAAC;YAAE4B,IAAI;YAAMZ,SAAS;QAAO;QACvE,MAAMgB,OAAOrC,yBAAyB,aAAa;YAAEgC;QAAS,IAAIU,OAAO,CAACC,OAAO,CAAC;IACtF;IAEAZ,GAAG,wDAAwD;QACvD,MAAMa,OAAOzC,GAAGC,EAAE,GAAGC,iBAAiB,CAAC;YAAE4B,IAAI;YAAMY,KAAK;QAAoC;QAC5F,MAAMR,OAAOtC,sBAAsB,aAAa;YAAE6C;QAAK,IAAIN,QAAQ,CAACQ,aAAa;QACjFT,OAAOO,MAAMG,oBAAoB;IACrC;IAEAhB,GAAG,qDAAqD;QACpD,MAAMa,OAAOzC,GAAGC,EAAE,GAAGC,iBAAiB,CAAC;YAAE4B,IAAI;QAAM;QACnD,MAAMI,OAAOtC,sBAAsB,aAAa;YAAE6C;QAAK,IAAIF,OAAO,CAACC,OAAO,CAAC;IAC/E;IAEAZ,GAAG,uEAAuE;QACtE,MAAMiB,SAAS,IAAI/C;QACnB,MAAMgD,UAAU,IAAInD,aAAaU,QAAQ;YAAE0C,cAAcF;YAAQG,WAAW;gBAAEC,MAAM;oBAAEC,aAAalD,GAAGC,EAAE;gBAAG;YAAE;QAAE;QAC/GiC,OAAO,MAAMY,QAAQK,SAAS,IAAIC,IAAI,CAAC;QACvC,MAAMN,QAAQ/C,KAAK;QACnBmC,OAAOW,OAAO9C,KAAK,EAAE6C,oBAAoB;QACzCV,OAAO,MAAMY,QAAQK,SAAS,IAAIC,IAAI,CAAC;QACvC,MAAMN,QAAQO,IAAI;QAClBnB,OAAOW,OAAOzC,UAAU,EAAEwC,oBAAoB;QAC9CV,OAAO,MAAMY,QAAQK,SAAS,IAAIC,IAAI,CAAC;IAC3C;IAEAxB,GAAG,yDAAyD;QACxD,MAAMiB,SAAS,IAAI/C;QACnB,MAAMgD,UAAU,IAAInD,aAAaU,QAAQ;YAAE0C,cAAcF;YAAQG,WAAW;gBAAEC,MAAM;oBAAEC,aAAalD,GAAGC,EAAE;gBAAG;YAAE;QAAE;QAC/G,MAAM6C,QAAQ/C,KAAK;QACnB,MAAM+C,QAAQO,IAAI;QAClB,MAAMP,QAAQ/C,KAAK;QACnBmC,OAAOW,OAAOS,aAAa,CAAC,gBAAgBF,IAAI,CAAC;QACjDlB,OAAOW,OAAOS,aAAa,CAAC,gBAAgBF,IAAI,CAAC;QACjDP,OAAOU,IAAI,CAAC;QACZrB,OAAO,MAAMY,QAAQK,SAAS,IAAIC,IAAI,CAAC;QACvCP,OAAOU,IAAI,CAAC;QACZrB,OAAO,MAAMY,QAAQK,SAAS,IAAIC,IAAI,CAAC;IAC3C;IAEAxB,GAAG,oEAAoE;QACnE,MAAMiB,SAAS,IAAI/C;QACnB,MAAMgD,UAAU,IAAInD,aAAaU,QAAQ;YAAE0C,cAAcF;YAAQG,WAAW;gBAAEC,MAAM;oBAAEC,aAAalD,GAAGC,EAAE;gBAAG;YAAE;QAAE;QAC/G,MAAMuD,QAAkB,EAAE;QAC1BV,QAAQW,SAAS,CAACzD,GAAGC,EAAE,CAAC,OAAOyD;YAC3BF,MAAMG,IAAI,CAAC;YACXzB,OAAOwB,SAASE,aAAa,CAAC;gBAC1BC,aAAa;gBAASC,QAAQ;gBAAQC,QAAQ;gBAAQrD,aAAa;gBAAQsD,WAAW;gBAASxC,MAAM;YACzG;QACJ;QACA,MAAMsB,QAAQ/C,KAAK;QACnB,MAAMkE,OAAOpD;QACboD,KAAKjD,GAAG,CAACkD,kBAAkB,CAAC;YAAcV,MAAMG,IAAI,CAAC;QAAQ;QAC7Dd,OAAOU,IAAI,CAAC,eAAeU;QAC3B,MAAMjE,GAAGmE,OAAO,CAAC,IAAMjC,OAAOsB,OAAOpB,OAAO,CAAC;gBAAC;gBAAO;aAAU;QAC/DS,OAAOU,IAAI,CAAC,eAAeU;QAC3B,MAAM,IAAIG,QAAQ,CAACC,UAAYC,WAAWD,SAAS;QACnDnC,OAAOsB,OAAOpB,OAAO,CAAC;YAAC;YAAO;YAAW;SAAM;IACnD;IAEAR,GAAG2C,IAAI,CAAC;QACJ;YAAC;YAAmB,CAAC;YAAG;gBAAErD,SAAS;YAAO;SAAE;QAC5C;YAAC;YAAe;gBAAEoB,QAAQ;YAAO;YAAG,CAAC;SAAE;QACvC;YAAC;YAAgB;gBAAEf,MAAM;YAAQ;YAAG,CAAC;SAAE;QACvC;YAAC;YAAW;gBAAEiD,SAAS;YAAkB;YAAG,CAAC;SAAE;QAC/C;YAAC;YAAU;gBAAEnD,cAAc;YAAU;YAAG,CAAC;SAAE;KAC9C,EAAE,qBAAqB,OAAOoD,OAAOC,gBAAgBC;QAClD,MAAM9B,SAAS,IAAI/C;QACnB,MAAM8E,UAAU5E,GAAGC,EAAE;QACrB,MAAM6C,UAAU,IAAInD,aAAaU,QAAQ;YAAE0C,cAAcF;YAAQG,WAAW;gBAAEC,MAAM;oBAAEC,aAAalD,GAAGC,EAAE;gBAAG;YAAE;QAAE;QAC/G6C,QAAQW,SAAS,CAACmB;QAClB,MAAM9B,QAAQ/C,KAAK;QACnB,MAAMkE,OAAOpD,SAAS6D;QACtBG,OAAOC,MAAM,CAACb,KAAKhD,IAAI,EAAE0D;QACzB9B,OAAOU,IAAI,CAAC,eAAeU;QAC3B,MAAMjE,GAAGmE,OAAO,CAAC,IAAMjC,OAAO+B,KAAKjD,GAAG,EAAE+D,gBAAgB;QACxD7C,OAAO0C,SAASI,GAAG,CAACD,gBAAgB;IACxC;IAEAnD,GAAG,iEAAiE;QAChE,MAAMiB,SAAS,IAAI/C;QACnB,MAAM8E,UAAU5E,GAAGC,EAAE;QACrB,MAAM6C,UAAU,IAAInD,aAAaU,QAAQ;YACrC0C,cAAcF;YACdG,WAAW;gBAAEC,MAAM;oBAAEC,aAAalD,GAAGC,EAAE;gBAAG;YAAE;QAChD;QACA6C,QAAQW,SAAS,CAACmB;QAClB,MAAM9B,QAAQ/C,KAAK;QAEnB8C,OAAOU,IAAI,CAAC,eAAe1C,SAAS;YAAEW,MAAM;QAAY;QAExD,MAAMxB,GAAGmE,OAAO,CAAC,IAAMjC,OAAO0C,SAASK,oBAAoB,CAAC/C,OAAOgD,gBAAgB,CAAC;gBAChFpB,QAAQ;gBAAQC,QAAQ;gBAAQvC,MAAM;gBAAad,aAAa;YACpE;IACJ;IAEAkB,GAAG,oEAAoE;QACnE,MAAMiB,SAAS,IAAI/C;QACnB,MAAMoD,cAAclD,GAAGC,EAAE,GAAGC,iBAAiB,CAAC;YAAE4B,IAAI;YAAML,IAAI;QAAQ;QACtE,MAAM0D,SAASnF,GAAGC,EAAE,GAAGC,iBAAiB,CAAC;YAAE4B,IAAI;QAAK;QACpD,MAAMgB,UAAU,IAAInD,aAAaU,QAAQ;YAAE0C,cAAcF;YAAQG,WAAW;gBAAEC,MAAM;oBAAEC;oBAAaiC;gBAAO;YAAE;QAAE;QAC9G,MAAMjD,OAAOY,QAAQsC,YAAY,CAAC,QAAQ;YACtCC,IAAI;YAAMC,QAAQ;YAASC,UAAU;YAAcC,WAAW;YAC9DC,SAAS;gBAAC;oBAAEC,OAAO;oBAAQC,aAAa;oBAAaC,OAAO;gBAAI;aAAE;QACtE,IAAIzD,QAAQ,CAACC,OAAO,CAAC;YAAE4B,WAAW;QAAQ;QAC1C9B,OAAOgB,aAAa+B,oBAAoB,CAAC/C,OAAOgD,gBAAgB,CAAC;YAC7D5D,SAAS;YAAQE,MAAM;YAAqBqE,QAAQ3D,OAAO4D,GAAG,CAACC;QACnE;QACA,MAAMjD,QAAQkD,mBAAmB,CAAC,QAAQ;QAC1C9D,OAAOiD,QAAQF,oBAAoB,CAAC;YAAE3D,SAAS;YAAQG,IAAI;YAASoE,QAAQ,EAAE;QAAC;IACnF;IAEAjE,GAAG,0DAA0D;QACzD,MAAMsB,cAAclD,GAAGC,EAAE,GAAGC,iBAAiB,CAAC;YAAE4B,IAAI;YAAML,IAAI;QAAQ;QACtE,MAAMqB,UAAU,IAAInD,aAAaU,QAAQ;YACrC0C,cAAc,IAAIjD;YAClBkD,WAAW;gBAAEC,MAAM;oBAAEC;gBAAY;YAAE;QACvC;QACA,MAAMJ,QAAQsC,YAAY,CAAC,QAAQ;YAC/BC,IAAI;YAAMC,QAAQ;YAAcC,UAAU;YAA2BC,WAAW;YAChFC,SAAS;gBAAC;oBAAEC,OAAO;oBAAQE,OAAO;gBAAI;aAAE;QAC5C;QACA1D,OAAOgB,aAAa+B,oBAAoB,CAAC/C,OAAOgD,gBAAgB,CAAC;YAC7D1D,MAAM;QACV;IACJ;IAEAI,GAAG,8DAA8D;QAC7D,MAAMiB,SAAS,IAAI/C;QACnB,MAAM8E,UAAU5E,GAAGC,EAAE;QACrB,MAAM6C,UAAU,IAAInD,aAAaU,QAAQ;YAAE0C,cAAcF;YAAQG,WAAW;gBAAEC,MAAM;oBAAEC,aAAalD,GAAGC,EAAE;gBAAG;YAAE;QAAE;QAC/G6C,QAAQmD,aAAa,CAACrB;QACtB,MAAM9B,QAAQ/C,KAAK;QACnB,MAAMkE,OAAO;YACTjD,KAAKhB,GAAGC,EAAE,GAAGC,iBAAiB,CAACC;YAC/Bc,MAAM;gBACFF,MAAM;gBAAiBkB,MAAM;oBAAEoD,IAAI;gBAAO;gBAAG9D,MAAM;oBAAE8D,IAAI;gBAAO;gBAChE/D,SAAS;oBAAE+D,IAAI;gBAAO;gBAAGa,WAAW;oBAAEC,YAAY;gBAAQ;gBAC1DC,SAAS;oBAAC;wBAAEC,WAAW;wBAAsBC,WAAW;wBAASV,OAAO;oBAAO;iBAAE;YACrF;QACJ;QACA/C,OAAOU,IAAI,CAAC,eAAeU;QAC3B,MAAMjE,GAAGmE,OAAO,CAAC,IAAMjC,OAAO0C,SAAShC,oBAAoB;QAC3DV,OAAO+B,KAAKjD,GAAG,EAAE4B,oBAAoB;QACrCV,OAAO0C,SAASK,oBAAoB,CAAC/C,OAAOgD,gBAAgB,CAAC;YACzDxE,aAAa;YAAQoD,QAAQ;YAAQC,QAAQ;YAAQC,WAAW;YAAS4B,OAAO;QACpF;QACA/C,OAAOU,IAAI,CAAC,eAAeU;QAC3B,MAAM,IAAIG,QAAQ,CAACC,UAAYC,WAAWD,SAAS;QACnDnC,OAAO0C,SAAShC,oBAAoB;QACpCV,OAAO+B,KAAKjD,GAAG,EAAEuF,qBAAqB,CAAC;IAC3C;IAEA3E,GAAG,wFAAwF;QACvF,MAAMiB,SAAS,IAAI/C;QACnB,MAAMgD,UAAU,IAAInD,aAAaU,QAAQ;YAAE0C,cAAcF;YAAQG,WAAW;gBAAEC,MAAM;oBAAEC,aAAalD,GAAGC,EAAE;gBAAG;YAAE;QAAE;QAC/G,MAAM6C,QAAQ/C,KAAK;QACnB,MAAMiB,MAAMhB,GAAGC,EAAE,GAAGC,iBAAiB,CAACC;QACtC0C,OAAOU,IAAI,CAAC,eAAe;YAAExC,MAAM;YAAeC;YAAKC,MAAM,CAAC;QAAE;QAChE,MAAM,IAAImD,QAAQ,CAACC,UAAYC,WAAWD,SAAS;QACnDnC,OAAOlB,KAAKgE,GAAG,CAACD,gBAAgB;IACpC;IAEAnD,GAAG,6EAA6E;QAC5E,MAAMiB,SAAS,IAAI/C;QACnB,MAAM8E,UAAU5E,GAAGC,EAAE;QACrB,MAAM6C,UAAU,IAAInD,aAAaU,QAAQ;YAAE0C,cAAcF;YAAQG,WAAW;gBAAEC,MAAM;oBAAEC,aAAalD,GAAGC,EAAE;gBAAG;YAAE;QAAE;QAC/G6C,QAAQmD,aAAa,CAACrB;QACtB,MAAM9B,QAAQ/C,KAAK;QACnB,MAAMiB,MAAMhB,GAAGC,EAAE,GAAGC,iBAAiB,CAACC;QACtC0C,OAAOU,IAAI,CAAC,eAAe;YAAEvC;YAAKC,MAAM;gBAAEF,MAAM;gBAAiBkB,MAAM;oBAAEoD,IAAI;gBAAO;gBAAGe,SAAS,EAAE;YAAC;QAAE;QACrG,MAAMpG,GAAGmE,OAAO,CAAC,IAAMjC,OAAOlB,KAAK+D,gBAAgB;QACnD7C,OAAO0C,SAASI,GAAG,CAACD,gBAAgB;IACxC;AACJ"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/__tests__/adapters/TelegramAdapter.test.ts"],"sourcesContent":["import * as telegrafModule from 'telegraf';\nimport * as telegramHtml from '../../utils/telegramHtml.js';\nimport { TelegramAdapter } from '../../adapters/TelegramAdapter.js';\nimport type { IncomingMessage } from '../../types.js';\n\n// Mock telegraf\nvi.mock('telegraf', () => {\n const handlers: Record<string, (...args: any[]) => any> = {};\n const mockBot = {\n launch: vi.fn().mockResolvedValue(undefined),\n stop: vi.fn().mockResolvedValue(undefined),\n on: vi.fn((event: string, handler: (...args: any[]) => any) => {\n handlers[event] = handler;\n }),\n telegram: {\n sendMessage: vi.fn().mockResolvedValue(undefined),\n editMessageReplyMarkup: vi.fn().mockResolvedValue(undefined),\n answerCbQuery: vi.fn().mockResolvedValue(undefined),\n getMe: vi.fn().mockResolvedValue({ username: 'test_bot' }),\n },\n _handlers: handlers,\n _triggerText: async (chatId: number, userId: number, text: string) => {\n const ctx = {\n message: {\n chat: { id: chatId },\n from: { id: userId },\n text,\n date: Math.floor(Date.now() / 1000),\n },\n reply: vi.fn().mockResolvedValue(undefined),\n };\n if (handlers['text']) {\n await handlers['text'](ctx);\n }\n return ctx;\n },\n _triggerCallback: async (chatId: number, userId: number, data: string, messageId = 555) => {\n const ctx = {\n callbackQuery: {\n id: 'cbq-test',\n data,\n message: { message_id: messageId, chat: { id: chatId } },\n from: { id: userId },\n },\n answerCbQuery: vi.fn().mockResolvedValue(undefined),\n };\n if (handlers['callback_query']) {\n await handlers['callback_query'](ctx);\n }\n return ctx;\n },\n };\n return {\n Telegraf: vi.fn(function () { return mockBot; }),\n __mockBot: mockBot,\n };\n});\n\nfunction getMockBot() {\n return (telegrafModule as unknown as { __mockBot: ReturnType<typeof vi.fn>['mock'] & Record<string, unknown> }).__mockBot;\n}\n\nfunction expectHtmlChunkWithinLimit(chunk: string): void {\n expect(chunk.length).toBeLessThanOrEqual(4096);\n expect(chunk).not.toMatch(/&(?:l|lt|g|gt|a|am|amp|q|qu|quo|quot)$/);\n expect((chunk.match(/<pre>/g) ?? []).length).toBe((chunk.match(/<\\/pre>/g) ?? []).length);\n expect((chunk.match(/<code(?: class=\"language-[^\"]+\")?>/g) ?? []).length).toBe((chunk.match(/<\\/code>/g) ?? []).length);\n}\n\ndescribe('TelegramAdapter', () => {\n let adapter: TelegramAdapter;\n\n beforeEach(() => {\n vi.clearAllMocks();\n adapter = new TelegramAdapter({ botToken: 'test-token-123' });\n });\n\n describe('type', () => {\n it('should return \"telegram\"', () => {\n expect(adapter.type).toBe('telegram');\n });\n });\n\n describe('start', () => {\n it('should launch the telegraf bot', async () => {\n const bot = getMockBot();\n await adapter.start();\n expect(bot.launch).toHaveBeenCalled();\n });\n });\n\n describe('stop', () => {\n it('should stop the telegraf bot', async () => {\n const bot = getMockBot();\n await adapter.start();\n await adapter.stop();\n expect(bot.stop).toHaveBeenCalled();\n });\n });\n\n describe('onMessage', () => {\n it('should silently ignore messages when no handler is registered', async () => {\n // Don't register a handler\n await adapter.start();\n\n const bot = getMockBot();\n const ctx = await bot._triggerText(12345, 67890, 'hello');\n\n // Should not throw or reply\n expect(ctx.reply).not.toHaveBeenCalled();\n });\n\n it('should handle non-Error thrown by handler', async () => {\n const handler = vi.fn().mockRejectedValue('string error');\n adapter.onMessage(handler);\n await adapter.start();\n\n const bot = getMockBot();\n const ctx = await bot._triggerText(12345, 67890, 'hello');\n\n expect(ctx.reply).toHaveBeenCalledWith(\n 'Error processing message: Unknown error'\n );\n });\n\n it('should call handler with IncomingMessage on incoming text', async () => {\n const handler = vi.fn().mockResolvedValue(undefined);\n adapter.onMessage(handler);\n await adapter.start();\n\n const bot = getMockBot();\n await bot._triggerText(12345, 67890, 'hello agent');\n\n expect(handler).toHaveBeenCalledTimes(1);\n const msg: IncomingMessage = handler.mock.calls[0][0];\n expect(msg.channelType).toBe('telegram');\n expect(msg.chatId).toBe('12345');\n expect(msg.userId).toBe('67890');\n expect(msg.text).toBe('hello agent');\n expect(msg.timestamp).toBeInstanceOf(Date);\n });\n\n it('should handle handler errors gracefully', async () => {\n const handler = vi.fn().mockRejectedValue(new Error('handler failed'));\n adapter.onMessage(handler);\n await adapter.start();\n\n const bot = getMockBot();\n const ctx = await bot._triggerText(12345, 67890, 'hello');\n\n // Should not throw, and should reply with error\n expect(ctx.reply).toHaveBeenCalledWith(\n expect.stringContaining('Error processing message')\n );\n });\n });\n\n describe('sendMessage', () => {\n it('should send plain text with parse_mode HTML', async () => {\n const bot = getMockBot();\n await adapter.sendMessage('12345', 'hello from bot');\n\n expect(bot.telegram.sendMessage).toHaveBeenCalledWith(\n '12345',\n 'hello from bot',\n { parse_mode: 'HTML' }\n );\n });\n\n it('should render markdown as Telegram HTML', async () => {\n const bot = getMockBot();\n await adapter.sendMessage('12345', '**bold** and *italic* and `code`');\n\n const sent = bot.telegram.sendMessage.mock.calls[0][1];\n expect(sent).toContain('<b>bold</b>');\n expect(sent).toContain('<i>italic</i>');\n expect(sent).toContain('<code>code</code>');\n expect(bot.telegram.sendMessage.mock.calls[0][2]).toEqual({\n parse_mode: 'HTML',\n });\n });\n\n it('should chunk messages exceeding 4096 chars', async () => {\n const bot = getMockBot();\n const line = 'A'.repeat(100) + '\\n';\n const longMessage = line.repeat(50); // 5050 chars\n\n await adapter.sendMessage('12345', longMessage);\n\n expect(bot.telegram.sendMessage.mock.calls.length).toBeGreaterThan(1);\n for (const call of bot.telegram.sendMessage.mock.calls) {\n expect(call[1].length).toBeLessThanOrEqual(4096);\n expect(call[2]).toEqual({ parse_mode: 'HTML' });\n }\n });\n\n it('should split long fenced code into independently valid HTML code blocks', async () => {\n const bot = getMockBot();\n const codeLine = 'const sample = \"<code>tag</code>\" && value < limit;\\n';\n const longMessage = `Before\\n\\n\\`\\`\\`ts\\n${codeLine.repeat(100)}\\`\\`\\`\\n\\nAfter`;\n\n await adapter.sendMessage('12345', longMessage);\n\n expect(bot.telegram.sendMessage.mock.calls.length).toBeGreaterThan(1);\n for (const call of bot.telegram.sendMessage.mock.calls) {\n const chunk = call[1];\n expect(call[2]).toEqual({ parse_mode: 'HTML' });\n expectHtmlChunkWithinLimit(chunk);\n if (chunk.includes('<pre>')) {\n expect(chunk).toContain('<code class=\"language-ts\">');\n expect(chunk).toContain('&lt;code&gt;tag&lt;/code&gt;');\n }\n }\n });\n\n it('should split nested list fenced code without sending partial HTML tags', async () => {\n const bot = getMockBot();\n const codeLine = ' return \"<code>tag</code>\" && input < output;\\n';\n const longMessage = [\n '- parent item',\n ' - child item with code',\n ' ```js',\n codeLine.repeat(100).trimEnd(),\n ' ```',\n '- final item',\n ].join('\\n');\n\n await adapter.sendMessage('12345', longMessage);\n\n expect(bot.telegram.sendMessage.mock.calls.length).toBeGreaterThan(1);\n for (const call of bot.telegram.sendMessage.mock.calls) {\n const chunk = call[1];\n expect(call[2]).toEqual({ parse_mode: 'HTML' });\n expectHtmlChunkWithinLimit(chunk);\n }\n });\n\n it('should split long paragraphs at readable markdown boundaries', async () => {\n const bot = getMockBot();\n const sentence = 'This is a long sentence with enough words to make chunking choose sentence boundaries. ';\n const longMessage = sentence.repeat(80);\n\n await adapter.sendMessage('12345', longMessage);\n\n expect(bot.telegram.sendMessage.mock.calls.length).toBeGreaterThan(1);\n for (const call of bot.telegram.sendMessage.mock.calls) {\n const chunk = call[1];\n expect(call[2]).toEqual({ parse_mode: 'HTML' });\n expectHtmlChunkWithinLimit(chunk);\n expect(chunk.endsWith('.') || chunk.endsWith('.\\n\\n') || chunk.endsWith(' ')).toBe(true);\n }\n });\n\n it('should keep emoji chunks within the configured JavaScript string length limit', async () => {\n const bot = getMockBot();\n const longMessage = `Status ${'🧪'.repeat(2500)}`;\n\n await adapter.sendMessage('12345', longMessage);\n\n expect(bot.telegram.sendMessage.mock.calls.length).toBeGreaterThan(1);\n for (const call of bot.telegram.sendMessage.mock.calls) {\n expect(call[1].length).toBeLessThanOrEqual(4096);\n expect(call[2]).toEqual({ parse_mode: 'HTML' });\n }\n });\n\n it('should hard split at 4096 when no newlines available', async () => {\n const bot = getMockBot();\n const longMessage = 'A'.repeat(5000);\n\n await adapter.sendMessage('12345', longMessage);\n\n expect(bot.telegram.sendMessage.mock.calls.length).toBe(2);\n expect(bot.telegram.sendMessage.mock.calls[0][1].length).toBe(4096);\n expect(bot.telegram.sendMessage.mock.calls[1][1].length).toBe(904);\n });\n\n it('should prefer paragraph (\\\\n\\\\n) over single \\\\n when chunking', async () => {\n const bot = getMockBot();\n // 4 paragraphs of ~1500 chars each, total > 4096\n const paragraph = 'A'.repeat(1500);\n const message = `${paragraph}\\n\\n${paragraph}\\n\\n${paragraph}\\n\\n${paragraph}`;\n\n await adapter.sendMessage('12345', message);\n\n // First chunk should end at a \\n\\n boundary, not mid-paragraph\n const firstChunk = bot.telegram.sendMessage.mock.calls[0][1];\n expect(firstChunk).toBe(`${paragraph}\\n\\n${paragraph}`);\n });\n\n it('should send short messages in a single call', async () => {\n const bot = getMockBot();\n await adapter.sendMessage('12345', 'short message');\n\n expect(bot.telegram.sendMessage).toHaveBeenCalledTimes(1);\n });\n\n it('should retry as plain text when Telegram rejects HTML with parse-entities error', async () => {\n const bot = getMockBot();\n const parseError = Object.assign(new Error('400: Bad Request'), {\n description: \"Bad Request: can't parse entities: Unsupported start tag \\\"foo\\\"\",\n });\n bot.telegram.sendMessage\n .mockRejectedValueOnce(parseError)\n .mockResolvedValueOnce(undefined);\n\n await adapter.sendMessage('12345', '**hello**');\n\n expect(bot.telegram.sendMessage).toHaveBeenCalledTimes(2);\n\n // First call: rendered HTML with parse_mode\n const [, htmlChunk, htmlOpts] = bot.telegram.sendMessage.mock.calls[0];\n expect(htmlChunk).toContain('<b>hello</b>');\n expect(htmlOpts).toEqual({ parse_mode: 'HTML' });\n\n // Second call: same content, plain text (tags stripped, no parse_mode)\n const [, plainChunk, plainOpts] = bot.telegram.sendMessage.mock.calls[1];\n expect(plainChunk).toBe('hello');\n expect(plainOpts).toBeUndefined();\n });\n\n it('should detect parse-entities error from \"message\" field too', async () => {\n const bot = getMockBot();\n // Some error shapes carry the marker on `message` rather than `description`\n const parseError = new Error(\"can't parse entities\");\n bot.telegram.sendMessage\n .mockRejectedValueOnce(parseError)\n .mockResolvedValueOnce(undefined);\n\n await adapter.sendMessage('12345', '**hi**');\n\n expect(bot.telegram.sendMessage).toHaveBeenCalledTimes(2);\n });\n\n it('should decode HTML entities when falling back to plain text', async () => {\n const bot = getMockBot();\n const parseError = Object.assign(new Error('400'), {\n description: \"Bad Request: can't parse entities\",\n });\n bot.telegram.sendMessage\n .mockRejectedValueOnce(parseError)\n .mockResolvedValueOnce(undefined);\n\n // Source has chars that escapeHtml encodes; fallback should decode them\n await adapter.sendMessage('12345', 'a < b && c > d');\n\n const [, plainChunk] = bot.telegram.sendMessage.mock.calls[1];\n expect(plainChunk).toContain('a < b && c > d');\n expect(plainChunk).not.toContain('&lt;');\n expect(plainChunk).not.toContain('&amp;');\n });\n\n it('should deliver nested lists without throwing', async () => {\n const bot = getMockBot();\n\n await adapter.sendMessage('12345', '- agent\\n - Status');\n\n expect(bot.telegram.sendMessage).toHaveBeenCalledTimes(1);\n expect(bot.telegram.sendMessage.mock.calls[0][1]).toContain('Status');\n });\n\n it('should send plain text when markdown formatting throws', async () => {\n const bot = getMockBot();\n const formatter = vi.spyOn(telegramHtml, 'markdownToTelegramHtml')\n .mockImplementationOnce(() => {\n throw new Error('formatter failed');\n });\n\n await adapter.sendMessage('12345', '- agent\\n - Status');\n\n expect(bot.telegram.sendMessage).toHaveBeenCalledTimes(1);\n expect(bot.telegram.sendMessage.mock.calls[0][0]).toBe('12345');\n expect(bot.telegram.sendMessage.mock.calls[0][1]).toBe('- agent\\n - Status');\n expect(bot.telegram.sendMessage.mock.calls[0][2]).toBeUndefined();\n\n formatter.mockRestore();\n });\n\n it('should propagate non-parse-entities errors without falling back', async () => {\n const bot = getMockBot();\n const otherError = Object.assign(new Error('403'), {\n description: 'Forbidden: bot was blocked by the user',\n });\n bot.telegram.sendMessage.mockRejectedValueOnce(otherError);\n\n await expect(adapter.sendMessage('12345', 'hi')).rejects.toBe(otherError);\n\n // Only the HTML attempt should have happened — no fallback retry\n expect(bot.telegram.sendMessage).toHaveBeenCalledTimes(1);\n });\n });\n\n describe('sendInlineKeyboard', () => {\n it('sends with parse_mode HTML and inline_keyboard payload, returns message_id', async () => {\n const bot = getMockBot();\n (bot.telegram.sendMessage as any).mockResolvedValueOnce({ message_id: 42 });\n\n const id = await adapter.sendInlineKeyboard('12345', '<b>hi</b>', [\n [{ text: 'A', callbackData: 'q:1:o:0' }],\n [{ text: 'B', callbackData: 'q:1:o:1' }],\n ]);\n\n expect(id).toBe(42);\n expect(bot.telegram.sendMessage).toHaveBeenCalledWith('12345', '<b>hi</b>', {\n parse_mode: 'HTML',\n reply_markup: {\n inline_keyboard: [\n [{ text: 'A', callback_data: 'q:1:o:0' }],\n [{ text: 'B', callback_data: 'q:1:o:1' }],\n ],\n },\n });\n });\n });\n\n describe('editInlineKeyboard', () => {\n it('replaces the keyboard on an existing message', async () => {\n const bot = getMockBot();\n await adapter.editInlineKeyboard('12345', 99, [[{ text: '✓ A', callbackData: 'q:1:o:0' }]]);\n expect(bot.telegram.editMessageReplyMarkup).toHaveBeenCalledWith('12345', 99, undefined, {\n inline_keyboard: [[{ text: '✓ A', callback_data: 'q:1:o:0' }]],\n });\n });\n\n it('passes undefined reply_markup to remove the keyboard', async () => {\n const bot = getMockBot();\n await adapter.editInlineKeyboard('12345', 99, null);\n expect(bot.telegram.editMessageReplyMarkup).toHaveBeenCalledWith('12345', 99, undefined, undefined);\n });\n });\n\n describe('answerCallback', () => {\n it('forwards id and optional text to telegraf', async () => {\n const bot = getMockBot();\n await adapter.answerCallback('cbq-1', 'thanks');\n expect(bot.telegram.answerCbQuery).toHaveBeenCalledWith('cbq-1', 'thanks');\n });\n });\n\n describe('onCallback', () => {\n it('invokes the registered handler with a normalized IncomingCallback', async () => {\n const handler = vi.fn().mockResolvedValue(undefined);\n adapter.onCallback(handler);\n await adapter.start();\n\n const bot = getMockBot();\n await (bot as any)._triggerCallback(12345, 67890, 'q:abc:o:1', 777);\n\n expect(handler).toHaveBeenCalledOnce();\n const cb = handler.mock.calls[0][0];\n expect(cb.channelType).toBe('telegram');\n expect(cb.chatId).toBe('12345');\n expect(cb.userId).toBe('67890');\n expect(cb.messageId).toBe(777);\n expect(cb.callbackData).toBe('q:abc:o:1');\n expect(cb.callbackQueryId).toBe('cbq-test');\n });\n\n it('answers callbacks when no handler is registered', async () => {\n await adapter.start();\n const bot = getMockBot();\n const ctx = await (bot as any)._triggerCallback(12345, 67890, 'q:x:o:0');\n expect(ctx.answerCbQuery).toHaveBeenCalled();\n });\n\n it('answers with error when handler rejects', async () => {\n adapter.onCallback(vi.fn().mockRejectedValue(new Error('boom')));\n await adapter.start();\n const bot = getMockBot();\n const ctx = await (bot as any)._triggerCallback(12345, 67890, 'q:x:o:0');\n expect(ctx.answerCbQuery).toHaveBeenCalledWith('Error');\n });\n });\n\n describe('isHealthy', () => {\n it('should return true after start', async () => {\n await adapter.start();\n expect(await adapter.isHealthy()).toBe(true);\n });\n\n it('should return false before start', async () => {\n expect(await adapter.isHealthy()).toBe(false);\n });\n\n it('should return false after stop', async () => {\n await adapter.start();\n await adapter.stop();\n expect(await adapter.isHealthy()).toBe(false);\n });\n });\n});\n"],"names":["telegrafModule","telegramHtml","TelegramAdapter","vi","mock","handlers","mockBot","launch","fn","mockResolvedValue","undefined","stop","on","event","handler","telegram","sendMessage","editMessageReplyMarkup","answerCbQuery","getMe","username","_handlers","_triggerText","chatId","userId","text","ctx","message","chat","id","from","date","Math","floor","Date","now","reply","_triggerCallback","data","messageId","callbackQuery","message_id","Telegraf","__mockBot","getMockBot","expectHtmlChunkWithinLimit","chunk","expect","length","toBeLessThanOrEqual","not","toMatch","match","toBe","describe","adapter","beforeEach","clearAllMocks","botToken","it","type","bot","start","toHaveBeenCalled","mockRejectedValue","onMessage","toHaveBeenCalledWith","toHaveBeenCalledTimes","msg","calls","channelType","timestamp","toBeInstanceOf","Error","stringContaining","parse_mode","sent","toContain","toEqual","line","repeat","longMessage","toBeGreaterThan","call","codeLine","includes","trimEnd","join","sentence","endsWith","paragraph","firstChunk","parseError","Object","assign","description","mockRejectedValueOnce","mockResolvedValueOnce","htmlChunk","htmlOpts","plainChunk","plainOpts","toBeUndefined","formatter","spyOn","mockImplementationOnce","mockRestore","otherError","rejects","sendInlineKeyboard","callbackData","reply_markup","inline_keyboard","callback_data","editInlineKeyboard","answerCallback","onCallback","toHaveBeenCalledOnce","cb","callbackQueryId","isHealthy"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/__tests__/utils/SlackDeliveryQueue.test.ts"],"sourcesContent":["import { SlackDeliveryQueue } from '../../utils/SlackDeliveryQueue.js';\n\ndescribe('SlackDeliveryQueue', () => {\n it('serializes long output as a parent followed by threaded continuations', async () => {\n const postMessage = vi.fn()\n .mockResolvedValueOnce({ ok: true, ts: '100.1' })\n .mockResolvedValue({ ok: true, ts: '100.2' });\n const queue = new SlackDeliveryQueue({ postMessage }, { maxMessageLength: 20 });\n const result = await queue.send('D123', 'first paragraph\\n\\nsecond paragraph that is long');\n expect(result).toEqual({ messageId: '100.1', threadId: '100.1' });\n expect(postMessage).toHaveBeenCalledTimes(3);\n expect(postMessage.mock.calls[0][0]).not.toHaveProperty('thread_ts');\n expect(postMessage.mock.calls[1][0]).toMatchObject({ channel: 'D123', thread_ts: '100.1' });\n expect(postMessage.mock.calls[2][0]).toMatchObject({ channel: 'D123', thread_ts: '100.1' });\n });\n\n it('waits for retryAfter before retrying a rate-limited API call', async () => {\n const error = Object.assign(new Error('rate limited'), { retryAfter: 2 });\n const postMessage = vi.fn().mockRejectedValueOnce(error).mockResolvedValue({ ok: true, ts: '200.1' });\n const sleep = vi.fn().mockResolvedValue(undefined);\n const queue = new SlackDeliveryQueue({ postMessage }, { sleep });\n await expect(queue.send('D123', 'hello')).resolves.toEqual({ messageId: '200.1', threadId: '200.1' });\n expect(sleep).toHaveBeenCalledWith(2000);\n expect(postMessage).toHaveBeenCalledTimes(2);\n });\n\n it('caps an excessive rate-limit delay', async () => {\n const error = Object.assign(new Error('rate limited'), { retryAfter: 86_400 });\n const postMessage = vi.fn().mockRejectedValueOnce(error).mockResolvedValue({ ok: true, ts: '200.1' });\n const sleep = vi.fn().mockResolvedValue(undefined);\n const queue = new SlackDeliveryQueue({ postMessage }, { sleep });\n await queue.send('D123', 'hello');\n expect(sleep).toHaveBeenCalledWith(60_000);\n });\n\n it('rejects overflow while a conversation send is pending', async () => {\n let release!: () => void;\n const pending = new Promise<{ ok: true; ts: string }>((resolve) => {\n release = () => resolve({ ok: true, ts: '300.1' });\n });\n const postMessage = vi.fn().mockReturnValue(pending);\n const queue = new SlackDeliveryQueue({ postMessage }, { maxQueueSize: 1 });\n const first = queue.send('D123', 'first');\n await expect(queue.send('D123', 'second')).rejects.toThrow('Slack delivery queue is full');\n release();\n await first;\n });\n\n it('rejects empty output and responses without a timestamp', async () => {\n const postMessage = vi.fn().mockResolvedValue({ ok: true });\n const queue = new SlackDeliveryQueue({ postMessage });\n await expect(queue.send('D123', '')).rejects.toThrow('Cannot send an empty Slack message');\n await expect(queue.send('D123', 'hello')).rejects.toThrow('Slack did not return a message timestamp');\n });\n\n it('propagates permanent and invalid rate-limit errors without sleeping', async () => {\n const sleep = vi.fn();\n const permanent = new Error('invalid_auth');\n const postMessage = vi.fn().mockRejectedValue(permanent);\n const queue = new SlackDeliveryQueue({ postMessage }, { sleep });\n await expect(queue.send('D123', 'hello')).rejects.toBe(permanent);\n expect(sleep).not.toHaveBeenCalled();\n });\n\n it('allows separate conversation queues to progress independently', async () => {\n const postMessage = vi.fn().mockImplementation(async ({ channel }) => ({ ok: true, ts: `${channel}.1` }));\n const queue = new SlackDeliveryQueue({ postMessage });\n await expect(Promise.all([queue.send('D1', 'one'), queue.send('D2', 'two')])).resolves.toHaveLength(2);\n expect(postMessage).toHaveBeenCalledTimes(2);\n });\n});\n"],"names":["SlackDeliveryQueue","describe","it","postMessage","vi","fn","mockResolvedValueOnce","ok","ts","mockResolvedValue","queue","maxMessageLength","result","send","expect","toEqual","messageId","threadId","toHaveBeenCalledTimes","mock","calls","not","toHaveProperty","toMatchObject","channel","thread_ts","error","Object","assign","Error","retryAfter","mockRejectedValueOnce","sleep","undefined","resolves","toHaveBeenCalledWith","release","pending","Promise","resolve","mockReturnValue","maxQueueSize","first","rejects","toThrow","permanent","mockRejectedValue","toBe","toHaveBeenCalled","mockImplementation","all","toHaveLength"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/__tests__/utils/slackMarkdown.test.ts"],"sourcesContent":["import {\n SLACK_MAX_MESSAGE_LENGTH,\n chunkMarkdownForSlack,\n markdownToSlackMrkdwn,\n} from '../../utils/slackMarkdown.js';\n\ndescribe('Slack Markdown', () => {\n it('renders common Markdown without activating broad mentions', () => {\n expect(markdownToSlackMrkdwn('# Result\\n\\n**Passed** & <safe> @channel [docs](https://example.com)'))\n .toBe('*Result*\\n\\n*Passed* &amp; &lt;safe&gt; @channel <https://example.com|docs>');\n });\n\n it('preserves inline and fenced code while escaping Slack control characters', () => {\n expect(markdownToSlackMrkdwn('Use `<tag>`\\n\\n```ts\\nconst x = \"<ok>\";\\n```'))\n .toContain('`&lt;tag&gt;`\\n\\n```\\nconst x = \"&lt;ok&gt;\";\\n```');\n });\n\n it('chunks long fenced code into independently fenced Slack messages', () => {\n const chunks = chunkMarkdownForSlack(`\\`\\`\\`ts\\n${'const value = 1;\\n'.repeat(400)}\\`\\`\\``);\n expect(chunks.length).toBeGreaterThan(1);\n expect(chunks.every((chunk) => chunk.length <= SLACK_MAX_MESSAGE_LENGTH)).toBe(true);\n expect(chunks.every((chunk) => chunk.startsWith('```') && chunk.endsWith('```'))).toBe(true);\n });\n\n it('accounts for escaped control-character expansion in code chunks', () => {\n const chunks = chunkMarkdownForSlack(`\\`\\`\\`\\n${'<&>'.repeat(2000)}\\n\\`\\`\\``);\n expect(chunks.length).toBeGreaterThan(1);\n expect(chunks.every((chunk) => chunk.length <= SLACK_MAX_MESSAGE_LENGTH)).toBe(true);\n expect(chunks.every((chunk) => chunk.startsWith('```') && chunk.endsWith('```'))).toBe(true);\n });\n\n it('splits Unicode text without breaking code points', () => {\n const chunks = chunkMarkdownForSlack('🎉'.repeat(5000));\n expect(chunks.join('')).toBe('🎉'.repeat(5000));\n expect(chunks.every((chunk) => chunk.length <= SLACK_MAX_MESSAGE_LENGTH)).toBe(true);\n });\n\n it('renders lists, quotes, emphasis, strike, breaks, and rules conservatively', () => {\n const rendered = markdownToSlackMrkdwn('1. _one_\\n2. ~~two~~\\n\\n> quoted \\n> next\\n\\n---');\n expect(rendered).toContain('1. _one_');\n expect(rendered).toContain('2. ~two~');\n expect(rendered).toContain('> quoted');\n expect(rendered).toContain('> next');\n expect(rendered).toContain('—');\n });\n\n it('packs short semantic blocks and splits oversized plain paragraphs', () => {\n expect(chunkMarkdownForSlack('one\\n\\ntwo', 20)).toEqual(['one\\n\\ntwo']);\n const chunks = chunkMarkdownForSlack('word '.repeat(30), 25);\n expect(chunks.length).toBeGreaterThan(1);\n expect(chunks.every((chunk) => chunk.length <= 25)).toBe(true);\n });\n});\n"],"names":["SLACK_MAX_MESSAGE_LENGTH","chunkMarkdownForSlack","markdownToSlackMrkdwn","describe","it","expect","toBe","toContain","chunks","repeat","length","toBeGreaterThan","every","chunk","startsWith","endsWith","join","rendered","toEqual"],"mappings":"AAAA,SACIA,wBAAwB,EACxBC,qBAAqB,EACrBC,qBAAqB,QAClB,+BAA+B;AAEtCC,SAAS,kBAAkB;IACvBC,GAAG,6DAA6D;QAC5DC,OAAOH,sBAAsB,yEACxBI,IAAI,CAAC;IACd;IAEAF,GAAG,4EAA4E;QAC3EC,OAAOH,sBAAsB,iDACxBK,SAAS,CAAC;IACnB;IAEAH,GAAG,oEAAoE;QACnE,MAAMI,SAASP,sBAAsB,CAAC,UAAU,EAAE,qBAAqBQ,MAAM,CAAC,KAAK,MAAM,CAAC;QAC1FJ,OAAOG,OAAOE,MAAM,EAAEC,eAAe,CAAC;QACtCN,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMH,MAAM,IAAIV,2BAA2BM,IAAI,CAAC;QAC/ED,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMC,UAAU,CAAC,UAAUD,MAAME,QAAQ,CAAC,SAAST,IAAI,CAAC;IAC3F;IAEAF,GAAG,mEAAmE;QAClE,MAAMI,SAASP,sBAAsB,CAAC,QAAQ,EAAE,MAAMQ,MAAM,CAAC,MAAM,QAAQ,CAAC;QAC5EJ,OAAOG,OAAOE,MAAM,EAAEC,eAAe,CAAC;QACtCN,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMH,MAAM,IAAIV,2BAA2BM,IAAI,CAAC;QAC/ED,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMC,UAAU,CAAC,UAAUD,MAAME,QAAQ,CAAC,SAAST,IAAI,CAAC;IAC3F;IAEAF,GAAG,oDAAoD;QACnD,MAAMI,SAASP,sBAAsB,KAAKQ,MAAM,CAAC;QACjDJ,OAAOG,OAAOQ,IAAI,CAAC,KAAKV,IAAI,CAAC,KAAKG,MAAM,CAAC;QACzCJ,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMH,MAAM,IAAIV,2BAA2BM,IAAI,CAAC;IACnF;IAEAF,GAAG,6EAA6E;QAC5E,MAAMa,WAAWf,sBAAsB;QACvCG,OAAOY,UAAUV,SAAS,CAAC;QAC3BF,OAAOY,UAAUV,SAAS,CAAC;QAC3BF,OAAOY,UAAUV,SAAS,CAAC;QAC3BF,OAAOY,UAAUV,SAAS,CAAC;QAC3BF,OAAOY,UAAUV,SAAS,CAAC;IAC/B;IAEAH,GAAG,qEAAqE;QACpEC,OAAOJ,sBAAsB,cAAc,KAAKiB,OAAO,CAAC;YAAC;SAAa;QACtE,MAAMV,SAASP,sBAAsB,QAAQQ,MAAM,CAAC,KAAK;QACzDJ,OAAOG,OAAOE,MAAM,EAAEC,eAAe,CAAC;QACtCN,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMH,MAAM,IAAI,KAAKJ,IAAI,CAAC;IAC7D;AACJ"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/__tests__/utils/telegramHtml.test.ts"],"sourcesContent":["import { markdownToTelegramHtml } from '../../utils/telegramHtml.js';\n\ndescribe('markdownToTelegramHtml', () => {\n it('renders bold, italic, strikethrough', () => {\n const out = markdownToTelegramHtml('**b** _i_ ~~s~~');\n expect(out).toContain('<b>b</b>');\n expect(out).toContain('<i>i</i>');\n expect(out).toContain('<s>s</s>');\n });\n\n it('renders inline code and fenced code with language', () => {\n const md = 'Run `npm test`\\n\\n```ts\\nconst x = 1;\\n```\\n\\n```\\nplain\\n```';\n const out = markdownToTelegramHtml(md);\n expect(out).toContain('<code>npm test</code>');\n expect(out).toContain('<pre><code class=\"language-ts\">const x = 1;</code></pre>');\n expect(out).toContain('<pre><code>plain</code></pre>');\n });\n\n it('renders links and converts headings to bold', () => {\n const md = '# Title\\n\\nSee [docs](https://x.com).';\n const out = markdownToTelegramHtml(md);\n expect(out).toContain('<b>Title</b>');\n expect(out).toContain('<a href=\"https://x.com\">docs</a>');\n });\n\n it('renders images as alt-text links', () => {\n const out = markdownToTelegramHtml('![diagram](https://x.com/d.png)');\n expect(out).toBe('<a href=\"https://x.com/d.png\">diagram</a>');\n });\n\n it('falls back to URL when image has no alt text', () => {\n const out = markdownToTelegramHtml('![](https://x.com/d.png)');\n expect(out).toContain('<a href=\"https://x.com/d.png\">https://x.com/d.png</a>');\n });\n\n it('renders unordered lists with bullets', () => {\n const out = markdownToTelegramHtml('- one\\n- two\\n- three');\n expect(out).toContain('• one');\n expect(out).toContain('• two');\n expect(out).toContain('• three');\n expect(out).not.toContain('<ul>');\n });\n\n it('renders nested lists without throwing', () => {\n const out = markdownToTelegramHtml('- agent\\n - Status');\n\n expect(out).toContain('• agent');\n expect(out).toContain('• Status');\n expect(out).not.toContain('<ul>');\n });\n\n it('renders ordered lists with numbers', () => {\n const out = markdownToTelegramHtml('1. one\\n2. two');\n expect(out).toContain('1. one');\n expect(out).toContain('2. two');\n expect(out).not.toContain('<ol>');\n });\n\n it('renders inline markup as HTML inside ordered tight lists', () => {\n const out = markdownToTelegramHtml('1. **bold** `code` *italic*');\n\n expect(out).toContain('1. <b>bold</b> <code>code</code> <i>italic</i>');\n expect(out).not.toContain('&lt;b&gt;');\n expect(out).not.toMatch(/\\*\\*|`/);\n });\n\n it('renders inline markup as HTML inside unordered tight lists', () => {\n const out = markdownToTelegramHtml('- **bold** `code` *italic*');\n\n expect(out).toContain('• <b>bold</b> <code>code</code> <i>italic</i>');\n expect(out).not.toMatch(/&lt;(?:b|code|i)&gt;/);\n });\n\n it('renders inline markup in the middle of list item text', () => {\n const out = markdownToTelegramHtml(\n '- While editing, `/x` is a **literal** character.'\n );\n\n expect(out).toContain(\n '• While editing, <code>/x</code> is a <b>literal</b> character.'\n );\n });\n\n it('renders inline markup in loose multi-paragraph lists', () => {\n const out = markdownToTelegramHtml(\n '- First **bold** paragraph.\\n\\n Second paragraph with *italic*.\\n\\n- `code` item.'\n );\n\n expect(out).toContain('• First <b>bold</b> paragraph.');\n expect(out).toContain('Second paragraph with <i>italic</i>.');\n expect(out).toContain('• <code>code</code> item.');\n expect(out).not.toMatch(/&lt;(?:b|code|i)&gt;/);\n });\n\n it('renders inline markup in nested list items', () => {\n const out = markdownToTelegramHtml('- **parent**\\n - child with `code`');\n\n expect(out).toContain('• <b>parent</b>');\n expect(out).toContain('• child with <code>code</code>');\n });\n\n it('escapes raw HTML inside list items', () => {\n const out = markdownToTelegramHtml('- literal <script>alert(1)</script> text');\n\n expect(out).toContain('&lt;script&gt;');\n expect(out).not.toContain('<script>');\n });\n\n it('preserves ordered list start numbering with inline markup', () => {\n const out = markdownToTelegramHtml('3. **three**\\n4. *four*');\n\n expect(out).toContain('3. <b>three</b>');\n expect(out).toContain('4. <i>four</i>');\n });\n\n it('renders links as HTML inside list items', () => {\n const out = markdownToTelegramHtml('- See [docs](https://example.com?a=1&b=2).');\n\n expect(out).toContain(\n '• See <a href=\"https://example.com?a=1&amp;b=2\">docs</a>.'\n );\n expect(out).not.toContain('&lt;a href=');\n });\n\n it('renders tables as ASCII inside <pre>', () => {\n const md = '| a | b |\\n|---|---|\\n| 1 | 2 |\\n| 3 |';\n const out = markdownToTelegramHtml(md);\n expect(out.startsWith('<pre>')).toBe(true);\n expect(out).toContain('a');\n expect(out).toContain('b');\n expect(out).toContain('1');\n expect(out).toContain('2');\n expect(out).toContain('3');\n expect(out).not.toContain('<table>');\n });\n\n it('uses <blockquote> for quotes', () => {\n const out = markdownToTelegramHtml('> quoted');\n expect(out).toContain('<blockquote>');\n expect(out).toContain('quoted');\n expect(out).toContain('</blockquote>');\n });\n\n it('escapes HTML special chars in plain text', () => {\n const out = markdownToTelegramHtml('a < b && c > d');\n expect(out).toContain('&lt;');\n expect(out).toContain('&amp;');\n expect(out).toContain('&gt;');\n expect(out).not.toContain(' < ');\n });\n\n it('escapes HTML special chars inside code', () => {\n const out = markdownToTelegramHtml('`<script>`');\n expect(out).toContain('<code>&lt;script&gt;</code>');\n });\n\n it('strips raw HTML blocks', () => {\n const out = markdownToTelegramHtml('hello\\n\\n<div>raw</div>\\n\\nworld');\n expect(out).not.toContain('<div>');\n expect(out).toContain('hello');\n expect(out).toContain('world');\n });\n\n it('renders horizontal rule as a divider', () => {\n const out = markdownToTelegramHtml('above\\n\\n---\\n\\nbelow');\n expect(out).toContain('above');\n expect(out).toContain('———');\n expect(out).toContain('below');\n });\n\n it('passes plain text through unchanged', () => {\n expect(markdownToTelegramHtml('hello world')).toBe('hello world');\n });\n});\n"],"names":["markdownToTelegramHtml","describe","it","out","expect","toContain","md","toBe","not","toMatch","startsWith"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"SlackAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/SlackAdapter.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/adapters/SlackAdapter.ts"],"sourcesContent":["import { SocketModeClient } from '@slack/socket-mode';\nimport { WebClient } from '@slack/web-api';\nimport type { InteractiveChannelAdapter } from './ChannelAdapter.js';\nimport type {\n ChannelQuestion,\n IncomingInteraction,\n IncomingMessage,\n SentMessage,\n SlackConfig,\n} from '../types.js';\nimport { SlackDeliveryQueue } from '../utils/SlackDeliveryQueue.js';\nimport { escapeSlackText } from '../utils/slackMarkdown.js';\n\nexport const SLACK_CHANNEL_TYPE = 'slack';\n\ninterface SlackAuthClient {\n authTest(): Promise<{ ok?: boolean; app_id?: string; user_id?: string; team_id?: string; team?: string }>;\n}\n\nexport interface SlackIdentity {\n appId?: string;\n botUserId: string;\n workspaceId: string;\n workspaceName?: string;\n}\n\ninterface SlackConnectionsClient {\n open(): Promise<{ ok?: boolean; url?: string }>;\n}\n\nexport async function validateSlackAppToken(appToken: string, client?: SlackConnectionsClient): Promise<void> {\n const connections = client ?? new WebClient(appToken).apps.connections;\n const result = await connections.open();\n if (!result.ok || !result.url) throw new Error('Slack app token cannot open Socket Mode');\n}\n\nexport async function validateSlackCredentials(botToken: string, client?: SlackAuthClient): Promise<SlackIdentity> {\n const authClient = client ?? {\n authTest: () => new WebClient(botToken).auth.test(),\n };\n const identity = await authClient.authTest();\n if (!identity.ok || !identity.user_id || !identity.team_id) {\n throw new Error('Slack bot token returned incomplete identity');\n }\n return {\n ...(identity.app_id ? { appId: identity.app_id } : {}),\n botUserId: identity.user_id,\n workspaceId: identity.team_id,\n workspaceName: identity.team,\n };\n}\n\ninterface SocketClientLike {\n on(event: string, listener: (payload?: unknown) => void): unknown;\n start(): Promise<unknown>;\n disconnect(): Promise<unknown>;\n}\n\ninterface WebClientLike {\n chat: {\n postMessage(input: Record<string, unknown>): Promise<{ ok?: boolean; ts?: string }>;\n update?(input: Record<string, unknown>): Promise<unknown>;\n };\n}\n\ninterface SlackAdapterDependencies {\n socketClient?: SocketClientLike;\n webClient?: WebClientLike;\n}\n\ninterface SlackEventEnvelope {\n type?: string;\n ack?: () => Promise<void>;\n body?: {\n team_id?: string;\n event_id?: string;\n is_ext_shared_channel?: boolean;\n event?: Record<string, unknown>;\n };\n}\n\nexport class SlackAdapter implements InteractiveChannelAdapter {\n readonly type = SLACK_CHANNEL_TYPE;\n private readonly socket: SocketClientLike;\n private readonly web: WebClientLike;\n private readonly delivery: SlackDeliveryQueue;\n private readonly recentEventIds = new Map<string, number>();\n private messageHandler: ((message: IncomingMessage) => Promise<void>) | null = null;\n private interactionHandler: ((interaction: IncomingInteraction) => Promise<void>) | null = null;\n private running = false;\n private listenersRegistered = false;\n\n constructor(private readonly config: SlackConfig, dependencies: SlackAdapterDependencies = {}) {\n this.socket = dependencies.socketClient ?? new SocketModeClient({ appToken: config.appToken });\n this.web = dependencies.webClient ?? new WebClient(config.botToken) as unknown as WebClientLike;\n this.delivery = new SlackDeliveryQueue({\n postMessage: (input) => this.web.chat.postMessage(input),\n });\n }\n\n async start(): Promise<void> {\n if (!this.listenersRegistered) {\n this.socket.on('slack_event', (payload) => {\n void this.handleSlackEvent(payload as SlackEventEnvelope).catch(() => undefined);\n });\n this.socket.on('interactive', (payload) => {\n void this.handleInteraction(payload as SlackInteractionEnvelope).catch(() => undefined);\n });\n this.socket.on('connected', () => { this.running = true; });\n this.socket.on('disconnected', () => { this.running = false; });\n this.listenersRegistered = true;\n }\n await this.socket.start();\n this.running = true;\n }\n\n async stop(): Promise<void> {\n this.running = false;\n await this.socket.disconnect();\n }\n\n onMessage(handler: (message: IncomingMessage) => Promise<void>): void {\n this.messageHandler = handler;\n }\n\n onInteraction(handler: (interaction: IncomingInteraction) => Promise<void>): void {\n this.interactionHandler = handler;\n }\n\n async sendMessage(chatId: string, text: string): Promise<SentMessage> {\n return this.delivery.send(chatId, text);\n }\n\n async isHealthy(): Promise<boolean> {\n return this.running;\n }\n\n async sendQuestion(chatId: string, question: ChannelQuestion): Promise<SentMessage> {\n const fallback = escapeSlackText(`${question.header ? `${question.header}: ` : ''}${question.question}`);\n const elements = question.options.map((option) => ({\n type: 'button',\n action_id: 'ai_devkit_question',\n text: { type: 'plain_text', text: option.label.slice(0, 75) },\n value: `${question.id}:${option.value}`.slice(0, 2000),\n }));\n if (question.allowSkip) {\n elements.push({\n type: 'button', action_id: 'ai_devkit_question',\n text: { type: 'plain_text', text: 'Skip' }, value: `${question.id}:skip`,\n });\n }\n const response = await this.web.chat.postMessage({\n channel: chatId,\n text: fallback,\n blocks: [\n {\n type: 'section',\n text: { type: 'mrkdwn', text: `*${escapeSlackText(question.header ?? 'Question')}*\\n${escapeSlackText(question.question)}` },\n },\n { type: 'actions', elements },\n ],\n });\n if (!response.ts) throw new Error('Slack did not return a question message timestamp');\n return { messageId: response.ts };\n }\n\n async finalizeInteraction(chatId: string, messageId: string): Promise<void> {\n if (!this.web.chat.update) throw new Error('Slack Web API chat.update is unavailable');\n await this.web.chat.update({ channel: chatId, ts: messageId, blocks: [] });\n }\n\n private async handleSlackEvent(envelope: SlackEventEnvelope): Promise<void> {\n if (envelope.type !== 'events_api') return;\n await envelope.ack?.();\n const body = envelope.body;\n const event = body?.event;\n const eventId = body?.event_id;\n if (!body || !event || !eventId || !this.messageHandler) return;\n if (!this.isValidDirectMessage(body, event)) return;\n if (this.recentEventIds.has(eventId)) return;\n this.rememberEvent(eventId);\n\n try {\n await this.messageHandler({\n channelType: SLACK_CHANNEL_TYPE,\n chatId: String(event.channel),\n userId: String(event.user),\n text: String(event.text),\n timestamp: new Date(Number(event.event_ts ?? event.ts) * 1000),\n messageId: eventId,\n threadId: typeof event.thread_ts === 'string' ? event.thread_ts : undefined,\n workspaceId: body.team_id,\n metadata: { slackTs: event.ts },\n });\n } catch {\n // The channel consumer reports terminal errors; never reject a Socket Mode listener.\n }\n }\n\n private isValidDirectMessage(body: NonNullable<SlackEventEnvelope['body']>, event: Record<string, unknown>): boolean {\n return body.team_id === this.config.workspaceId\n && body.is_ext_shared_channel !== true\n && event.type === 'message'\n && event.channel_type === 'im'\n && event.user !== this.config.botUserId\n && typeof event.text === 'string'\n && typeof event.ts === 'string'\n && event.subtype === undefined\n && event.bot_id === undefined;\n }\n\n private rememberEvent(eventId: string): void {\n this.recentEventIds.set(eventId, Date.now());\n while (this.recentEventIds.size > 1000) {\n const oldest = this.recentEventIds.keys().next().value as string | undefined;\n if (!oldest) break;\n this.recentEventIds.delete(oldest);\n }\n }\n\n private async handleInteraction(envelope: SlackInteractionEnvelope): Promise<void> {\n await envelope.ack?.();\n const body = envelope.body;\n const action = body?.actions?.[0];\n const interactionId = action?.action_ts;\n const workspaceId = body?.team?.id;\n const userId = body?.user?.id;\n const chatId = body?.channel?.id;\n const messageId = body?.container?.message_ts;\n if (!body || !action || !interactionId || !this.interactionHandler) return;\n if (body.type !== 'block_actions'\n || typeof workspaceId !== 'string'\n || typeof userId !== 'string'\n || typeof chatId !== 'string'\n || workspaceId !== this.config.workspaceId\n || typeof messageId !== 'string'\n || action.action_id !== 'ai_devkit_question'\n || typeof action.value !== 'string'\n || this.recentEventIds.has(`interaction:${interactionId}`)) return;\n this.rememberEvent(`interaction:${interactionId}`);\n try {\n await this.interactionHandler({\n channelType: SLACK_CHANNEL_TYPE,\n chatId,\n userId,\n workspaceId,\n interactionId,\n messageId,\n actionId: action.action_id,\n value: action.value,\n timestamp: new Date(Number(interactionId) * 1000),\n });\n } catch {\n // Keep Socket Mode listener failures isolated from the SDK event loop.\n }\n }\n}\n\ninterface SlackInteractionEnvelope {\n ack?: () => Promise<void>;\n body?: {\n type?: string;\n team?: { id?: string };\n user?: { id?: string };\n channel?: { id?: string };\n container?: { message_ts?: string };\n actions?: Array<{ action_id?: string; action_ts?: string; value?: string }>;\n };\n}\n"],"names":["SocketModeClient","WebClient","SlackDeliveryQueue","escapeSlackText","SLACK_CHANNEL_TYPE","validateSlackAppToken","appToken","client","connections","apps","result","open","ok","url","Error","validateSlackCredentials","botToken","authClient","authTest","auth","test","identity","user_id","team_id","app_id","appId","botUserId","workspaceId","workspaceName","team","SlackAdapter","type","socket","web","delivery","recentEventIds","Map","messageHandler","interactionHandler","running","listenersRegistered","config","dependencies","socketClient","webClient","postMessage","input","chat","start","on","payload","handleSlackEvent","catch","undefined","handleInteraction","stop","disconnect","onMessage","handler","onInteraction","sendMessage","chatId","text","send","isHealthy","sendQuestion","question","fallback","header","elements","options","map","option","action_id","label","slice","value","id","allowSkip","push","response","channel","blocks","ts","messageId","finalizeInteraction","update","envelope","ack","body","event","eventId","event_id","isValidDirectMessage","has","rememberEvent","channelType","String","userId","user","timestamp","Date","Number","event_ts","threadId","thread_ts","metadata","slackTs","is_ext_shared_channel","channel_type","subtype","bot_id","set","now","size","oldest","keys","next","delete","action","actions","interactionId","action_ts","container","message_ts","actionId"],"mappings":"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"}