agent-messenger 1.0.0 → 1.1.0

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 (330) hide show
  1. package/.claude/commands/release.md +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.github/workflows/ci.yml +1 -1
  4. package/.github/workflows/e2e.yml.disabled +69 -0
  5. package/README.md +16 -14
  6. package/biome.json +33 -1
  7. package/bun.lock +63 -0
  8. package/dist/package.json +8 -4
  9. package/dist/src/cli.d.ts.map +1 -1
  10. package/dist/src/cli.js +4 -1
  11. package/dist/src/cli.js.map +1 -1
  12. package/dist/src/platforms/discord/cli.js +1 -1
  13. package/dist/src/platforms/discord/client.d.ts.map +1 -1
  14. package/dist/src/platforms/discord/client.js +3 -3
  15. package/dist/src/platforms/discord/client.js.map +1 -1
  16. package/dist/src/platforms/discord/commands/user.d.ts.map +1 -1
  17. package/dist/src/platforms/discord/commands/user.js +10 -1
  18. package/dist/src/platforms/discord/commands/user.js.map +1 -1
  19. package/dist/src/platforms/discord/credential-manager.d.ts.map +1 -1
  20. package/dist/src/platforms/discord/credential-manager.js +18 -12
  21. package/dist/src/platforms/discord/credential-manager.js.map +1 -1
  22. package/dist/src/platforms/slack/cli.js +1 -1
  23. package/dist/src/platforms/slack/credential-manager.d.ts.map +1 -1
  24. package/dist/src/platforms/slack/credential-manager.js +20 -6
  25. package/dist/src/platforms/slack/credential-manager.js.map +1 -1
  26. package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
  27. package/dist/src/platforms/slack/token-extractor.js +34 -9
  28. package/dist/src/platforms/slack/token-extractor.js.map +1 -1
  29. package/dist/src/platforms/teams/cli.d.ts.map +1 -0
  30. package/dist/{cli.js → src/platforms/teams/cli.js} +11 -10
  31. package/dist/src/platforms/teams/cli.js.map +1 -0
  32. package/dist/src/platforms/teams/client.d.ts +32 -0
  33. package/dist/src/platforms/teams/client.d.ts.map +1 -0
  34. package/dist/src/platforms/teams/client.js +202 -0
  35. package/dist/src/platforms/teams/client.js.map +1 -0
  36. package/dist/src/platforms/teams/commands/auth.d.ts +14 -0
  37. package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -0
  38. package/dist/src/platforms/teams/commands/auth.js +176 -0
  39. package/dist/src/platforms/teams/commands/auth.js.map +1 -0
  40. package/dist/src/platforms/teams/commands/channel.d.ts +13 -0
  41. package/dist/src/platforms/teams/commands/channel.d.ts.map +1 -0
  42. package/dist/src/platforms/teams/commands/channel.js +97 -0
  43. package/dist/src/platforms/teams/commands/channel.js.map +1 -0
  44. package/dist/src/platforms/teams/commands/file.d.ts +12 -0
  45. package/dist/src/platforms/teams/commands/file.d.ts.map +1 -0
  46. package/dist/src/platforms/teams/commands/file.js +104 -0
  47. package/dist/src/platforms/teams/commands/file.js.map +1 -0
  48. package/dist/{commands → src/platforms/teams/commands}/index.d.ts +5 -2
  49. package/dist/src/platforms/teams/commands/index.d.ts.map +1 -0
  50. package/dist/{commands → src/platforms/teams/commands}/index.js +5 -2
  51. package/dist/src/platforms/teams/commands/index.js.map +1 -0
  52. package/dist/src/platforms/teams/commands/message.d.ts +17 -0
  53. package/dist/src/platforms/teams/commands/message.d.ts.map +1 -0
  54. package/dist/src/platforms/teams/commands/message.js +133 -0
  55. package/dist/src/platforms/teams/commands/message.js.map +1 -0
  56. package/dist/src/platforms/teams/commands/reaction.d.ts +9 -0
  57. package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -0
  58. package/dist/src/platforms/teams/commands/reaction.js +68 -0
  59. package/dist/src/platforms/teams/commands/reaction.js.map +1 -0
  60. package/dist/src/platforms/teams/commands/snapshot.d.ts +10 -0
  61. package/dist/src/platforms/teams/commands/snapshot.d.ts.map +1 -0
  62. package/dist/src/platforms/teams/commands/snapshot.js +85 -0
  63. package/dist/src/platforms/teams/commands/snapshot.js.map +1 -0
  64. package/dist/src/platforms/teams/commands/team.d.ts +18 -0
  65. package/dist/src/platforms/teams/commands/team.d.ts.map +1 -0
  66. package/dist/src/platforms/teams/commands/team.js +130 -0
  67. package/dist/src/platforms/teams/commands/team.js.map +1 -0
  68. package/dist/src/platforms/teams/commands/user.d.ts.map +1 -0
  69. package/dist/src/platforms/teams/commands/user.js +88 -0
  70. package/dist/src/platforms/teams/commands/user.js.map +1 -0
  71. package/dist/src/platforms/teams/credential-manager.d.ts +18 -0
  72. package/dist/src/platforms/teams/credential-manager.d.ts.map +1 -0
  73. package/dist/src/platforms/teams/credential-manager.js +81 -0
  74. package/dist/src/platforms/teams/credential-manager.js.map +1 -0
  75. package/dist/src/platforms/teams/index.d.ts +4 -0
  76. package/dist/src/platforms/teams/index.d.ts.map +1 -0
  77. package/dist/src/platforms/teams/index.js +6 -0
  78. package/dist/src/platforms/teams/index.js.map +1 -0
  79. package/dist/src/platforms/teams/token-extractor.d.ts +36 -0
  80. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -0
  81. package/dist/src/platforms/teams/token-extractor.js +335 -0
  82. package/dist/src/platforms/teams/token-extractor.js.map +1 -0
  83. package/dist/src/platforms/teams/types.d.ts +209 -0
  84. package/dist/src/platforms/teams/types.d.ts.map +1 -0
  85. package/dist/src/platforms/teams/types.js +65 -0
  86. package/dist/src/platforms/teams/types.js.map +1 -0
  87. package/docs/teams.md +321 -0
  88. package/e2e/README.md +256 -0
  89. package/e2e/config.ts +45 -0
  90. package/e2e/discord.e2e.test.ts +252 -0
  91. package/e2e/helpers.ts +107 -0
  92. package/e2e/slack.e2e.test.ts +309 -0
  93. package/package.json +8 -4
  94. package/scripts/postbuild.ts +15 -0
  95. package/skills/agent-teams/SKILL.md +292 -0
  96. package/skills/agent-teams/references/authentication.md +375 -0
  97. package/skills/agent-teams/references/common-patterns.md +596 -0
  98. package/skills/agent-teams/templates/monitor-channel.sh +239 -0
  99. package/skills/agent-teams/templates/post-message.sh +224 -0
  100. package/skills/agent-teams/templates/team-summary.sh +210 -0
  101. package/src/cli.ts +4 -0
  102. package/src/platforms/discord/client.ts +3 -3
  103. package/src/platforms/discord/commands/auth.test.ts +48 -32
  104. package/src/platforms/discord/commands/channel.test.ts +54 -42
  105. package/src/platforms/discord/commands/file.test.ts +40 -53
  106. package/src/platforms/discord/commands/guild.test.ts +47 -27
  107. package/src/platforms/discord/commands/message.test.ts +54 -51
  108. package/src/platforms/discord/commands/reaction.test.ts +54 -42
  109. package/src/platforms/discord/commands/user.ts +12 -1
  110. package/src/platforms/discord/credential-manager.test.ts +137 -136
  111. package/src/platforms/discord/credential-manager.ts +20 -13
  112. package/src/platforms/discord/token-extractor.test.ts +133 -383
  113. package/{tests → src/platforms/slack}/cli.test.ts +3 -3
  114. package/{tests/slack-client.test.ts → src/platforms/slack/client.test.ts} +1 -1
  115. package/{tests → src/platforms/slack}/commands/auth.test.ts +25 -13
  116. package/{tests → src/platforms/slack}/commands/channel.test.ts +2 -2
  117. package/{tests → src/platforms/slack}/commands/file.test.ts +2 -2
  118. package/{tests → src/platforms/slack}/commands/message.test.ts +2 -2
  119. package/{tests → src/platforms/slack}/commands/reaction.test.ts +1 -1
  120. package/{tests → src/platforms/slack}/commands/snapshot.test.ts +117 -105
  121. package/{tests → src/platforms/slack}/commands/user.test.ts +3 -3
  122. package/{tests → src/platforms/slack}/commands/workspace.test.ts +44 -95
  123. package/{tests → src/platforms/slack}/credential-manager.test.ts +2 -2
  124. package/src/platforms/slack/credential-manager.ts +22 -7
  125. package/src/platforms/slack/token-extractor-node-test.ts +40 -0
  126. package/src/platforms/slack/token-extractor-node.test.ts +10 -0
  127. package/src/platforms/slack/token-extractor.ts +36 -10
  128. package/{tests → src/platforms/slack}/types.test.ts +1 -1
  129. package/src/platforms/teams/cli.ts +36 -0
  130. package/src/platforms/teams/client.test.ts +500 -0
  131. package/src/platforms/teams/client.ts +365 -0
  132. package/src/platforms/teams/commands/auth.test.ts +99 -0
  133. package/src/platforms/teams/commands/auth.ts +232 -0
  134. package/src/platforms/teams/commands/channel.test.ts +147 -0
  135. package/src/platforms/teams/commands/channel.ts +129 -0
  136. package/src/platforms/teams/commands/file.test.ts +88 -0
  137. package/src/platforms/teams/commands/file.ts +144 -0
  138. package/src/platforms/teams/commands/index.ts +12 -0
  139. package/src/platforms/teams/commands/message.test.ts +110 -0
  140. package/src/platforms/teams/commands/message.ts +188 -0
  141. package/src/platforms/teams/commands/reaction.test.ts +87 -0
  142. package/src/platforms/teams/commands/reaction.ts +104 -0
  143. package/src/platforms/teams/commands/snapshot.test.ts +35 -0
  144. package/src/platforms/teams/commands/snapshot.ts +115 -0
  145. package/src/platforms/teams/commands/team.test.ts +157 -0
  146. package/src/platforms/teams/commands/team.ts +164 -0
  147. package/src/platforms/teams/commands/user.test.ts +83 -0
  148. package/src/platforms/teams/commands/user.ts +112 -0
  149. package/src/platforms/teams/credential-manager.test.ts +178 -0
  150. package/src/platforms/teams/credential-manager.ts +92 -0
  151. package/src/platforms/teams/index.ts +5 -0
  152. package/src/platforms/teams/token-extractor.test.ts +429 -0
  153. package/src/platforms/teams/token-extractor.ts +462 -0
  154. package/src/platforms/teams/types.test.ts +226 -0
  155. package/src/platforms/teams/types.ts +140 -0
  156. package/tsconfig.json +1 -1
  157. package/dist/cli.d.ts.map +0 -1
  158. package/dist/cli.js.map +0 -1
  159. package/dist/commands/auth.d.ts +0 -3
  160. package/dist/commands/auth.d.ts.map +0 -1
  161. package/dist/commands/auth.js +0 -140
  162. package/dist/commands/auth.js.map +0 -1
  163. package/dist/commands/channel.d.ts +0 -3
  164. package/dist/commands/channel.d.ts.map +0 -1
  165. package/dist/commands/channel.js +0 -118
  166. package/dist/commands/channel.js.map +0 -1
  167. package/dist/commands/file.d.ts +0 -3
  168. package/dist/commands/file.d.ts.map +0 -1
  169. package/dist/commands/file.js +0 -113
  170. package/dist/commands/file.js.map +0 -1
  171. package/dist/commands/index.d.ts.map +0 -1
  172. package/dist/commands/index.js.map +0 -1
  173. package/dist/commands/message.d.ts +0 -3
  174. package/dist/commands/message.d.ts.map +0 -1
  175. package/dist/commands/message.js +0 -214
  176. package/dist/commands/message.js.map +0 -1
  177. package/dist/commands/reaction.d.ts +0 -3
  178. package/dist/commands/reaction.d.ts.map +0 -1
  179. package/dist/commands/reaction.js +0 -100
  180. package/dist/commands/reaction.js.map +0 -1
  181. package/dist/commands/snapshot.d.ts +0 -3
  182. package/dist/commands/snapshot.d.ts.map +0 -1
  183. package/dist/commands/snapshot.js +0 -88
  184. package/dist/commands/snapshot.js.map +0 -1
  185. package/dist/commands/user.d.ts.map +0 -1
  186. package/dist/commands/user.js +0 -96
  187. package/dist/commands/user.js.map +0 -1
  188. package/dist/commands/workspace.d.ts +0 -3
  189. package/dist/commands/workspace.d.ts.map +0 -1
  190. package/dist/commands/workspace.js +0 -89
  191. package/dist/commands/workspace.js.map +0 -1
  192. package/dist/lib/credential-manager.d.ts +0 -13
  193. package/dist/lib/credential-manager.d.ts.map +0 -1
  194. package/dist/lib/credential-manager.js +0 -58
  195. package/dist/lib/credential-manager.js.map +0 -1
  196. package/dist/lib/index.d.ts +0 -3
  197. package/dist/lib/index.d.ts.map +0 -1
  198. package/dist/lib/index.js +0 -3
  199. package/dist/lib/index.js.map +0 -1
  200. package/dist/lib/ref-manager.d.ts +0 -26
  201. package/dist/lib/ref-manager.d.ts.map +0 -1
  202. package/dist/lib/ref-manager.js +0 -92
  203. package/dist/lib/ref-manager.js.map +0 -1
  204. package/dist/lib/slack-client.d.ts +0 -37
  205. package/dist/lib/slack-client.d.ts.map +0 -1
  206. package/dist/lib/slack-client.js +0 -379
  207. package/dist/lib/slack-client.js.map +0 -1
  208. package/dist/lib/token-extractor.d.ts +0 -28
  209. package/dist/lib/token-extractor.d.ts.map +0 -1
  210. package/dist/lib/token-extractor.js +0 -401
  211. package/dist/lib/token-extractor.js.map +0 -1
  212. package/dist/src/platforms/discord/client.test.d.ts +0 -2
  213. package/dist/src/platforms/discord/client.test.d.ts.map +0 -1
  214. package/dist/src/platforms/discord/client.test.js +0 -367
  215. package/dist/src/platforms/discord/client.test.js.map +0 -1
  216. package/dist/src/platforms/discord/commands/auth.test.d.ts +0 -2
  217. package/dist/src/platforms/discord/commands/auth.test.d.ts.map +0 -1
  218. package/dist/src/platforms/discord/commands/auth.test.js +0 -65
  219. package/dist/src/platforms/discord/commands/auth.test.js.map +0 -1
  220. package/dist/src/platforms/discord/commands/channel.test.d.ts +0 -2
  221. package/dist/src/platforms/discord/commands/channel.test.d.ts.map +0 -1
  222. package/dist/src/platforms/discord/commands/channel.test.js +0 -136
  223. package/dist/src/platforms/discord/commands/channel.test.js.map +0 -1
  224. package/dist/src/platforms/discord/commands/file.test.d.ts +0 -2
  225. package/dist/src/platforms/discord/commands/file.test.d.ts.map +0 -1
  226. package/dist/src/platforms/discord/commands/file.test.js +0 -83
  227. package/dist/src/platforms/discord/commands/file.test.js.map +0 -1
  228. package/dist/src/platforms/discord/commands/guild.test.d.ts +0 -2
  229. package/dist/src/platforms/discord/commands/guild.test.d.ts.map +0 -1
  230. package/dist/src/platforms/discord/commands/guild.test.js +0 -100
  231. package/dist/src/platforms/discord/commands/guild.test.js.map +0 -1
  232. package/dist/src/platforms/discord/commands/message.test.d.ts +0 -2
  233. package/dist/src/platforms/discord/commands/message.test.d.ts.map +0 -1
  234. package/dist/src/platforms/discord/commands/message.test.js +0 -91
  235. package/dist/src/platforms/discord/commands/message.test.js.map +0 -1
  236. package/dist/src/platforms/discord/commands/reaction.test.d.ts +0 -2
  237. package/dist/src/platforms/discord/commands/reaction.test.d.ts.map +0 -1
  238. package/dist/src/platforms/discord/commands/reaction.test.js +0 -115
  239. package/dist/src/platforms/discord/commands/reaction.test.js.map +0 -1
  240. package/dist/src/platforms/discord/commands/snapshot.test.d.ts +0 -2
  241. package/dist/src/platforms/discord/commands/snapshot.test.d.ts.map +0 -1
  242. package/dist/src/platforms/discord/commands/snapshot.test.js +0 -25
  243. package/dist/src/platforms/discord/commands/snapshot.test.js.map +0 -1
  244. package/dist/src/platforms/discord/commands/user.test.d.ts +0 -2
  245. package/dist/src/platforms/discord/commands/user.test.d.ts.map +0 -1
  246. package/dist/src/platforms/discord/commands/user.test.js +0 -103
  247. package/dist/src/platforms/discord/commands/user.test.js.map +0 -1
  248. package/dist/src/platforms/discord/credential-manager.test.d.ts +0 -2
  249. package/dist/src/platforms/discord/credential-manager.test.d.ts.map +0 -1
  250. package/dist/src/platforms/discord/credential-manager.test.js +0 -136
  251. package/dist/src/platforms/discord/credential-manager.test.js.map +0 -1
  252. package/dist/src/platforms/discord/token-extractor.test.d.ts +0 -2
  253. package/dist/src/platforms/discord/token-extractor.test.d.ts.map +0 -1
  254. package/dist/src/platforms/discord/token-extractor.test.js +0 -789
  255. package/dist/src/platforms/discord/token-extractor.test.js.map +0 -1
  256. package/dist/src/platforms/discord/types.test.d.ts +0 -2
  257. package/dist/src/platforms/discord/types.test.d.ts.map +0 -1
  258. package/dist/src/platforms/discord/types.test.js +0 -211
  259. package/dist/src/platforms/discord/types.test.js.map +0 -1
  260. package/dist/src/shared/utils/concurrency.test.d.ts +0 -2
  261. package/dist/src/shared/utils/concurrency.test.d.ts.map +0 -1
  262. package/dist/src/shared/utils/concurrency.test.js +0 -39
  263. package/dist/src/shared/utils/concurrency.test.js.map +0 -1
  264. package/dist/tests/cli.test.d.ts +0 -2
  265. package/dist/tests/cli.test.d.ts.map +0 -1
  266. package/dist/tests/cli.test.js +0 -83
  267. package/dist/tests/cli.test.js.map +0 -1
  268. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/CURRENT +0 -1
  269. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOCK +0 -0
  270. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOG +0 -3
  271. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOG.old +0 -1
  272. package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/MANIFEST-000004 +0 -0
  273. package/dist/tests/commands/auth.test.d.ts +0 -2
  274. package/dist/tests/commands/auth.test.d.ts.map +0 -1
  275. package/dist/tests/commands/auth.test.js +0 -304
  276. package/dist/tests/commands/auth.test.js.map +0 -1
  277. package/dist/tests/commands/channel.test.d.ts +0 -2
  278. package/dist/tests/commands/channel.test.d.ts.map +0 -1
  279. package/dist/tests/commands/channel.test.js +0 -166
  280. package/dist/tests/commands/channel.test.js.map +0 -1
  281. package/dist/tests/commands/file.test.d.ts +0 -2
  282. package/dist/tests/commands/file.test.d.ts.map +0 -1
  283. package/dist/tests/commands/file.test.js +0 -175
  284. package/dist/tests/commands/file.test.js.map +0 -1
  285. package/dist/tests/commands/message.test.d.ts +0 -2
  286. package/dist/tests/commands/message.test.d.ts.map +0 -1
  287. package/dist/tests/commands/message.test.js +0 -293
  288. package/dist/tests/commands/message.test.js.map +0 -1
  289. package/dist/tests/commands/reaction.test.d.ts +0 -2
  290. package/dist/tests/commands/reaction.test.d.ts.map +0 -1
  291. package/dist/tests/commands/reaction.test.js +0 -84
  292. package/dist/tests/commands/reaction.test.js.map +0 -1
  293. package/dist/tests/commands/snapshot.test.d.ts +0 -2
  294. package/dist/tests/commands/snapshot.test.d.ts.map +0 -1
  295. package/dist/tests/commands/snapshot.test.js +0 -280
  296. package/dist/tests/commands/snapshot.test.js.map +0 -1
  297. package/dist/tests/commands/user.test.d.ts +0 -2
  298. package/dist/tests/commands/user.test.d.ts.map +0 -1
  299. package/dist/tests/commands/user.test.js +0 -117
  300. package/dist/tests/commands/user.test.js.map +0 -1
  301. package/dist/tests/commands/workspace.test.d.ts +0 -2
  302. package/dist/tests/commands/workspace.test.d.ts.map +0 -1
  303. package/dist/tests/commands/workspace.test.js +0 -453
  304. package/dist/tests/commands/workspace.test.js.map +0 -1
  305. package/dist/tests/credential-manager.test.d.ts +0 -2
  306. package/dist/tests/credential-manager.test.d.ts.map +0 -1
  307. package/dist/tests/credential-manager.test.js +0 -199
  308. package/dist/tests/credential-manager.test.js.map +0 -1
  309. package/dist/tests/slack-client.test.d.ts +0 -2
  310. package/dist/tests/slack-client.test.d.ts.map +0 -1
  311. package/dist/tests/slack-client.test.js +0 -741
  312. package/dist/tests/slack-client.test.js.map +0 -1
  313. package/dist/tests/types.test.d.ts +0 -2
  314. package/dist/tests/types.test.d.ts.map +0 -1
  315. package/dist/tests/types.test.js +0 -215
  316. package/dist/tests/types.test.js.map +0 -1
  317. package/dist/types/index.d.ts +0 -369
  318. package/dist/types/index.d.ts.map +0 -1
  319. package/dist/types/index.js +0 -92
  320. package/dist/types/index.js.map +0 -1
  321. package/dist/utils/error-handler.d.ts +0 -2
  322. package/dist/utils/error-handler.d.ts.map +0 -1
  323. package/dist/utils/error-handler.js +0 -5
  324. package/dist/utils/error-handler.js.map +0 -1
  325. package/dist/utils/output.d.ts +0 -2
  326. package/dist/utils/output.d.ts.map +0 -1
  327. package/dist/utils/output.js +0 -4
  328. package/dist/utils/output.js.map +0 -1
  329. /package/dist/{cli.d.ts → src/platforms/teams/cli.d.ts} +0 -0
  330. /package/dist/{commands → src/platforms/teams/commands}/user.d.ts +0 -0
@@ -1,741 +0,0 @@
1
- import { beforeEach, describe, expect, mock, test } from 'bun:test';
2
- import { SlackClient, SlackError } from '../src/platforms/slack/client';
3
- const mockWebClient = {
4
- conversations: {
5
- list: mock(() => Promise.resolve({ ok: true, channels: [] })),
6
- info: mock(() => Promise.resolve({ ok: true, channel: {} })),
7
- history: mock(() => Promise.resolve({ ok: true, messages: [] })),
8
- replies: mock(() => Promise.resolve({ ok: true, messages: [], has_more: false })),
9
- },
10
- chat: {
11
- postMessage: mock(() => Promise.resolve({ ok: true, ts: '123.456', message: {} })),
12
- update: mock(() => Promise.resolve({ ok: true, ts: '123.456', message: {} })),
13
- delete: mock(() => Promise.resolve({ ok: true })),
14
- },
15
- reactions: {
16
- add: mock(() => Promise.resolve({ ok: true })),
17
- remove: mock(() => Promise.resolve({ ok: true })),
18
- },
19
- users: {
20
- list: mock(() => Promise.resolve({ ok: true, members: [] })),
21
- info: mock(() => Promise.resolve({ ok: true, user: {} })),
22
- },
23
- files: {
24
- uploadV2: mock(() => Promise.resolve({ ok: true, file: {} })),
25
- list: mock(() => Promise.resolve({ ok: true, files: [] })),
26
- },
27
- auth: {
28
- test: mock(() => Promise.resolve({ ok: true, user_id: 'U123', team_id: 'T123' })),
29
- },
30
- };
31
- function resetMocks() {
32
- for (const group of Object.values(mockWebClient)) {
33
- for (const fn of Object.values(group)) {
34
- if (typeof fn.mockReset === 'function') {
35
- fn.mockReset();
36
- }
37
- }
38
- }
39
- }
40
- describe('SlackClient', () => {
41
- describe('constructor', () => {
42
- test('throws SlackError when token is empty', () => {
43
- expect(() => new SlackClient('', 'xoxd-cookie')).toThrow(SlackError);
44
- expect(() => new SlackClient('', 'xoxd-cookie')).toThrow('Token is required');
45
- });
46
- test('throws SlackError when cookie is empty', () => {
47
- expect(() => new SlackClient('xoxc-token', '')).toThrow(SlackError);
48
- expect(() => new SlackClient('xoxc-token', '')).toThrow('Cookie is required');
49
- });
50
- test('throws SlackError when both token and cookie are empty', () => {
51
- expect(() => new SlackClient('', '')).toThrow(SlackError);
52
- });
53
- test('creates client successfully with valid token and cookie', () => {
54
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
55
- expect(client).toBeInstanceOf(SlackClient);
56
- });
57
- });
58
- describe('testAuth', () => {
59
- beforeEach(() => resetMocks());
60
- test('returns auth info on success', async () => {
61
- mockWebClient.auth.test.mockResolvedValue({
62
- ok: true,
63
- user_id: 'U123',
64
- team_id: 'T123',
65
- user: 'testuser',
66
- team: 'Test Team',
67
- });
68
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
69
- // @ts-expect-error - accessing private property for testing
70
- client.client = mockWebClient;
71
- const result = await client.testAuth();
72
- expect(result.user_id).toBe('U123');
73
- expect(result.team_id).toBe('T123');
74
- });
75
- test('throws SlackError on API failure', async () => {
76
- mockWebClient.auth.test.mockResolvedValue({
77
- ok: false,
78
- error: 'invalid_auth',
79
- });
80
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
81
- // @ts-expect-error - accessing private property for testing
82
- client.client = mockWebClient;
83
- await expect(client.testAuth()).rejects.toThrow(SlackError);
84
- });
85
- });
86
- describe('listChannels', () => {
87
- beforeEach(() => resetMocks());
88
- test('returns list of channels', async () => {
89
- mockWebClient.conversations.list.mockResolvedValue({
90
- ok: true,
91
- channels: [
92
- {
93
- id: 'C123',
94
- name: 'general',
95
- is_private: false,
96
- is_archived: false,
97
- created: 1234567890,
98
- creator: 'U123',
99
- },
100
- {
101
- id: 'C456',
102
- name: 'random',
103
- is_private: false,
104
- is_archived: false,
105
- created: 1234567891,
106
- creator: 'U123',
107
- },
108
- ],
109
- });
110
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
111
- // @ts-expect-error - accessing private property for testing
112
- client.client = mockWebClient;
113
- const channels = await client.listChannels();
114
- expect(channels).toHaveLength(2);
115
- expect(channels[0].id).toBe('C123');
116
- expect(channels[1].name).toBe('random');
117
- });
118
- test('handles pagination automatically', async () => {
119
- mockWebClient.conversations.list
120
- .mockResolvedValueOnce({
121
- ok: true,
122
- channels: [
123
- {
124
- id: 'C123',
125
- name: 'general',
126
- is_private: false,
127
- is_archived: false,
128
- created: 1234567890,
129
- creator: 'U123',
130
- },
131
- ],
132
- response_metadata: { next_cursor: 'cursor123' },
133
- })
134
- .mockResolvedValueOnce({
135
- ok: true,
136
- channels: [
137
- {
138
- id: 'C456',
139
- name: 'random',
140
- is_private: false,
141
- is_archived: false,
142
- created: 1234567891,
143
- creator: 'U123',
144
- },
145
- ],
146
- });
147
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
148
- // @ts-expect-error - accessing private property for testing
149
- client.client = mockWebClient;
150
- const channels = await client.listChannels();
151
- expect(channels).toHaveLength(2);
152
- expect(mockWebClient.conversations.list).toHaveBeenCalledTimes(2);
153
- });
154
- test('throws SlackError on API failure', async () => {
155
- mockWebClient.conversations.list.mockResolvedValue({
156
- ok: false,
157
- error: 'channel_not_found',
158
- });
159
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
160
- // @ts-expect-error - accessing private property for testing
161
- client.client = mockWebClient;
162
- await expect(client.listChannels()).rejects.toThrow(SlackError);
163
- });
164
- });
165
- describe('getChannel', () => {
166
- beforeEach(() => resetMocks());
167
- test('returns channel info', async () => {
168
- mockWebClient.conversations.info.mockResolvedValue({
169
- ok: true,
170
- channel: {
171
- id: 'C123',
172
- name: 'general',
173
- is_private: false,
174
- is_archived: false,
175
- created: 1234567890,
176
- creator: 'U123',
177
- },
178
- });
179
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
180
- // @ts-expect-error - accessing private property for testing
181
- client.client = mockWebClient;
182
- const channel = await client.getChannel('C123');
183
- expect(channel.id).toBe('C123');
184
- expect(channel.name).toBe('general');
185
- });
186
- test('throws SlackError when channel not found', async () => {
187
- mockWebClient.conversations.info.mockResolvedValue({
188
- ok: false,
189
- error: 'channel_not_found',
190
- });
191
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
192
- // @ts-expect-error - accessing private property for testing
193
- client.client = mockWebClient;
194
- await expect(client.getChannel('C999')).rejects.toThrow(SlackError);
195
- });
196
- });
197
- describe('getMessages', () => {
198
- beforeEach(() => resetMocks());
199
- test('returns messages with default limit of 20', async () => {
200
- const messages = Array.from({ length: 20 }, (_, i) => ({
201
- ts: `123.${i}`,
202
- text: `Message ${i}`,
203
- type: 'message',
204
- }));
205
- mockWebClient.conversations.history.mockResolvedValue({
206
- ok: true,
207
- messages,
208
- });
209
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
210
- // @ts-expect-error - accessing private property for testing
211
- client.client = mockWebClient;
212
- const result = await client.getMessages('C123');
213
- expect(result).toHaveLength(20);
214
- expect(mockWebClient.conversations.history).toHaveBeenCalledWith(expect.objectContaining({ channel: 'C123', limit: 20 }));
215
- });
216
- test('respects custom limit', async () => {
217
- mockWebClient.conversations.history.mockResolvedValue({
218
- ok: true,
219
- messages: [{ ts: '123.456', text: 'Hello', type: 'message' }],
220
- });
221
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
222
- // @ts-expect-error - accessing private property for testing
223
- client.client = mockWebClient;
224
- await client.getMessages('C123', 50);
225
- expect(mockWebClient.conversations.history).toHaveBeenCalledWith(expect.objectContaining({ channel: 'C123', limit: 50 }));
226
- });
227
- test('throws SlackError on API failure', async () => {
228
- mockWebClient.conversations.history.mockResolvedValue({
229
- ok: false,
230
- error: 'channel_not_found',
231
- });
232
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
233
- // @ts-expect-error - accessing private property for testing
234
- client.client = mockWebClient;
235
- await expect(client.getMessages('C999')).rejects.toThrow(SlackError);
236
- });
237
- });
238
- describe('sendMessage', () => {
239
- beforeEach(() => resetMocks());
240
- test('sends message to channel', async () => {
241
- mockWebClient.chat.postMessage.mockResolvedValue({
242
- ok: true,
243
- ts: '123.456',
244
- message: { ts: '123.456', text: 'Hello', type: 'message' },
245
- });
246
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
247
- // @ts-expect-error - accessing private property for testing
248
- client.client = mockWebClient;
249
- const message = await client.sendMessage('C123', 'Hello');
250
- expect(message.ts).toBe('123.456');
251
- expect(mockWebClient.chat.postMessage).toHaveBeenCalledWith(expect.objectContaining({ channel: 'C123', text: 'Hello' }));
252
- });
253
- test('sends message to thread', async () => {
254
- mockWebClient.chat.postMessage.mockResolvedValue({
255
- ok: true,
256
- ts: '123.789',
257
- message: { ts: '123.789', text: 'Reply', type: 'message', thread_ts: '123.456' },
258
- });
259
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
260
- // @ts-expect-error - accessing private property for testing
261
- client.client = mockWebClient;
262
- const message = await client.sendMessage('C123', 'Reply', '123.456');
263
- expect(message.thread_ts).toBe('123.456');
264
- expect(mockWebClient.chat.postMessage).toHaveBeenCalledWith(expect.objectContaining({ channel: 'C123', text: 'Reply', thread_ts: '123.456' }));
265
- });
266
- test('throws SlackError on API failure', async () => {
267
- mockWebClient.chat.postMessage.mockResolvedValue({
268
- ok: false,
269
- error: 'channel_not_found',
270
- });
271
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
272
- // @ts-expect-error - accessing private property for testing
273
- client.client = mockWebClient;
274
- await expect(client.sendMessage('C999', 'Hello')).rejects.toThrow(SlackError);
275
- });
276
- });
277
- describe('updateMessage', () => {
278
- beforeEach(() => resetMocks());
279
- test('updates message text', async () => {
280
- mockWebClient.chat.update.mockResolvedValue({
281
- ok: true,
282
- ts: '123.456',
283
- message: { ts: '123.456', text: 'Updated', type: 'message' },
284
- });
285
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
286
- // @ts-expect-error - accessing private property for testing
287
- client.client = mockWebClient;
288
- const message = await client.updateMessage('C123', '123.456', 'Updated');
289
- expect(message.text).toBe('Updated');
290
- expect(mockWebClient.chat.update).toHaveBeenCalledWith(expect.objectContaining({ channel: 'C123', ts: '123.456', text: 'Updated' }));
291
- });
292
- test('throws SlackError on API failure', async () => {
293
- mockWebClient.chat.update.mockResolvedValue({
294
- ok: false,
295
- error: 'message_not_found',
296
- });
297
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
298
- // @ts-expect-error - accessing private property for testing
299
- client.client = mockWebClient;
300
- await expect(client.updateMessage('C123', '999.999', 'Updated')).rejects.toThrow(SlackError);
301
- });
302
- });
303
- describe('deleteMessage', () => {
304
- beforeEach(() => resetMocks());
305
- test('deletes message', async () => {
306
- mockWebClient.chat.delete.mockResolvedValue({ ok: true });
307
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
308
- // @ts-expect-error - accessing private property for testing
309
- client.client = mockWebClient;
310
- await expect(client.deleteMessage('C123', '123.456')).resolves.toBeUndefined();
311
- expect(mockWebClient.chat.delete).toHaveBeenCalledWith(expect.objectContaining({ channel: 'C123', ts: '123.456' }));
312
- });
313
- test('throws SlackError on API failure', async () => {
314
- mockWebClient.chat.delete.mockResolvedValue({
315
- ok: false,
316
- error: 'message_not_found',
317
- });
318
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
319
- // @ts-expect-error - accessing private property for testing
320
- client.client = mockWebClient;
321
- await expect(client.deleteMessage('C123', '999.999')).rejects.toThrow(SlackError);
322
- });
323
- });
324
- describe('addReaction', () => {
325
- beforeEach(() => resetMocks());
326
- test('adds reaction to message', async () => {
327
- mockWebClient.reactions.add.mockResolvedValue({ ok: true });
328
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
329
- // @ts-expect-error - accessing private property for testing
330
- client.client = mockWebClient;
331
- await expect(client.addReaction('C123', '123.456', 'thumbsup')).resolves.toBeUndefined();
332
- expect(mockWebClient.reactions.add).toHaveBeenCalledWith(expect.objectContaining({ channel: 'C123', timestamp: '123.456', name: 'thumbsup' }));
333
- });
334
- test('throws SlackError on API failure', async () => {
335
- mockWebClient.reactions.add.mockResolvedValue({
336
- ok: false,
337
- error: 'already_reacted',
338
- });
339
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
340
- // @ts-expect-error - accessing private property for testing
341
- client.client = mockWebClient;
342
- await expect(client.addReaction('C123', '123.456', 'thumbsup')).rejects.toThrow(SlackError);
343
- });
344
- });
345
- describe('removeReaction', () => {
346
- beforeEach(() => resetMocks());
347
- test('removes reaction from message', async () => {
348
- mockWebClient.reactions.remove.mockResolvedValue({ ok: true });
349
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
350
- // @ts-expect-error - accessing private property for testing
351
- client.client = mockWebClient;
352
- await expect(client.removeReaction('C123', '123.456', 'thumbsup')).resolves.toBeUndefined();
353
- expect(mockWebClient.reactions.remove).toHaveBeenCalledWith(expect.objectContaining({ channel: 'C123', timestamp: '123.456', name: 'thumbsup' }));
354
- });
355
- test('throws SlackError on API failure', async () => {
356
- mockWebClient.reactions.remove.mockResolvedValue({
357
- ok: false,
358
- error: 'no_reaction',
359
- });
360
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
361
- // @ts-expect-error - accessing private property for testing
362
- client.client = mockWebClient;
363
- await expect(client.removeReaction('C123', '123.456', 'thumbsup')).rejects.toThrow(SlackError);
364
- });
365
- });
366
- describe('listUsers', () => {
367
- beforeEach(() => resetMocks());
368
- test('returns list of users', async () => {
369
- mockWebClient.users.list.mockResolvedValue({
370
- ok: true,
371
- members: [
372
- {
373
- id: 'U123',
374
- name: 'alice',
375
- real_name: 'Alice',
376
- is_admin: false,
377
- is_owner: false,
378
- is_bot: false,
379
- is_app_user: false,
380
- },
381
- {
382
- id: 'U456',
383
- name: 'bob',
384
- real_name: 'Bob',
385
- is_admin: true,
386
- is_owner: false,
387
- is_bot: false,
388
- is_app_user: false,
389
- },
390
- ],
391
- });
392
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
393
- // @ts-expect-error - accessing private property for testing
394
- client.client = mockWebClient;
395
- const users = await client.listUsers();
396
- expect(users).toHaveLength(2);
397
- expect(users[0].name).toBe('alice');
398
- expect(users[1].is_admin).toBe(true);
399
- });
400
- test('handles pagination automatically', async () => {
401
- mockWebClient.users.list
402
- .mockResolvedValueOnce({
403
- ok: true,
404
- members: [
405
- {
406
- id: 'U123',
407
- name: 'alice',
408
- real_name: 'Alice',
409
- is_admin: false,
410
- is_owner: false,
411
- is_bot: false,
412
- is_app_user: false,
413
- },
414
- ],
415
- response_metadata: { next_cursor: 'cursor123' },
416
- })
417
- .mockResolvedValueOnce({
418
- ok: true,
419
- members: [
420
- {
421
- id: 'U456',
422
- name: 'bob',
423
- real_name: 'Bob',
424
- is_admin: false,
425
- is_owner: false,
426
- is_bot: false,
427
- is_app_user: false,
428
- },
429
- ],
430
- });
431
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
432
- // @ts-expect-error - accessing private property for testing
433
- client.client = mockWebClient;
434
- const users = await client.listUsers();
435
- expect(users).toHaveLength(2);
436
- expect(mockWebClient.users.list).toHaveBeenCalledTimes(2);
437
- });
438
- test('throws SlackError on API failure', async () => {
439
- mockWebClient.users.list.mockResolvedValue({
440
- ok: false,
441
- error: 'invalid_auth',
442
- });
443
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
444
- // @ts-expect-error - accessing private property for testing
445
- client.client = mockWebClient;
446
- await expect(client.listUsers()).rejects.toThrow(SlackError);
447
- });
448
- });
449
- describe('getUser', () => {
450
- beforeEach(() => resetMocks());
451
- test('returns user info', async () => {
452
- mockWebClient.users.info.mockResolvedValue({
453
- ok: true,
454
- user: {
455
- id: 'U123',
456
- name: 'alice',
457
- real_name: 'Alice',
458
- is_admin: false,
459
- is_owner: false,
460
- is_bot: false,
461
- is_app_user: false,
462
- },
463
- });
464
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
465
- // @ts-expect-error - accessing private property for testing
466
- client.client = mockWebClient;
467
- const user = await client.getUser('U123');
468
- expect(user.id).toBe('U123');
469
- expect(user.name).toBe('alice');
470
- });
471
- test('throws SlackError when user not found', async () => {
472
- mockWebClient.users.info.mockResolvedValue({
473
- ok: false,
474
- error: 'user_not_found',
475
- });
476
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
477
- // @ts-expect-error - accessing private property for testing
478
- client.client = mockWebClient;
479
- await expect(client.getUser('U999')).rejects.toThrow(SlackError);
480
- });
481
- });
482
- describe('uploadFile', () => {
483
- beforeEach(() => resetMocks());
484
- test('uploads file to channels', async () => {
485
- mockWebClient.files.uploadV2.mockResolvedValue({
486
- ok: true,
487
- file: {
488
- id: 'F123',
489
- name: 'test.txt',
490
- title: 'test.txt',
491
- mimetype: 'text/plain',
492
- size: 100,
493
- url_private: 'https://...',
494
- created: 1234567890,
495
- user: 'U123',
496
- },
497
- });
498
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
499
- // @ts-expect-error - accessing private property for testing
500
- client.client = mockWebClient;
501
- const file = await client.uploadFile(['C123'], Buffer.from('test'), 'test.txt');
502
- expect(file.id).toBe('F123');
503
- expect(mockWebClient.files.uploadV2).toHaveBeenCalledWith(expect.objectContaining({ channel_id: 'C123', filename: 'test.txt' }));
504
- });
505
- test('throws SlackError on API failure', async () => {
506
- mockWebClient.files.uploadV2.mockResolvedValue({
507
- ok: false,
508
- error: 'file_upload_failed',
509
- });
510
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
511
- // @ts-expect-error - accessing private property for testing
512
- client.client = mockWebClient;
513
- await expect(client.uploadFile(['C123'], Buffer.from('test'), 'test.txt')).rejects.toThrow(SlackError);
514
- });
515
- });
516
- describe('listFiles', () => {
517
- beforeEach(() => resetMocks());
518
- test('returns list of files', async () => {
519
- mockWebClient.files.list.mockResolvedValue({
520
- ok: true,
521
- files: [
522
- {
523
- id: 'F123',
524
- name: 'test.txt',
525
- title: 'test.txt',
526
- mimetype: 'text/plain',
527
- size: 100,
528
- url_private: 'https://...',
529
- created: 1234567890,
530
- user: 'U123',
531
- },
532
- ],
533
- });
534
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
535
- // @ts-expect-error - accessing private property for testing
536
- client.client = mockWebClient;
537
- const files = await client.listFiles();
538
- expect(files).toHaveLength(1);
539
- expect(files[0].name).toBe('test.txt');
540
- });
541
- test('filters by channel when provided', async () => {
542
- mockWebClient.files.list.mockResolvedValue({
543
- ok: true,
544
- files: [],
545
- });
546
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
547
- // @ts-expect-error - accessing private property for testing
548
- client.client = mockWebClient;
549
- await client.listFiles('C123');
550
- expect(mockWebClient.files.list).toHaveBeenCalledWith(expect.objectContaining({ channel: 'C123' }));
551
- });
552
- test('throws SlackError on API failure', async () => {
553
- mockWebClient.files.list.mockResolvedValue({
554
- ok: false,
555
- error: 'invalid_auth',
556
- });
557
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
558
- // @ts-expect-error - accessing private property for testing
559
- client.client = mockWebClient;
560
- await expect(client.listFiles()).rejects.toThrow(SlackError);
561
- });
562
- });
563
- describe('getThreadReplies', () => {
564
- beforeEach(() => resetMocks());
565
- test('returns thread replies including parent message', async () => {
566
- mockWebClient.conversations.replies.mockResolvedValue({
567
- ok: true,
568
- messages: [
569
- {
570
- ts: '123.456',
571
- text: 'Parent message',
572
- type: 'message',
573
- user: 'U123',
574
- thread_ts: '123.456',
575
- reply_count: 2,
576
- },
577
- {
578
- ts: '123.457',
579
- text: 'First reply',
580
- type: 'message',
581
- user: 'U456',
582
- thread_ts: '123.456',
583
- },
584
- {
585
- ts: '123.458',
586
- text: 'Second reply',
587
- type: 'message',
588
- user: 'U789',
589
- thread_ts: '123.456',
590
- },
591
- ],
592
- has_more: false,
593
- });
594
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
595
- // @ts-expect-error - accessing private property for testing
596
- client.client = mockWebClient;
597
- const result = await client.getThreadReplies('C123', '123.456');
598
- expect(result.messages).toHaveLength(3);
599
- expect(result.messages[0].text).toBe('Parent message');
600
- expect(result.messages[0].reply_count).toBe(2);
601
- expect(result.messages[1].text).toBe('First reply');
602
- expect(result.messages[2].text).toBe('Second reply');
603
- expect(result.has_more).toBe(false);
604
- });
605
- test('respects limit parameter', async () => {
606
- mockWebClient.conversations.replies.mockResolvedValue({
607
- ok: true,
608
- messages: [{ ts: '123.456', text: 'Hello', type: 'message' }],
609
- has_more: false,
610
- });
611
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
612
- // @ts-expect-error - accessing private property for testing
613
- client.client = mockWebClient;
614
- await client.getThreadReplies('C123', '123.456', { limit: 50 });
615
- expect(mockWebClient.conversations.replies).toHaveBeenCalledWith(expect.objectContaining({ channel: 'C123', ts: '123.456', limit: 50 }));
616
- });
617
- test('passes optional oldest and latest parameters', async () => {
618
- mockWebClient.conversations.replies.mockResolvedValue({
619
- ok: true,
620
- messages: [],
621
- has_more: false,
622
- });
623
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
624
- // @ts-expect-error - accessing private property for testing
625
- client.client = mockWebClient;
626
- await client.getThreadReplies('C123', '123.456', {
627
- oldest: '123.400',
628
- latest: '123.500',
629
- });
630
- expect(mockWebClient.conversations.replies).toHaveBeenCalledWith(expect.objectContaining({
631
- channel: 'C123',
632
- ts: '123.456',
633
- oldest: '123.400',
634
- latest: '123.500',
635
- }));
636
- });
637
- test('returns pagination info when has_more is true', async () => {
638
- mockWebClient.conversations.replies.mockResolvedValue({
639
- ok: true,
640
- messages: [{ ts: '123.456', text: 'Hello', type: 'message' }],
641
- has_more: true,
642
- response_metadata: { next_cursor: 'cursor123' },
643
- });
644
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
645
- // @ts-expect-error - accessing private property for testing
646
- client.client = mockWebClient;
647
- const result = await client.getThreadReplies('C123', '123.456');
648
- expect(result.has_more).toBe(true);
649
- expect(result.next_cursor).toBe('cursor123');
650
- });
651
- test('throws SlackError when thread not found', async () => {
652
- mockWebClient.conversations.replies.mockResolvedValue({
653
- ok: false,
654
- error: 'thread_not_found',
655
- });
656
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
657
- // @ts-expect-error - accessing private property for testing
658
- client.client = mockWebClient;
659
- await expect(client.getThreadReplies('C123', '999.999')).rejects.toThrow(SlackError);
660
- });
661
- test('throws SlackError when channel not found', async () => {
662
- mockWebClient.conversations.replies.mockResolvedValue({
663
- ok: false,
664
- error: 'channel_not_found',
665
- });
666
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
667
- // @ts-expect-error - accessing private property for testing
668
- client.client = mockWebClient;
669
- await expect(client.getThreadReplies('C999', '123.456')).rejects.toThrow(SlackError);
670
- });
671
- });
672
- describe('rate limiting', () => {
673
- beforeEach(() => resetMocks());
674
- test('retries on rate limit error with exponential backoff', async () => {
675
- const rateLimitError = new Error('Rate limited');
676
- rateLimitError.code = 'slack_webapi_rate_limited_error';
677
- rateLimitError.retryAfter = 0.001;
678
- mockWebClient.conversations.list
679
- .mockRejectedValueOnce(rateLimitError)
680
- .mockRejectedValueOnce(rateLimitError)
681
- .mockResolvedValueOnce({
682
- ok: true,
683
- channels: [
684
- {
685
- id: 'C123',
686
- name: 'general',
687
- is_private: false,
688
- is_archived: false,
689
- created: 1234567890,
690
- creator: 'U123',
691
- },
692
- ],
693
- });
694
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
695
- // @ts-expect-error - accessing private property for testing
696
- client.client = mockWebClient;
697
- const channels = await client.listChannels();
698
- expect(channels).toHaveLength(1);
699
- expect(mockWebClient.conversations.list).toHaveBeenCalledTimes(3);
700
- });
701
- test('throws SlackError after max retries (3)', async () => {
702
- const rateLimitError = new Error('Rate limited');
703
- rateLimitError.code = 'slack_webapi_rate_limited_error';
704
- rateLimitError.retryAfter = 0.001;
705
- mockWebClient.conversations.list.mockRejectedValue(rateLimitError);
706
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
707
- // @ts-expect-error - accessing private property for testing
708
- client.client = mockWebClient;
709
- await expect(client.listChannels()).rejects.toThrow(SlackError);
710
- // Initial call + 3 retries = 4 total calls
711
- expect(mockWebClient.conversations.list).toHaveBeenCalledTimes(4);
712
- });
713
- test('does not retry on non-rate-limit errors', async () => {
714
- const otherError = new Error('Some other error');
715
- otherError.code = 'some_other_error';
716
- mockWebClient.conversations.list.mockRejectedValue(otherError);
717
- const client = new SlackClient('xoxc-token', 'xoxd-cookie');
718
- // @ts-expect-error - accessing private property for testing
719
- client.client = mockWebClient;
720
- await expect(client.listChannels()).rejects.toThrow(SlackError);
721
- expect(mockWebClient.conversations.list).toHaveBeenCalledTimes(1);
722
- });
723
- });
724
- describe('SlackError', () => {
725
- test('is an instance of Error', () => {
726
- const error = new SlackError('test error', 'test_code');
727
- expect(error).toBeInstanceOf(Error);
728
- expect(error).toBeInstanceOf(SlackError);
729
- });
730
- test('has message and code properties', () => {
731
- const error = new SlackError('test error', 'test_code');
732
- expect(error.message).toBe('test error');
733
- expect(error.code).toBe('test_code');
734
- });
735
- test('has name property set to SlackError', () => {
736
- const error = new SlackError('test error', 'test_code');
737
- expect(error.name).toBe('SlackError');
738
- });
739
- });
740
- });
741
- //# sourceMappingURL=slack-client.test.js.map