@ai-devkit/channel-connector 0.13.3 → 0.13.4

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 (69) hide show
  1. package/dist/ChannelConfigRepository.d.ts +1 -1
  2. package/dist/ChannelConfigRepository.d.ts.map +1 -1
  3. package/dist/ChannelConfigRepository.js +13 -13
  4. package/dist/ChannelConfigRepository.js.map +1 -1
  5. package/dist/ChannelManager.d.ts +1 -1
  6. package/dist/ChannelManager.d.ts.map +1 -1
  7. package/dist/ChannelManager.js +9 -9
  8. package/dist/ChannelManager.js.map +1 -1
  9. package/dist/__tests__/ChannelConfigRepository.test.js +72 -72
  10. package/dist/__tests__/ChannelConfigRepository.test.js.map +1 -1
  11. package/dist/__tests__/ChannelManager.test.js +26 -26
  12. package/dist/__tests__/ChannelManager.test.js.map +1 -1
  13. package/dist/__tests__/adapters/slack/SlackAdapter.test.js +137 -137
  14. package/dist/__tests__/adapters/slack/SlackAdapter.test.js.map +1 -1
  15. package/dist/__tests__/adapters/slack/SlackMessageDelivery.test.js +36 -36
  16. package/dist/__tests__/adapters/slack/SlackMessageDelivery.test.js.map +1 -1
  17. package/dist/__tests__/adapters/slack/slackMarkdown.test.js +25 -25
  18. package/dist/__tests__/adapters/slack/slackMarkdown.test.js.map +1 -1
  19. package/dist/__tests__/adapters/slack/slackQuestion.test.js +41 -41
  20. package/dist/__tests__/adapters/slack/slackQuestion.test.js.map +1 -1
  21. package/dist/__tests__/adapters/telegram/TelegramAdapter.test.js +154 -154
  22. package/dist/__tests__/adapters/telegram/TelegramAdapter.test.js.map +1 -1
  23. package/dist/__tests__/adapters/telegram/telegramHtml.test.js +109 -109
  24. package/dist/__tests__/adapters/telegram/telegramHtml.test.js.map +1 -1
  25. package/dist/adapters/ChannelAdapter.d.ts +1 -1
  26. package/dist/adapters/ChannelAdapter.d.ts.map +1 -1
  27. package/dist/adapters/ChannelAdapter.js +1 -1
  28. package/dist/adapters/ChannelAdapter.js.map +1 -1
  29. package/dist/adapters/slack/SlackAdapter.d.ts +2 -2
  30. package/dist/adapters/slack/SlackAdapter.d.ts.map +1 -1
  31. package/dist/adapters/slack/SlackAdapter.js +17 -17
  32. package/dist/adapters/slack/SlackAdapter.js.map +1 -1
  33. package/dist/adapters/slack/SlackMessageDelivery.d.ts +1 -1
  34. package/dist/adapters/slack/SlackMessageDelivery.d.ts.map +1 -1
  35. package/dist/adapters/slack/SlackMessageDelivery.js +6 -6
  36. package/dist/adapters/slack/SlackMessageDelivery.js.map +1 -1
  37. package/dist/adapters/slack/slackMarkdown.d.ts.map +1 -1
  38. package/dist/adapters/slack/slackMarkdown.js +36 -36
  39. package/dist/adapters/slack/slackMarkdown.js.map +1 -1
  40. package/dist/adapters/slack/slackQuestion.d.ts +7 -7
  41. package/dist/adapters/slack/slackQuestion.d.ts.map +1 -1
  42. package/dist/adapters/slack/slackQuestion.js +13 -13
  43. package/dist/adapters/slack/slackQuestion.js.map +1 -1
  44. package/dist/adapters/telegram/TelegramAdapter.d.ts +2 -2
  45. package/dist/adapters/telegram/TelegramAdapter.d.ts.map +1 -1
  46. package/dist/adapters/telegram/TelegramAdapter.js +30 -27
  47. package/dist/adapters/telegram/TelegramAdapter.js.map +1 -1
  48. package/dist/adapters/telegram/TelegramMessageDelivery.d.ts.map +1 -1
  49. package/dist/adapters/telegram/TelegramMessageDelivery.js +2 -2
  50. package/dist/adapters/telegram/TelegramMessageDelivery.js.map +1 -1
  51. package/dist/adapters/telegram/telegramHtml.d.ts.map +1 -1
  52. package/dist/adapters/telegram/telegramHtml.js +16 -16
  53. package/dist/adapters/telegram/telegramHtml.js.map +1 -1
  54. package/dist/adapters/telegram/telegramKeyboard.d.ts +1 -1
  55. package/dist/adapters/telegram/telegramKeyboard.d.ts.map +1 -1
  56. package/dist/adapters/telegram/telegramKeyboard.js.map +1 -1
  57. package/dist/adapters/telegram/telegramMarkdown.d.ts.map +1 -1
  58. package/dist/adapters/telegram/telegramMarkdown.js +28 -28
  59. package/dist/adapters/telegram/telegramMarkdown.js.map +1 -1
  60. package/dist/index.d.ts +9 -9
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +5 -5
  63. package/dist/index.js.map +1 -1
  64. package/dist/types.d.ts +6 -6
  65. package/dist/types.d.ts.map +1 -1
  66. package/dist/types.js +1 -1
  67. package/dist/types.js.map +1 -1
  68. package/package.json +21 -22
  69. package/vitest.config.ts +16 -16
@@ -1,4 +1,4 @@
1
- import type { ChannelConfig, ChannelEntry } from './types.js';
1
+ import type { ChannelConfig, ChannelEntry } from "./types.js";
2
2
  /**
3
3
  * Persists channel configurations to disk.
4
4
  * Default location: ~/.ai-devkit/channels.json
@@ -1 +1 @@
1
- {"version":3,"file":"ChannelConfigRepository.d.ts","sourceRoot":"","sources":["../src/ChannelConfigRepository.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK9D;;;;GAIG;AACH,qBAAa,uBAAuB;IAChC,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
+ {"version":3,"file":"ChannelConfigRepository.d.ts","sourceRoot":"","sources":["../src/ChannelConfigRepository.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK9D;;;;GAIG;AACH,qBAAa,uBAAuB;IAClC,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;CAM1B"}
@@ -1,7 +1,7 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import * as os from 'os';
4
- const DEFAULT_CONFIG_PATH = path.join(os.homedir(), '.ai-devkit', 'channels.json');
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import * as os from "os";
4
+ const DEFAULT_CONFIG_PATH = path.join(os.homedir(), ".ai-devkit", "channels.json");
5
5
  const DEFAULT_CONFIG = {
6
6
  channels: {}
7
7
  };
@@ -15,10 +15,10 @@ const DEFAULT_CONFIG = {
15
15
  this.configPath = configPath ?? DEFAULT_CONFIG_PATH;
16
16
  }
17
17
  /**
18
- * Read the full config. Returns default empty config if file is missing or corrupt.
19
- */ async getConfig() {
18
+ * Read the full config. Returns default empty config if file is missing or corrupt.
19
+ */ async getConfig() {
20
20
  try {
21
- const raw = fs.readFileSync(this.configPath, 'utf-8');
21
+ const raw = fs.readFileSync(this.configPath, "utf-8");
22
22
  return JSON.parse(raw);
23
23
  } catch {
24
24
  return {
@@ -28,22 +28,22 @@ const DEFAULT_CONFIG = {
28
28
  }
29
29
  }
30
30
  /**
31
- * Save a channel entry. Creates the file and parent directory if needed.
32
- */ async saveChannel(name, entry) {
31
+ * Save a channel entry. Creates the file and parent directory if needed.
32
+ */ async saveChannel(name, entry) {
33
33
  const config = await this.getConfig();
34
34
  config.channels[name] = entry;
35
35
  await this.writeConfig(config);
36
36
  }
37
37
  /**
38
- * Remove a channel entry by name.
39
- */ async removeChannel(name) {
38
+ * Remove a channel entry by name.
39
+ */ async removeChannel(name) {
40
40
  const config = await this.getConfig();
41
41
  delete config.channels[name];
42
42
  await this.writeConfig(config);
43
43
  }
44
44
  /**
45
- * Get a single channel entry by name.
46
- */ async getChannel(name) {
45
+ * Get a single channel entry by name.
46
+ */ async getChannel(name) {
47
47
  const config = await this.getConfig();
48
48
  return config.channels[name];
49
49
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ChannelConfigRepository.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 ChannelConfigRepository {\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","ChannelConfigRepository","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
+ {"version":3,"sources":["../src/ChannelConfigRepository.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 ChannelConfigRepository {\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","ChannelConfigRepository","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;IACHC,WAAmB;IAE3B,YAAYA,UAAmB,CAAE;QAC/B,IAAI,CAACA,UAAU,GAAGA,cAAcN;IAClC;IAEA;;GAEC,GACD,MAAMO,YAAoC;QACxC,IAAI;YACF,MAAMC,MAAMX,GAAGY,YAAY,CAAC,IAAI,CAACH,UAAU,EAAE;YAC7C,OAAOI,KAAKC,KAAK,CAACH;QACpB,EAAE,OAAM;YACN,OAAO;gBAAE,GAAGL,cAAc;gBAAEC,UAAU,CAAC;YAAE;QAC3C;IACF;IAEA;;GAEC,GACD,MAAMQ,YAAYC,IAAY,EAAEC,KAAmB,EAAiB;QAClE,MAAMC,SAAS,MAAM,IAAI,CAACR,SAAS;QACnCQ,OAAOX,QAAQ,CAACS,KAAK,GAAGC;QACxB,MAAM,IAAI,CAACE,WAAW,CAACD;IACzB;IAEA;;GAEC,GACD,MAAME,cAAcJ,IAAY,EAAiB;QAC/C,MAAME,SAAS,MAAM,IAAI,CAACR,SAAS;QACnC,OAAOQ,OAAOX,QAAQ,CAACS,KAAK;QAC5B,MAAM,IAAI,CAACG,WAAW,CAACD;IACzB;IAEA;;GAEC,GACD,MAAMG,WAAWL,IAAY,EAAqC;QAChE,MAAME,SAAS,MAAM,IAAI,CAACR,SAAS;QACnC,OAAOQ,OAAOX,QAAQ,CAACS,KAAK;IAC9B;IAEA,MAAcG,YAAYD,MAAqB,EAAiB;QAC9D,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;IAChC;AACF"}
@@ -1,4 +1,4 @@
1
- import type { ChannelAdapter } from './adapters/ChannelAdapter.js';
1
+ import type { ChannelAdapter } from "./adapters/ChannelAdapter.js";
2
2
  /**
3
3
  * Central registry for channel adapters.
4
4
  * Manages adapter lifecycle (start/stop).
@@ -1 +1 @@
1
- {"version":3,"file":"ChannelManager.d.ts","sourceRoot":"","sources":["../src/ChannelManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;GAGG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,QAAQ,CAA0C;IAE1D;;;OAGG;IACH,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAO9C;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAIpD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAK/B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAIjC"}
1
+ {"version":3,"file":"ChannelManager.d.ts","sourceRoot":"","sources":["../src/ChannelManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAA0C;IAE1D;;;OAGG;IACH,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAO9C;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAIpD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAK/B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAI/B"}
@@ -4,28 +4,28 @@
4
4
  */ export class ChannelManager {
5
5
  adapters = new Map();
6
6
  /**
7
- * Register a channel adapter.
8
- * @throws If an adapter for the same type is already registered.
9
- */ registerAdapter(adapter) {
7
+ * Register a channel adapter.
8
+ * @throws If an adapter for the same type is already registered.
9
+ */ registerAdapter(adapter) {
10
10
  if (this.adapters.has(adapter.type)) {
11
11
  throw new Error(`Adapter for type "${adapter.type}" is already registered`);
12
12
  }
13
13
  this.adapters.set(adapter.type, adapter);
14
14
  }
15
15
  /**
16
- * Get a registered adapter by type.
17
- */ getAdapter(type) {
16
+ * Get a registered adapter by type.
17
+ */ getAdapter(type) {
18
18
  return this.adapters.get(type);
19
19
  }
20
20
  /**
21
- * Start all registered adapters.
22
- */ async startAll() {
21
+ * Start all registered adapters.
22
+ */ async startAll() {
23
23
  const startPromises = Array.from(this.adapters.values()).map((a)=>a.start());
24
24
  await Promise.all(startPromises);
25
25
  }
26
26
  /**
27
- * Stop all registered adapters.
28
- */ async stopAll() {
27
+ * Stop all registered adapters.
28
+ */ async stopAll() {
29
29
  const stopPromises = Array.from(this.adapters.values()).map((a)=>a.stop());
30
30
  await Promise.all(stopPromises);
31
31
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ChannelManager.ts"],"sourcesContent":["import type { ChannelAdapter } from './adapters/ChannelAdapter.js';\n\n/**\n * Central registry for channel adapters.\n * Manages adapter lifecycle (start/stop).\n */\nexport class ChannelManager {\n private adapters: Map<string, ChannelAdapter> = new Map();\n\n /**\n * Register a channel adapter.\n * @throws If an adapter for the same type is already registered.\n */\n registerAdapter(adapter: ChannelAdapter): void {\n if (this.adapters.has(adapter.type)) {\n throw new Error(`Adapter for type \"${adapter.type}\" is already registered`);\n }\n this.adapters.set(adapter.type, adapter);\n }\n\n /**\n * Get a registered adapter by type.\n */\n getAdapter(type: string): ChannelAdapter | undefined {\n return this.adapters.get(type);\n }\n\n /**\n * Start all registered adapters.\n */\n async startAll(): Promise<void> {\n const startPromises = Array.from(this.adapters.values()).map(a => a.start());\n await Promise.all(startPromises);\n }\n\n /**\n * Stop all registered adapters.\n */\n async stopAll(): Promise<void> {\n const stopPromises = Array.from(this.adapters.values()).map(a => a.stop());\n await Promise.all(stopPromises);\n }\n}\n"],"names":["ChannelManager","adapters","Map","registerAdapter","adapter","has","type","Error","set","getAdapter","get","startAll","startPromises","Array","from","values","map","a","start","Promise","all","stopAll","stopPromises","stop"],"mappings":"AAEA;;;CAGC,GACD,OAAO,MAAMA;IACDC,WAAwC,IAAIC,MAAM;IAE1D;;;KAGC,GACDC,gBAAgBC,OAAuB,EAAQ;QAC3C,IAAI,IAAI,CAACH,QAAQ,CAACI,GAAG,CAACD,QAAQE,IAAI,GAAG;YACjC,MAAM,IAAIC,MAAM,CAAC,kBAAkB,EAAEH,QAAQE,IAAI,CAAC,uBAAuB,CAAC;QAC9E;QACA,IAAI,CAACL,QAAQ,CAACO,GAAG,CAACJ,QAAQE,IAAI,EAAEF;IACpC;IAEA;;KAEC,GACDK,WAAWH,IAAY,EAA8B;QACjD,OAAO,IAAI,CAACL,QAAQ,CAACS,GAAG,CAACJ;IAC7B;IAEA;;KAEC,GACD,MAAMK,WAA0B;QAC5B,MAAMC,gBAAgBC,MAAMC,IAAI,CAAC,IAAI,CAACb,QAAQ,CAACc,MAAM,IAAIC,GAAG,CAACC,CAAAA,IAAKA,EAAEC,KAAK;QACzE,MAAMC,QAAQC,GAAG,CAACR;IACtB;IAEA;;KAEC,GACD,MAAMS,UAAyB;QAC3B,MAAMC,eAAeT,MAAMC,IAAI,CAAC,IAAI,CAACb,QAAQ,CAACc,MAAM,IAAIC,GAAG,CAACC,CAAAA,IAAKA,EAAEM,IAAI;QACvE,MAAMJ,QAAQC,GAAG,CAACE;IACtB;AACJ"}
1
+ {"version":3,"sources":["../src/ChannelManager.ts"],"sourcesContent":["import type { ChannelAdapter } from \"./adapters/ChannelAdapter.js\";\n\n/**\n * Central registry for channel adapters.\n * Manages adapter lifecycle (start/stop).\n */\nexport class ChannelManager {\n private adapters: Map<string, ChannelAdapter> = new Map();\n\n /**\n * Register a channel adapter.\n * @throws If an adapter for the same type is already registered.\n */\n registerAdapter(adapter: ChannelAdapter): void {\n if (this.adapters.has(adapter.type)) {\n throw new Error(`Adapter for type \"${adapter.type}\" is already registered`);\n }\n this.adapters.set(adapter.type, adapter);\n }\n\n /**\n * Get a registered adapter by type.\n */\n getAdapter(type: string): ChannelAdapter | undefined {\n return this.adapters.get(type);\n }\n\n /**\n * Start all registered adapters.\n */\n async startAll(): Promise<void> {\n const startPromises = Array.from(this.adapters.values()).map((a) => a.start());\n await Promise.all(startPromises);\n }\n\n /**\n * Stop all registered adapters.\n */\n async stopAll(): Promise<void> {\n const stopPromises = Array.from(this.adapters.values()).map((a) => a.stop());\n await Promise.all(stopPromises);\n }\n}\n"],"names":["ChannelManager","adapters","Map","registerAdapter","adapter","has","type","Error","set","getAdapter","get","startAll","startPromises","Array","from","values","map","a","start","Promise","all","stopAll","stopPromises","stop"],"mappings":"AAEA;;;CAGC,GACD,OAAO,MAAMA;IACHC,WAAwC,IAAIC,MAAM;IAE1D;;;GAGC,GACDC,gBAAgBC,OAAuB,EAAQ;QAC7C,IAAI,IAAI,CAACH,QAAQ,CAACI,GAAG,CAACD,QAAQE,IAAI,GAAG;YACnC,MAAM,IAAIC,MAAM,CAAC,kBAAkB,EAAEH,QAAQE,IAAI,CAAC,uBAAuB,CAAC;QAC5E;QACA,IAAI,CAACL,QAAQ,CAACO,GAAG,CAACJ,QAAQE,IAAI,EAAEF;IAClC;IAEA;;GAEC,GACDK,WAAWH,IAAY,EAA8B;QACnD,OAAO,IAAI,CAACL,QAAQ,CAACS,GAAG,CAACJ;IAC3B;IAEA;;GAEC,GACD,MAAMK,WAA0B;QAC9B,MAAMC,gBAAgBC,MAAMC,IAAI,CAAC,IAAI,CAACb,QAAQ,CAACc,MAAM,IAAIC,GAAG,CAAC,CAACC,IAAMA,EAAEC,KAAK;QAC3E,MAAMC,QAAQC,GAAG,CAACR;IACpB;IAEA;;GAEC,GACD,MAAMS,UAAyB;QAC7B,MAAMC,eAAeT,MAAMC,IAAI,CAAC,IAAI,CAACb,QAAQ,CAACc,MAAM,IAAIC,GAAG,CAAC,CAACC,IAAMA,EAAEM,IAAI;QACzE,MAAMJ,QAAQC,GAAG,CAACE;IACpB;AACF"}
@@ -1,15 +1,15 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import * as os from 'os';
4
- import { ChannelConfigRepository } from '../ChannelConfigRepository.js';
5
- import { isSlackEntry } from '../types.js';
6
- describe('ChannelConfigRepository', ()=>{
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import * as os from "os";
4
+ import { ChannelConfigRepository } from "../ChannelConfigRepository.js";
5
+ import { isSlackEntry } from "../types.js";
6
+ describe("ChannelConfigRepository", ()=>{
7
7
  let tmpDir;
8
8
  let configPath;
9
9
  let store;
10
10
  beforeEach(()=>{
11
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'channel-connector-test-'));
12
- configPath = path.join(tmpDir, 'channels.json');
11
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "channel-connector-test-"));
12
+ configPath = path.join(tmpDir, "channels.json");
13
13
  store = new ChannelConfigRepository(configPath);
14
14
  });
15
15
  afterEach(()=>{
@@ -19,50 +19,50 @@ describe('ChannelConfigRepository', ()=>{
19
19
  });
20
20
  });
21
21
  const sampleEntry = {
22
- type: 'telegram',
22
+ type: "telegram",
23
23
  enabled: true,
24
- createdAt: '2026-04-11T00:00:00Z',
24
+ createdAt: "2026-04-11T00:00:00Z",
25
25
  config: {
26
- botToken: 'test-token-123',
27
- botUsername: 'test_bot'
26
+ botToken: "test-token-123",
27
+ botUsername: "test_bot"
28
28
  }
29
29
  };
30
30
  const slackEntry = {
31
- type: 'slack',
31
+ type: "slack",
32
32
  enabled: true,
33
- createdAt: '2026-08-06T00:00:00Z',
33
+ createdAt: "2026-08-06T00:00:00Z",
34
34
  config: {
35
- appToken: 'xapp-fake',
36
- botToken: 'xoxb-fake',
37
- appId: 'A123',
38
- botUserId: 'U-BOT',
39
- workspaceId: 'T123',
40
- workspaceName: 'Sandbox',
41
- transport: 'socket-mode',
42
- audience: 'dm'
35
+ appToken: "xapp-fake",
36
+ botToken: "xoxb-fake",
37
+ appId: "A123",
38
+ botUserId: "U-BOT",
39
+ workspaceId: "T123",
40
+ workspaceName: "Sandbox",
41
+ transport: "socket-mode",
42
+ audience: "dm"
43
43
  }
44
44
  };
45
- describe('constructor', ()=>{
46
- it('should use default path when no configPath provided', async ()=>{
45
+ describe("constructor", ()=>{
46
+ it("should use default path when no configPath provided", async ()=>{
47
47
  const defaultStore = new ChannelConfigRepository();
48
48
  // Should not throw — just uses default path
49
49
  const config = await defaultStore.getConfig();
50
50
  expect(config).toBeDefined();
51
51
  });
52
52
  });
53
- describe('getConfig', ()=>{
54
- it('narrows provider configuration from the channel type', ()=>{
53
+ describe("getConfig", ()=>{
54
+ it("narrows provider configuration from the channel type", ()=>{
55
55
  expect(isSlackEntry(slackEntry)).toBe(true);
56
- if (!isSlackEntry(slackEntry)) throw new Error('expected Slack entry');
57
- expect(slackEntry.config.workspaceId).toBe('T123');
56
+ if (!isSlackEntry(slackEntry)) throw new Error("expected Slack entry");
57
+ expect(slackEntry.config.workspaceId).toBe("T123");
58
58
  });
59
- it('should return default empty config when file does not exist', async ()=>{
59
+ it("should return default empty config when file does not exist", async ()=>{
60
60
  const config = await store.getConfig();
61
61
  expect(config).toEqual({
62
62
  channels: {}
63
63
  });
64
64
  });
65
- it('should return parsed config when file exists', async ()=>{
65
+ it("should return parsed config when file exists", async ()=>{
66
66
  fs.writeFileSync(configPath, JSON.stringify({
67
67
  channels: {
68
68
  telegram: sampleEntry
@@ -71,102 +71,102 @@ describe('ChannelConfigRepository', ()=>{
71
71
  const config = await store.getConfig();
72
72
  expect(config.channels.telegram).toEqual(sampleEntry);
73
73
  });
74
- it('should handle corrupted JSON gracefully', async ()=>{
75
- fs.writeFileSync(configPath, 'not valid json{{{');
74
+ it("should handle corrupted JSON gracefully", async ()=>{
75
+ fs.writeFileSync(configPath, "not valid json{{{");
76
76
  const config = await store.getConfig();
77
77
  expect(config).toEqual({
78
78
  channels: {}
79
79
  });
80
80
  });
81
81
  });
82
- describe('saveChannel', ()=>{
83
- it('should create config file with channel entry', async ()=>{
84
- await store.saveChannel('telegram', sampleEntry);
85
- const raw = fs.readFileSync(configPath, 'utf-8');
82
+ describe("saveChannel", ()=>{
83
+ it("should create config file with channel entry", async ()=>{
84
+ await store.saveChannel("telegram", sampleEntry);
85
+ const raw = fs.readFileSync(configPath, "utf-8");
86
86
  const config = JSON.parse(raw);
87
87
  expect(config.channels.telegram).toEqual(sampleEntry);
88
88
  });
89
- it('should create parent directory if missing', async ()=>{
90
- const nestedPath = path.join(tmpDir, 'nested', 'dir', 'channels.json');
89
+ it("should create parent directory if missing", async ()=>{
90
+ const nestedPath = path.join(tmpDir, "nested", "dir", "channels.json");
91
91
  const nestedStore = new ChannelConfigRepository(nestedPath);
92
- await nestedStore.saveChannel('telegram', sampleEntry);
92
+ await nestedStore.saveChannel("telegram", sampleEntry);
93
93
  expect(fs.existsSync(nestedPath)).toBe(true);
94
94
  });
95
- it('should set file permissions to 0600', async ()=>{
96
- await store.saveChannel('telegram', sampleEntry);
95
+ it("should set file permissions to 0600", async ()=>{
96
+ await store.saveChannel("telegram", sampleEntry);
97
97
  const stats = fs.statSync(configPath);
98
98
  const mode = (stats.mode & 0o777).toString(8);
99
- expect(mode).toBe('600');
99
+ expect(mode).toBe("600");
100
100
  });
101
- it('should repair permissive permissions on an existing config file', async ()=>{
101
+ it("should repair permissive permissions on an existing config file", async ()=>{
102
102
  fs.writeFileSync(configPath, JSON.stringify({
103
103
  channels: {}
104
104
  }), {
105
105
  mode: 0o644
106
106
  });
107
107
  fs.chmodSync(configPath, 0o644);
108
- await store.saveChannel('slack', slackEntry);
108
+ await store.saveChannel("slack", slackEntry);
109
109
  expect(fs.statSync(configPath).mode & 0o777).toBe(0o600);
110
110
  });
111
- it('should preserve existing channels when adding a new one', async ()=>{
112
- await store.saveChannel('telegram', sampleEntry);
113
- await store.saveChannel('slack', slackEntry);
111
+ it("should preserve existing channels when adding a new one", async ()=>{
112
+ await store.saveChannel("telegram", sampleEntry);
113
+ await store.saveChannel("slack", slackEntry);
114
114
  const config = await store.getConfig();
115
115
  expect(Object.keys(config.channels)).toEqual([
116
- 'telegram',
117
- 'slack'
116
+ "telegram",
117
+ "slack"
118
118
  ]);
119
119
  expect(config.channels.slack).toEqual(slackEntry);
120
120
  });
121
- it('should preserve separate Telegram configs by channel name', async ()=>{
122
- await store.saveChannel('personal', {
121
+ it("should preserve separate Telegram configs by channel name", async ()=>{
122
+ await store.saveChannel("personal", {
123
123
  ...sampleEntry,
124
124
  config: {
125
- botToken: 'personal-token',
126
- botUsername: 'personal_bot',
125
+ botToken: "personal-token",
126
+ botUsername: "personal_bot",
127
127
  authorizedChatId: 111
128
128
  }
129
129
  });
130
- await store.saveChannel('work', {
130
+ await store.saveChannel("work", {
131
131
  ...sampleEntry,
132
132
  config: {
133
- botToken: 'work-token',
134
- botUsername: 'work_bot',
133
+ botToken: "work-token",
134
+ botUsername: "work_bot",
135
135
  authorizedChatId: 222
136
136
  }
137
137
  });
138
138
  const config = await store.getConfig();
139
139
  expect(config.channels.personal.config).toEqual({
140
- botToken: 'personal-token',
141
- botUsername: 'personal_bot',
140
+ botToken: "personal-token",
141
+ botUsername: "personal_bot",
142
142
  authorizedChatId: 111
143
143
  });
144
144
  expect(config.channels.work.config).toEqual({
145
- botToken: 'work-token',
146
- botUsername: 'work_bot',
145
+ botToken: "work-token",
146
+ botUsername: "work_bot",
147
147
  authorizedChatId: 222
148
148
  });
149
149
  });
150
150
  });
151
- describe('removeChannel', ()=>{
152
- it('should remove a channel entry', async ()=>{
153
- await store.saveChannel('telegram', sampleEntry);
154
- await store.removeChannel('telegram');
151
+ describe("removeChannel", ()=>{
152
+ it("should remove a channel entry", async ()=>{
153
+ await store.saveChannel("telegram", sampleEntry);
154
+ await store.removeChannel("telegram");
155
155
  const config = await store.getConfig();
156
156
  expect(config.channels.telegram).toBeUndefined();
157
157
  });
158
- it('should not throw when removing non-existent channel', async ()=>{
159
- await expect(store.removeChannel('nonexistent')).resolves.toBeUndefined();
158
+ it("should not throw when removing non-existent channel", async ()=>{
159
+ await expect(store.removeChannel("nonexistent")).resolves.toBeUndefined();
160
160
  });
161
161
  });
162
- describe('getChannel', ()=>{
163
- it('should return the channel entry', async ()=>{
164
- await store.saveChannel('telegram', sampleEntry);
165
- const entry = await store.getChannel('telegram');
162
+ describe("getChannel", ()=>{
163
+ it("should return the channel entry", async ()=>{
164
+ await store.saveChannel("telegram", sampleEntry);
165
+ const entry = await store.getChannel("telegram");
166
166
  expect(entry).toEqual(sampleEntry);
167
167
  });
168
- it('should return undefined for non-existent channel', async ()=>{
169
- const entry = await store.getChannel('slack');
168
+ it("should return undefined for non-existent channel", async ()=>{
169
+ const entry = await store.getChannel("slack");
170
170
  expect(entry).toBeUndefined();
171
171
  });
172
172
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/__tests__/ChannelConfigRepository.test.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { ChannelConfigRepository } from '../ChannelConfigRepository.js';\nimport { isSlackEntry } from '../types.js';\nimport type { ChannelEntry } from '../types.js';\n\ndescribe('ChannelConfigRepository', () => {\n let tmpDir: string;\n let configPath: string;\n let store: ChannelConfigRepository;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'channel-connector-test-'));\n configPath = path.join(tmpDir, 'channels.json');\n store = new ChannelConfigRepository(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 ChannelConfigRepository();\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 ChannelConfigRepository(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","ChannelConfigRepository","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
+ {"version":3,"sources":["../../src/__tests__/ChannelConfigRepository.test.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { ChannelConfigRepository } from \"../ChannelConfigRepository.js\";\nimport { isSlackEntry } from \"../types.js\";\nimport type { ChannelEntry } from \"../types.js\";\n\ndescribe(\"ChannelConfigRepository\", () => {\n let tmpDir: string;\n let configPath: string;\n let store: ChannelConfigRepository;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"channel-connector-test-\"));\n configPath = path.join(tmpDir, \"channels.json\");\n store = new ChannelConfigRepository(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 ChannelConfigRepository();\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(\n configPath,\n JSON.stringify({\n channels: { telegram: sampleEntry },\n }),\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 ChannelConfigRepository(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","ChannelConfigRepository","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,69 +1,69 @@
1
- import { ChannelManager } from '../ChannelManager.js';
1
+ import { ChannelManager } from "../ChannelManager.js";
2
2
  function createMockAdapter(type) {
3
3
  return {
4
4
  type,
5
5
  start: vi.fn().mockResolvedValue(undefined),
6
6
  stop: vi.fn().mockResolvedValue(undefined),
7
7
  sendMessage: vi.fn().mockResolvedValue({
8
- messageId: '1'
8
+ messageId: "1"
9
9
  }),
10
10
  onMessage: vi.fn(),
11
11
  isHealthy: vi.fn().mockResolvedValue(true)
12
12
  };
13
13
  }
14
- describe('ChannelManager', ()=>{
14
+ describe("ChannelManager", ()=>{
15
15
  let manager;
16
16
  beforeEach(()=>{
17
17
  manager = new ChannelManager();
18
18
  });
19
- describe('registerAdapter', ()=>{
20
- it('should register an adapter', ()=>{
21
- const adapter = createMockAdapter('telegram');
19
+ describe("registerAdapter", ()=>{
20
+ it("should register an adapter", ()=>{
21
+ const adapter = createMockAdapter("telegram");
22
22
  manager.registerAdapter(adapter);
23
- expect(manager.getAdapter('telegram')).toBe(adapter);
23
+ expect(manager.getAdapter("telegram")).toBe(adapter);
24
24
  });
25
- it('should throw on duplicate adapter type', ()=>{
26
- const adapter1 = createMockAdapter('telegram');
27
- const adapter2 = createMockAdapter('telegram');
25
+ it("should throw on duplicate adapter type", ()=>{
26
+ const adapter1 = createMockAdapter("telegram");
27
+ const adapter2 = createMockAdapter("telegram");
28
28
  manager.registerAdapter(adapter1);
29
29
  expect(()=>manager.registerAdapter(adapter2)).toThrow('Adapter for type "telegram" is already registered');
30
30
  });
31
31
  });
32
- describe('getAdapter', ()=>{
33
- it('should return undefined for unregistered type', ()=>{
34
- expect(manager.getAdapter('slack')).toBeUndefined();
32
+ describe("getAdapter", ()=>{
33
+ it("should return undefined for unregistered type", ()=>{
34
+ expect(manager.getAdapter("slack")).toBeUndefined();
35
35
  });
36
- it('should return the registered adapter', ()=>{
37
- const adapter = createMockAdapter('telegram');
36
+ it("should return the registered adapter", ()=>{
37
+ const adapter = createMockAdapter("telegram");
38
38
  manager.registerAdapter(adapter);
39
- expect(manager.getAdapter('telegram')).toBe(adapter);
39
+ expect(manager.getAdapter("telegram")).toBe(adapter);
40
40
  });
41
41
  });
42
- describe('startAll', ()=>{
43
- it('should call start() on all registered adapters', async ()=>{
44
- const telegram = createMockAdapter('telegram');
45
- const slack = createMockAdapter('slack');
42
+ describe("startAll", ()=>{
43
+ it("should call start() on all registered adapters", async ()=>{
44
+ const telegram = createMockAdapter("telegram");
45
+ const slack = createMockAdapter("slack");
46
46
  manager.registerAdapter(telegram);
47
47
  manager.registerAdapter(slack);
48
48
  await manager.startAll();
49
49
  expect(telegram.start).toHaveBeenCalledTimes(1);
50
50
  expect(slack.start).toHaveBeenCalledTimes(1);
51
51
  });
52
- it('should work with no adapters', async ()=>{
52
+ it("should work with no adapters", async ()=>{
53
53
  await expect(manager.startAll()).resolves.toBeUndefined();
54
54
  });
55
55
  });
56
- describe('stopAll', ()=>{
57
- it('should call stop() on all registered adapters', async ()=>{
58
- const telegram = createMockAdapter('telegram');
59
- const slack = createMockAdapter('slack');
56
+ describe("stopAll", ()=>{
57
+ it("should call stop() on all registered adapters", async ()=>{
58
+ const telegram = createMockAdapter("telegram");
59
+ const slack = createMockAdapter("slack");
60
60
  manager.registerAdapter(telegram);
61
61
  manager.registerAdapter(slack);
62
62
  await manager.stopAll();
63
63
  expect(telegram.stop).toHaveBeenCalledTimes(1);
64
64
  expect(slack.stop).toHaveBeenCalledTimes(1);
65
65
  });
66
- it('should work with no adapters', async ()=>{
66
+ it("should work with no adapters", async ()=>{
67
67
  await expect(manager.stopAll()).resolves.toBeUndefined();
68
68
  });
69
69
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/__tests__/ChannelManager.test.ts"],"sourcesContent":["import type { Mocked } from 'vitest';\nimport { ChannelManager } from '../ChannelManager.js';\nimport type { ChannelAdapter } from '../adapters/ChannelAdapter.js';\n\nfunction createMockAdapter(type: string): Mocked<ChannelAdapter> {\n return {\n type,\n start: vi.fn().mockResolvedValue(undefined),\n stop: vi.fn().mockResolvedValue(undefined),\n sendMessage: vi.fn().mockResolvedValue({ messageId: '1' }),\n onMessage: vi.fn(),\n isHealthy: vi.fn().mockResolvedValue(true),\n };\n}\n\ndescribe('ChannelManager', () => {\n let manager: ChannelManager;\n\n beforeEach(() => {\n manager = new ChannelManager();\n });\n\n describe('registerAdapter', () => {\n it('should register an adapter', () => {\n const adapter = createMockAdapter('telegram');\n manager.registerAdapter(adapter);\n expect(manager.getAdapter('telegram')).toBe(adapter);\n });\n\n it('should throw on duplicate adapter type', () => {\n const adapter1 = createMockAdapter('telegram');\n const adapter2 = createMockAdapter('telegram');\n manager.registerAdapter(adapter1);\n expect(() => manager.registerAdapter(adapter2)).toThrow(\n 'Adapter for type \"telegram\" is already registered'\n );\n });\n });\n\n describe('getAdapter', () => {\n it('should return undefined for unregistered type', () => {\n expect(manager.getAdapter('slack')).toBeUndefined();\n });\n\n it('should return the registered adapter', () => {\n const adapter = createMockAdapter('telegram');\n manager.registerAdapter(adapter);\n expect(manager.getAdapter('telegram')).toBe(adapter);\n });\n });\n\n describe('startAll', () => {\n it('should call start() on all registered adapters', async () => {\n const telegram = createMockAdapter('telegram');\n const slack = createMockAdapter('slack');\n manager.registerAdapter(telegram);\n manager.registerAdapter(slack);\n\n await manager.startAll();\n\n expect(telegram.start).toHaveBeenCalledTimes(1);\n expect(slack.start).toHaveBeenCalledTimes(1);\n });\n\n it('should work with no adapters', async () => {\n await expect(manager.startAll()).resolves.toBeUndefined();\n });\n });\n\n describe('stopAll', () => {\n it('should call stop() on all registered adapters', async () => {\n const telegram = createMockAdapter('telegram');\n const slack = createMockAdapter('slack');\n manager.registerAdapter(telegram);\n manager.registerAdapter(slack);\n\n await manager.stopAll();\n\n expect(telegram.stop).toHaveBeenCalledTimes(1);\n expect(slack.stop).toHaveBeenCalledTimes(1);\n });\n\n it('should work with no adapters', async () => {\n await expect(manager.stopAll()).resolves.toBeUndefined();\n });\n });\n});\n"],"names":["ChannelManager","createMockAdapter","type","start","vi","fn","mockResolvedValue","undefined","stop","sendMessage","messageId","onMessage","isHealthy","describe","manager","beforeEach","it","adapter","registerAdapter","expect","getAdapter","toBe","adapter1","adapter2","toThrow","toBeUndefined","telegram","slack","startAll","toHaveBeenCalledTimes","resolves","stopAll"],"mappings":"AACA,SAASA,cAAc,QAAQ,uBAAuB;AAGtD,SAASC,kBAAkBC,IAAY;IACnC,OAAO;QACHA;QACAC,OAAOC,GAAGC,EAAE,GAAGC,iBAAiB,CAACC;QACjCC,MAAMJ,GAAGC,EAAE,GAAGC,iBAAiB,CAACC;QAChCE,aAAaL,GAAGC,EAAE,GAAGC,iBAAiB,CAAC;YAAEI,WAAW;QAAI;QACxDC,WAAWP,GAAGC,EAAE;QAChBO,WAAWR,GAAGC,EAAE,GAAGC,iBAAiB,CAAC;IACzC;AACJ;AAEAO,SAAS,kBAAkB;IACvB,IAAIC;IAEJC,WAAW;QACPD,UAAU,IAAId;IAClB;IAEAa,SAAS,mBAAmB;QACxBG,GAAG,8BAA8B;YAC7B,MAAMC,UAAUhB,kBAAkB;YAClCa,QAAQI,eAAe,CAACD;YACxBE,OAAOL,QAAQM,UAAU,CAAC,aAAaC,IAAI,CAACJ;QAChD;QAEAD,GAAG,0CAA0C;YACzC,MAAMM,WAAWrB,kBAAkB;YACnC,MAAMsB,WAAWtB,kBAAkB;YACnCa,QAAQI,eAAe,CAACI;YACxBH,OAAO,IAAML,QAAQI,eAAe,CAACK,WAAWC,OAAO,CACnD;QAER;IACJ;IAEAX,SAAS,cAAc;QACnBG,GAAG,iDAAiD;YAChDG,OAAOL,QAAQM,UAAU,CAAC,UAAUK,aAAa;QACrD;QAEAT,GAAG,wCAAwC;YACvC,MAAMC,UAAUhB,kBAAkB;YAClCa,QAAQI,eAAe,CAACD;YACxBE,OAAOL,QAAQM,UAAU,CAAC,aAAaC,IAAI,CAACJ;QAChD;IACJ;IAEAJ,SAAS,YAAY;QACjBG,GAAG,kDAAkD;YACjD,MAAMU,WAAWzB,kBAAkB;YACnC,MAAM0B,QAAQ1B,kBAAkB;YAChCa,QAAQI,eAAe,CAACQ;YACxBZ,QAAQI,eAAe,CAACS;YAExB,MAAMb,QAAQc,QAAQ;YAEtBT,OAAOO,SAASvB,KAAK,EAAE0B,qBAAqB,CAAC;YAC7CV,OAAOQ,MAAMxB,KAAK,EAAE0B,qBAAqB,CAAC;QAC9C;QAEAb,GAAG,gCAAgC;YAC/B,MAAMG,OAAOL,QAAQc,QAAQ,IAAIE,QAAQ,CAACL,aAAa;QAC3D;IACJ;IAEAZ,SAAS,WAAW;QAChBG,GAAG,iDAAiD;YAChD,MAAMU,WAAWzB,kBAAkB;YACnC,MAAM0B,QAAQ1B,kBAAkB;YAChCa,QAAQI,eAAe,CAACQ;YACxBZ,QAAQI,eAAe,CAACS;YAExB,MAAMb,QAAQiB,OAAO;YAErBZ,OAAOO,SAASlB,IAAI,EAAEqB,qBAAqB,CAAC;YAC5CV,OAAOQ,MAAMnB,IAAI,EAAEqB,qBAAqB,CAAC;QAC7C;QAEAb,GAAG,gCAAgC;YAC/B,MAAMG,OAAOL,QAAQiB,OAAO,IAAID,QAAQ,CAACL,aAAa;QAC1D;IACJ;AACJ"}
1
+ {"version":3,"sources":["../../src/__tests__/ChannelManager.test.ts"],"sourcesContent":["import type { Mocked } from \"vitest\";\nimport { ChannelManager } from \"../ChannelManager.js\";\nimport type { ChannelAdapter } from \"../adapters/ChannelAdapter.js\";\n\nfunction createMockAdapter(type: string): Mocked<ChannelAdapter> {\n return {\n type,\n start: vi.fn().mockResolvedValue(undefined),\n stop: vi.fn().mockResolvedValue(undefined),\n sendMessage: vi.fn().mockResolvedValue({ messageId: \"1\" }),\n onMessage: vi.fn(),\n isHealthy: vi.fn().mockResolvedValue(true),\n };\n}\n\ndescribe(\"ChannelManager\", () => {\n let manager: ChannelManager;\n\n beforeEach(() => {\n manager = new ChannelManager();\n });\n\n describe(\"registerAdapter\", () => {\n it(\"should register an adapter\", () => {\n const adapter = createMockAdapter(\"telegram\");\n manager.registerAdapter(adapter);\n expect(manager.getAdapter(\"telegram\")).toBe(adapter);\n });\n\n it(\"should throw on duplicate adapter type\", () => {\n const adapter1 = createMockAdapter(\"telegram\");\n const adapter2 = createMockAdapter(\"telegram\");\n manager.registerAdapter(adapter1);\n expect(() => manager.registerAdapter(adapter2)).toThrow(\n 'Adapter for type \"telegram\" is already registered',\n );\n });\n });\n\n describe(\"getAdapter\", () => {\n it(\"should return undefined for unregistered type\", () => {\n expect(manager.getAdapter(\"slack\")).toBeUndefined();\n });\n\n it(\"should return the registered adapter\", () => {\n const adapter = createMockAdapter(\"telegram\");\n manager.registerAdapter(adapter);\n expect(manager.getAdapter(\"telegram\")).toBe(adapter);\n });\n });\n\n describe(\"startAll\", () => {\n it(\"should call start() on all registered adapters\", async () => {\n const telegram = createMockAdapter(\"telegram\");\n const slack = createMockAdapter(\"slack\");\n manager.registerAdapter(telegram);\n manager.registerAdapter(slack);\n\n await manager.startAll();\n\n expect(telegram.start).toHaveBeenCalledTimes(1);\n expect(slack.start).toHaveBeenCalledTimes(1);\n });\n\n it(\"should work with no adapters\", async () => {\n await expect(manager.startAll()).resolves.toBeUndefined();\n });\n });\n\n describe(\"stopAll\", () => {\n it(\"should call stop() on all registered adapters\", async () => {\n const telegram = createMockAdapter(\"telegram\");\n const slack = createMockAdapter(\"slack\");\n manager.registerAdapter(telegram);\n manager.registerAdapter(slack);\n\n await manager.stopAll();\n\n expect(telegram.stop).toHaveBeenCalledTimes(1);\n expect(slack.stop).toHaveBeenCalledTimes(1);\n });\n\n it(\"should work with no adapters\", async () => {\n await expect(manager.stopAll()).resolves.toBeUndefined();\n });\n });\n});\n"],"names":["ChannelManager","createMockAdapter","type","start","vi","fn","mockResolvedValue","undefined","stop","sendMessage","messageId","onMessage","isHealthy","describe","manager","beforeEach","it","adapter","registerAdapter","expect","getAdapter","toBe","adapter1","adapter2","toThrow","toBeUndefined","telegram","slack","startAll","toHaveBeenCalledTimes","resolves","stopAll"],"mappings":"AACA,SAASA,cAAc,QAAQ,uBAAuB;AAGtD,SAASC,kBAAkBC,IAAY;IACrC,OAAO;QACLA;QACAC,OAAOC,GAAGC,EAAE,GAAGC,iBAAiB,CAACC;QACjCC,MAAMJ,GAAGC,EAAE,GAAGC,iBAAiB,CAACC;QAChCE,aAAaL,GAAGC,EAAE,GAAGC,iBAAiB,CAAC;YAAEI,WAAW;QAAI;QACxDC,WAAWP,GAAGC,EAAE;QAChBO,WAAWR,GAAGC,EAAE,GAAGC,iBAAiB,CAAC;IACvC;AACF;AAEAO,SAAS,kBAAkB;IACzB,IAAIC;IAEJC,WAAW;QACTD,UAAU,IAAId;IAChB;IAEAa,SAAS,mBAAmB;QAC1BG,GAAG,8BAA8B;YAC/B,MAAMC,UAAUhB,kBAAkB;YAClCa,QAAQI,eAAe,CAACD;YACxBE,OAAOL,QAAQM,UAAU,CAAC,aAAaC,IAAI,CAACJ;QAC9C;QAEAD,GAAG,0CAA0C;YAC3C,MAAMM,WAAWrB,kBAAkB;YACnC,MAAMsB,WAAWtB,kBAAkB;YACnCa,QAAQI,eAAe,CAACI;YACxBH,OAAO,IAAML,QAAQI,eAAe,CAACK,WAAWC,OAAO,CACrD;QAEJ;IACF;IAEAX,SAAS,cAAc;QACrBG,GAAG,iDAAiD;YAClDG,OAAOL,QAAQM,UAAU,CAAC,UAAUK,aAAa;QACnD;QAEAT,GAAG,wCAAwC;YACzC,MAAMC,UAAUhB,kBAAkB;YAClCa,QAAQI,eAAe,CAACD;YACxBE,OAAOL,QAAQM,UAAU,CAAC,aAAaC,IAAI,CAACJ;QAC9C;IACF;IAEAJ,SAAS,YAAY;QACnBG,GAAG,kDAAkD;YACnD,MAAMU,WAAWzB,kBAAkB;YACnC,MAAM0B,QAAQ1B,kBAAkB;YAChCa,QAAQI,eAAe,CAACQ;YACxBZ,QAAQI,eAAe,CAACS;YAExB,MAAMb,QAAQc,QAAQ;YAEtBT,OAAOO,SAASvB,KAAK,EAAE0B,qBAAqB,CAAC;YAC7CV,OAAOQ,MAAMxB,KAAK,EAAE0B,qBAAqB,CAAC;QAC5C;QAEAb,GAAG,gCAAgC;YACjC,MAAMG,OAAOL,QAAQc,QAAQ,IAAIE,QAAQ,CAACL,aAAa;QACzD;IACF;IAEAZ,SAAS,WAAW;QAClBG,GAAG,iDAAiD;YAClD,MAAMU,WAAWzB,kBAAkB;YACnC,MAAM0B,QAAQ1B,kBAAkB;YAChCa,QAAQI,eAAe,CAACQ;YACxBZ,QAAQI,eAAe,CAACS;YAExB,MAAMb,QAAQiB,OAAO;YAErBZ,OAAOO,SAASlB,IAAI,EAAEqB,qBAAqB,CAAC;YAC5CV,OAAOQ,MAAMnB,IAAI,EAAEqB,qBAAqB,CAAC;QAC3C;QAEAb,GAAG,gCAAgC;YACjC,MAAMG,OAAOL,QAAQiB,OAAO,IAAID,QAAQ,CAACL,aAAa;QACxD;IACF;AACF"}