agent-messenger 2.10.1 → 2.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/package.json +1 -1
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/teams/token-extractor.js +9 -2
- package/dist/src/platforms/teams/token-extractor.js.map +1 -1
- package/dist/src/shared/chromium/decryptor.d.ts +6 -0
- package/dist/src/shared/chromium/decryptor.d.ts.map +1 -1
- package/dist/src/shared/chromium/decryptor.js +26 -6
- package/dist/src/shared/chromium/decryptor.js.map +1 -1
- package/e2e/channeltalk.e2e.test.ts +13 -13
- package/e2e/channeltalkbot.e2e.test.ts +13 -13
- package/e2e/discord.e2e.test.ts +24 -24
- package/e2e/discordbot.e2e.test.ts +16 -16
- package/e2e/instagram.e2e.test.ts +10 -10
- package/e2e/kakaotalk.e2e.test.ts +7 -7
- package/e2e/line.e2e.test.ts +8 -8
- package/e2e/slack.e2e.test.ts +34 -34
- package/e2e/slackbot.e2e.test.ts +14 -14
- package/e2e/teams.e2e.test.ts +23 -23
- package/e2e/telegram.e2e.test.ts +8 -8
- package/e2e/webex.e2e.test.ts +14 -14
- package/e2e/whatsapp.e2e.test.ts +8 -8
- package/e2e/whatsappbot.e2e.test.ts +6 -6
- package/package.json +1 -1
- package/skills/agent-channeltalk/SKILL.md +1 -1
- package/skills/agent-channeltalkbot/SKILL.md +1 -1
- package/skills/agent-discord/SKILL.md +1 -1
- package/skills/agent-discordbot/SKILL.md +1 -1
- package/skills/agent-instagram/SKILL.md +1 -1
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +1 -1
- package/skills/agent-slackbot/SKILL.md +1 -1
- package/skills/agent-teams/SKILL.md +1 -1
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +1 -1
- package/skills/agent-wechatbot/SKILL.md +1 -1
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +1 -1
- package/src/platforms/channeltalk/client.test.ts +26 -26
- package/src/platforms/channeltalk/commands/auth.test.ts +16 -16
- package/src/platforms/channeltalk/commands/bot.test.ts +2 -2
- package/src/platforms/channeltalk/commands/chat.test.ts +3 -3
- package/src/platforms/channeltalk/commands/group.test.ts +4 -4
- package/src/platforms/channeltalk/commands/manager.test.ts +2 -2
- package/src/platforms/channeltalk/commands/message.test.ts +17 -17
- package/src/platforms/channeltalk/commands/snapshot.test.ts +7 -7
- package/src/platforms/channeltalk/commands/whoami.test.ts +3 -3
- package/src/platforms/channeltalk/credential-manager.test.ts +18 -18
- package/src/platforms/channeltalk/ensure-auth.test.ts +5 -5
- package/src/platforms/channeltalk/index.test.ts +23 -23
- package/src/platforms/channeltalk/token-extractor.test.ts +21 -21
- package/src/platforms/channeltalk/types.test.ts +12 -12
- package/src/platforms/channeltalkbot/client.test.ts +14 -14
- package/src/platforms/channeltalkbot/commands/auth.test.ts +16 -16
- package/src/platforms/channeltalkbot/commands/bot.test.ts +6 -6
- package/src/platforms/channeltalkbot/commands/chat.test.ts +9 -9
- package/src/platforms/channeltalkbot/commands/group.test.ts +6 -6
- package/src/platforms/channeltalkbot/commands/manager.test.ts +3 -3
- package/src/platforms/channeltalkbot/commands/message.test.ts +10 -10
- package/src/platforms/channeltalkbot/commands/snapshot.test.ts +7 -7
- package/src/platforms/channeltalkbot/commands/whoami.test.ts +4 -4
- package/src/platforms/channeltalkbot/credential-manager.test.ts +27 -27
- package/src/platforms/channeltalkbot/index.test.ts +15 -15
- package/src/platforms/discord/client.test.ts +28 -28
- package/src/platforms/discord/commands/auth.test.ts +7 -7
- package/src/platforms/discord/commands/channel.test.ts +7 -7
- package/src/platforms/discord/commands/dm.test.ts +4 -4
- package/src/platforms/discord/commands/file.test.ts +4 -4
- package/src/platforms/discord/commands/friend.test.ts +6 -6
- package/src/platforms/discord/commands/member.test.ts +5 -5
- package/src/platforms/discord/commands/mention.test.ts +5 -5
- package/src/platforms/discord/commands/message.test.ts +9 -9
- package/src/platforms/discord/commands/note.test.ts +6 -6
- package/src/platforms/discord/commands/profile.test.ts +4 -4
- package/src/platforms/discord/commands/reaction.test.ts +5 -5
- package/src/platforms/discord/commands/server.test.ts +7 -7
- package/src/platforms/discord/commands/snapshot.test.ts +6 -6
- package/src/platforms/discord/commands/thread.test.ts +6 -6
- package/src/platforms/discord/commands/user.test.ts +5 -5
- package/src/platforms/discord/commands/whoami.test.ts +6 -6
- package/src/platforms/discord/credential-manager.test.ts +16 -16
- package/src/platforms/discord/ensure-auth.test.ts +8 -8
- package/src/platforms/discord/index.test.ts +17 -17
- package/src/platforms/discord/listener.test.ts +33 -33
- package/src/platforms/discord/token-extractor.test.ts +53 -53
- package/src/platforms/discord/types.test.ts +26 -26
- package/src/platforms/discordbot/client.test.ts +31 -31
- package/src/platforms/discordbot/commands/auth.test.ts +18 -18
- package/src/platforms/discordbot/commands/channel.test.ts +11 -11
- package/src/platforms/discordbot/commands/file.test.ts +7 -7
- package/src/platforms/discordbot/commands/message.test.ts +25 -25
- package/src/platforms/discordbot/commands/reaction.test.ts +6 -6
- package/src/platforms/discordbot/commands/server.test.ts +12 -12
- package/src/platforms/discordbot/commands/snapshot.test.ts +13 -13
- package/src/platforms/discordbot/commands/thread.test.ts +10 -10
- package/src/platforms/discordbot/commands/user.test.ts +9 -9
- package/src/platforms/discordbot/commands/whoami.test.ts +4 -4
- package/src/platforms/discordbot/credential-manager.test.ts +28 -28
- package/src/platforms/instagram/client.test.ts +18 -18
- package/src/platforms/instagram/commands/auth.test.ts +11 -11
- package/src/platforms/instagram/commands/chat.test.ts +6 -6
- package/src/platforms/instagram/commands/message.test.ts +11 -11
- package/src/platforms/instagram/commands/shared.test.ts +12 -12
- package/src/platforms/instagram/commands/whoami.test.ts +3 -3
- package/src/platforms/instagram/credential-manager.test.ts +21 -21
- package/src/platforms/instagram/ensure-auth.test.ts +4 -4
- package/src/platforms/instagram/index.test.ts +9 -9
- package/src/platforms/instagram/listener.test.ts +8 -8
- package/src/platforms/instagram/token-extractor.test.ts +35 -35
- package/src/platforms/kakaotalk/client.test.ts +33 -33
- package/src/platforms/kakaotalk/commands/auth.test.ts +11 -11
- package/src/platforms/kakaotalk/commands/chat.test.ts +6 -6
- package/src/platforms/kakaotalk/commands/message.test.ts +7 -7
- package/src/platforms/kakaotalk/commands/whoami.test.ts +5 -5
- package/src/platforms/kakaotalk/credential-manager.test.ts +15 -15
- package/src/platforms/kakaotalk/index.test.ts +15 -15
- package/src/platforms/kakaotalk/listener.test.ts +17 -17
- package/src/platforms/line/client.test.ts +17 -17
- package/src/platforms/line/commands/auth.test.ts +8 -8
- package/src/platforms/line/commands/chat.test.ts +7 -7
- package/src/platforms/line/commands/friend.test.ts +6 -6
- package/src/platforms/line/commands/message.test.ts +7 -7
- package/src/platforms/line/commands/whoami.test.ts +6 -6
- package/src/platforms/line/credential-manager.test.ts +17 -17
- package/src/platforms/line/index.test.ts +10 -10
- package/src/platforms/line/listener.test.ts +15 -15
- package/src/platforms/line/types.test.ts +14 -14
- package/src/platforms/slack/cli.test.ts +8 -8
- package/src/platforms/slack/client.test.ts +151 -151
- package/src/platforms/slack/commands/activity.test.ts +13 -13
- package/src/platforms/slack/commands/auth.test.ts +34 -34
- package/src/platforms/slack/commands/bookmark.test.ts +9 -9
- package/src/platforms/slack/commands/channel.test.ts +17 -17
- package/src/platforms/slack/commands/drafts.test.ts +7 -7
- package/src/platforms/slack/commands/emoji.test.ts +3 -3
- package/src/platforms/slack/commands/file.test.ts +12 -12
- package/src/platforms/slack/commands/message.test.ts +19 -19
- package/src/platforms/slack/commands/pin.test.ts +7 -7
- package/src/platforms/slack/commands/reaction.test.ts +10 -10
- package/src/platforms/slack/commands/reminder.test.ts +9 -9
- package/src/platforms/slack/commands/saved.test.ts +7 -7
- package/src/platforms/slack/commands/sections.test.ts +5 -5
- package/src/platforms/slack/commands/snapshot.test.ts +13 -13
- package/src/platforms/slack/commands/unread.test.ts +6 -6
- package/src/platforms/slack/commands/user.test.ts +10 -10
- package/src/platforms/slack/commands/usergroup.test.ts +15 -15
- package/src/platforms/slack/commands/whoami.test.ts +6 -6
- package/src/platforms/slack/commands/workspace.test.ts +26 -26
- package/src/platforms/slack/credential-manager.test.ts +14 -14
- package/src/platforms/slack/ensure-auth.test.ts +21 -21
- package/src/platforms/slack/index.test.ts +12 -12
- package/src/platforms/slack/listener.test.ts +17 -17
- package/src/platforms/slack/token-extractor-node.test.ts +2 -2
- package/src/platforms/slack/token-extractor.test.ts +37 -37
- package/src/platforms/slack/types.test.ts +21 -21
- package/src/platforms/slackbot/client.test.ts +22 -22
- package/src/platforms/slackbot/commands/auth.test.ts +14 -14
- package/src/platforms/slackbot/commands/channel.test.ts +7 -7
- package/src/platforms/slackbot/commands/message.test.ts +13 -13
- package/src/platforms/slackbot/commands/reaction.test.ts +6 -6
- package/src/platforms/slackbot/commands/user.test.ts +7 -7
- package/src/platforms/slackbot/commands/whoami.test.ts +4 -4
- package/src/platforms/slackbot/credential-manager.test.ts +22 -22
- package/src/platforms/slackbot/types.test.ts +7 -7
- package/src/platforms/teams/client.test.ts +30 -30
- package/src/platforms/teams/commands/auth.test.ts +8 -8
- package/src/platforms/teams/commands/channel.test.ts +7 -7
- package/src/platforms/teams/commands/file.test.ts +4 -4
- package/src/platforms/teams/commands/message.test.ts +5 -5
- package/src/platforms/teams/commands/reaction.test.ts +4 -4
- package/src/platforms/teams/commands/snapshot.test.ts +7 -7
- package/src/platforms/teams/commands/team.test.ts +8 -8
- package/src/platforms/teams/commands/user.test.ts +4 -4
- package/src/platforms/teams/commands/whoami.test.ts +6 -6
- package/src/platforms/teams/credential-manager.test.ts +17 -17
- package/src/platforms/teams/ensure-auth.test.ts +13 -13
- package/src/platforms/teams/index.test.ts +15 -15
- package/src/platforms/teams/token-extractor.test.ts +109 -49
- package/src/platforms/teams/token-extractor.ts +7 -2
- package/src/platforms/teams/types.test.ts +26 -26
- package/src/platforms/telegram/app-config.test.ts +4 -4
- package/src/platforms/telegram/chat-utils.test.ts +12 -12
- package/src/platforms/telegram/client.test.ts +4 -4
- package/src/platforms/telegram/commands/auth.test.ts +16 -16
- package/src/platforms/telegram/commands/chat.test.ts +9 -9
- package/src/platforms/telegram/commands/message.test.ts +6 -6
- package/src/platforms/telegram/commands/shared.test.ts +3 -3
- package/src/platforms/telegram/commands/whoami.test.ts +3 -3
- package/src/platforms/telegram/credential-manager.test.ts +10 -10
- package/src/platforms/telegram/types.test.ts +6 -6
- package/src/platforms/webex/app-config.test.ts +8 -8
- package/src/platforms/webex/cli.test.ts +5 -5
- package/src/platforms/webex/client.test.ts +65 -65
- package/src/platforms/webex/commands/auth.test.ts +18 -18
- package/src/platforms/webex/commands/member.test.ts +5 -5
- package/src/platforms/webex/commands/message.test.ts +12 -12
- package/src/platforms/webex/commands/snapshot.test.ts +5 -5
- package/src/platforms/webex/commands/space.test.ts +10 -10
- package/src/platforms/webex/commands/whoami.test.ts +6 -6
- package/src/platforms/webex/credential-manager.test.ts +22 -22
- package/src/platforms/webex/encryption.test.ts +4 -4
- package/src/platforms/webex/ensure-auth.test.ts +5 -5
- package/src/platforms/webex/index.test.ts +5 -5
- package/src/platforms/webex/markdown-to-html.test.ts +33 -33
- package/src/platforms/webex/token-extractor.test.ts +23 -23
- package/src/platforms/webex/types.test.ts +27 -27
- package/src/platforms/wechatbot/client.test.ts +27 -27
- package/src/platforms/wechatbot/commands/auth.test.ts +15 -15
- package/src/platforms/wechatbot/commands/message.test.ts +8 -8
- package/src/platforms/wechatbot/commands/template.test.ts +9 -9
- package/src/platforms/wechatbot/commands/user.test.ts +7 -7
- package/src/platforms/wechatbot/commands/whoami.test.ts +5 -5
- package/src/platforms/wechatbot/credential-manager.test.ts +18 -18
- package/src/platforms/wechatbot/index.test.ts +10 -10
- package/src/platforms/wechatbot/types.test.ts +25 -25
- package/src/platforms/whatsapp/commands/auth.test.ts +13 -13
- package/src/platforms/whatsapp/commands/chat.test.ts +8 -8
- package/src/platforms/whatsapp/commands/message.test.ts +10 -10
- package/src/platforms/whatsapp/commands/whoami.test.ts +3 -3
- package/src/platforms/whatsapp/credential-manager.test.ts +23 -23
- package/src/platforms/whatsapp/ensure-auth.test.ts +4 -4
- package/src/platforms/whatsapp/index.test.ts +8 -8
- package/src/platforms/whatsapp/types.test.ts +42 -42
- package/src/platforms/whatsappbot/client.test.ts +27 -27
- package/src/platforms/whatsappbot/commands/auth.test.ts +14 -14
- package/src/platforms/whatsappbot/commands/message.test.ts +16 -16
- package/src/platforms/whatsappbot/commands/template.test.ts +9 -9
- package/src/platforms/whatsappbot/commands/whoami.test.ts +5 -5
- package/src/platforms/whatsappbot/credential-manager.test.ts +18 -18
- package/src/platforms/whatsappbot/index.test.ts +7 -7
- package/src/platforms/whatsappbot/types.test.ts +18 -18
- package/src/shared/chromium/browsers.test.ts +22 -22
- package/src/shared/chromium/cookie-reader.test.ts +13 -13
- package/src/shared/chromium/decryptor.test.ts +97 -32
- package/src/shared/chromium/decryptor.ts +27 -6
- package/src/shared/utils/concurrency.test.ts +6 -6
- package/src/shared/utils/derived-key-cache.test.ts +11 -11
- package/src/tui/utils.test.ts +31 -31
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect,
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from 'bun:test'
|
|
2
2
|
|
|
3
3
|
import { DiscordBotClient } from './client'
|
|
4
4
|
import { DiscordBotError } from './types'
|
|
@@ -48,19 +48,19 @@ describe('DiscordBotClient', () => {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
describe('constructor', () => {
|
|
51
|
-
|
|
51
|
+
it('requires token', async () => {
|
|
52
52
|
await expect(new DiscordBotClient().login({ token: '' })).rejects.toThrow(DiscordBotError)
|
|
53
53
|
await expect(new DiscordBotClient().login({ token: '' })).rejects.toThrow('Token is required')
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
it('accepts valid token', async () => {
|
|
57
57
|
const client = await new DiscordBotClient().login({ token: 'bot-test-token' })
|
|
58
58
|
expect(client).toBeInstanceOf(DiscordBotClient)
|
|
59
59
|
})
|
|
60
60
|
})
|
|
61
61
|
|
|
62
62
|
describe('testAuth', () => {
|
|
63
|
-
|
|
63
|
+
it('returns current user and uses Bot auth header', async () => {
|
|
64
64
|
mockResponse({
|
|
65
65
|
id: '123456789',
|
|
66
66
|
username: 'testbot',
|
|
@@ -81,7 +81,7 @@ describe('DiscordBotClient', () => {
|
|
|
81
81
|
expect(headers['User-Agent']).toContain('DiscordBot')
|
|
82
82
|
})
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
it('throws DiscordBotError on API error', async () => {
|
|
85
85
|
mockResponse({ message: 'Unauthorized', code: 401 }, 401)
|
|
86
86
|
|
|
87
87
|
const client = await new DiscordBotClient().login({ token: 'bad-token' })
|
|
@@ -90,7 +90,7 @@ describe('DiscordBotClient', () => {
|
|
|
90
90
|
})
|
|
91
91
|
|
|
92
92
|
describe('listGuilds', () => {
|
|
93
|
-
|
|
93
|
+
it('returns list of guilds', async () => {
|
|
94
94
|
mockResponse([
|
|
95
95
|
{ id: '111', name: 'Guild One' },
|
|
96
96
|
{ id: '222', name: 'Guild Two' },
|
|
@@ -106,7 +106,7 @@ describe('DiscordBotClient', () => {
|
|
|
106
106
|
})
|
|
107
107
|
|
|
108
108
|
describe('getGuild', () => {
|
|
109
|
-
|
|
109
|
+
it('returns guild info', async () => {
|
|
110
110
|
mockResponse({ id: '111', name: 'Test Guild' })
|
|
111
111
|
|
|
112
112
|
const client = await new DiscordBotClient().login({ token: 'bot-token' })
|
|
@@ -119,7 +119,7 @@ describe('DiscordBotClient', () => {
|
|
|
119
119
|
})
|
|
120
120
|
|
|
121
121
|
describe('listChannels', () => {
|
|
122
|
-
|
|
122
|
+
it('returns channels for guild', async () => {
|
|
123
123
|
mockResponse([
|
|
124
124
|
{ id: 'ch1', guild_id: '111', name: 'general', type: 0 },
|
|
125
125
|
{ id: 'ch2', guild_id: '111', name: 'random', type: 0 },
|
|
@@ -135,7 +135,7 @@ describe('DiscordBotClient', () => {
|
|
|
135
135
|
})
|
|
136
136
|
|
|
137
137
|
describe('sendMessage', () => {
|
|
138
|
-
|
|
138
|
+
it('sends message to channel', async () => {
|
|
139
139
|
mockResponse({
|
|
140
140
|
id: 'msg1',
|
|
141
141
|
channel_id: 'ch1',
|
|
@@ -153,7 +153,7 @@ describe('DiscordBotClient', () => {
|
|
|
153
153
|
expect(fetchCalls[0].options?.body).toBe(JSON.stringify({ content: 'Hello world' }))
|
|
154
154
|
})
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
it('includes thread_id when provided', async () => {
|
|
157
157
|
mockResponse({
|
|
158
158
|
id: 'msg1',
|
|
159
159
|
channel_id: 'ch1',
|
|
@@ -170,7 +170,7 @@ describe('DiscordBotClient', () => {
|
|
|
170
170
|
})
|
|
171
171
|
|
|
172
172
|
describe('editMessage', () => {
|
|
173
|
-
|
|
173
|
+
it('edits message with PATCH', async () => {
|
|
174
174
|
mockResponse({
|
|
175
175
|
id: 'msg1',
|
|
176
176
|
channel_id: 'ch1',
|
|
@@ -191,7 +191,7 @@ describe('DiscordBotClient', () => {
|
|
|
191
191
|
})
|
|
192
192
|
|
|
193
193
|
describe('deleteMessage', () => {
|
|
194
|
-
|
|
194
|
+
it('deletes message and returns void', async () => {
|
|
195
195
|
mockResponse(null, 204)
|
|
196
196
|
|
|
197
197
|
const client = await new DiscordBotClient().login({ token: 'bot-token' })
|
|
@@ -204,7 +204,7 @@ describe('DiscordBotClient', () => {
|
|
|
204
204
|
})
|
|
205
205
|
|
|
206
206
|
describe('addReaction', () => {
|
|
207
|
-
|
|
207
|
+
it('adds reaction with encoded emoji', async () => {
|
|
208
208
|
mockResponse(null, 204)
|
|
209
209
|
|
|
210
210
|
const client = await new DiscordBotClient().login({ token: 'bot-token' })
|
|
@@ -218,7 +218,7 @@ describe('DiscordBotClient', () => {
|
|
|
218
218
|
})
|
|
219
219
|
|
|
220
220
|
describe('removeReaction', () => {
|
|
221
|
-
|
|
221
|
+
it('removes reaction with DELETE', async () => {
|
|
222
222
|
mockResponse(null, 204)
|
|
223
223
|
|
|
224
224
|
const client = await new DiscordBotClient().login({ token: 'bot-token' })
|
|
@@ -232,7 +232,7 @@ describe('DiscordBotClient', () => {
|
|
|
232
232
|
})
|
|
233
233
|
|
|
234
234
|
describe('listUsers', () => {
|
|
235
|
-
|
|
235
|
+
it('maps guild members to users', async () => {
|
|
236
236
|
mockResponse([{ user: { id: 'u1', username: 'user1' } }, { user: { id: 'u2', username: 'user2' } }])
|
|
237
237
|
|
|
238
238
|
const client = await new DiscordBotClient().login({ token: 'bot-token' })
|
|
@@ -245,7 +245,7 @@ describe('DiscordBotClient', () => {
|
|
|
245
245
|
})
|
|
246
246
|
|
|
247
247
|
describe('getUser', () => {
|
|
248
|
-
|
|
248
|
+
it('returns user info', async () => {
|
|
249
249
|
mockResponse({ id: 'u1', username: 'testuser' })
|
|
250
250
|
|
|
251
251
|
const client = await new DiscordBotClient().login({ token: 'bot-token' })
|
|
@@ -258,7 +258,7 @@ describe('DiscordBotClient', () => {
|
|
|
258
258
|
})
|
|
259
259
|
|
|
260
260
|
describe('uploadFile', () => {
|
|
261
|
-
|
|
261
|
+
it('uploads file to channel', async () => {
|
|
262
262
|
const { tmpdir } = await import('node:os')
|
|
263
263
|
const { join } = await import('node:path')
|
|
264
264
|
const tempFile = join(tmpdir(), 'test-discordbot-upload.txt')
|
|
@@ -293,7 +293,7 @@ describe('DiscordBotClient', () => {
|
|
|
293
293
|
})
|
|
294
294
|
|
|
295
295
|
describe('listFiles', () => {
|
|
296
|
-
|
|
296
|
+
it('returns files from recent messages', async () => {
|
|
297
297
|
mockResponse([
|
|
298
298
|
{
|
|
299
299
|
id: 'msg1',
|
|
@@ -322,7 +322,7 @@ describe('DiscordBotClient', () => {
|
|
|
322
322
|
})
|
|
323
323
|
|
|
324
324
|
describe('createThread', () => {
|
|
325
|
-
|
|
325
|
+
it('creates thread in channel', async () => {
|
|
326
326
|
mockResponse({
|
|
327
327
|
id: 'thread1',
|
|
328
328
|
guild_id: '111',
|
|
@@ -342,7 +342,7 @@ describe('DiscordBotClient', () => {
|
|
|
342
342
|
})
|
|
343
343
|
|
|
344
344
|
describe('archiveThread', () => {
|
|
345
|
-
|
|
345
|
+
it('archives thread with PATCH', async () => {
|
|
346
346
|
mockResponse({
|
|
347
347
|
id: 'thread1',
|
|
348
348
|
guild_id: '111',
|
|
@@ -361,7 +361,7 @@ describe('DiscordBotClient', () => {
|
|
|
361
361
|
})
|
|
362
362
|
|
|
363
363
|
describe('resolveChannel', () => {
|
|
364
|
-
|
|
364
|
+
it('returns channel ID directly if all digits', async () => {
|
|
365
365
|
const client = await new DiscordBotClient().login({ token: 'bot-token' })
|
|
366
366
|
const id = await client.resolveChannel('111', '123456789')
|
|
367
367
|
|
|
@@ -369,7 +369,7 @@ describe('DiscordBotClient', () => {
|
|
|
369
369
|
expect(fetchCalls.length).toBe(0)
|
|
370
370
|
})
|
|
371
371
|
|
|
372
|
-
|
|
372
|
+
it('looks up channel by name', async () => {
|
|
373
373
|
mockResponse([
|
|
374
374
|
{ id: 'ch1', guild_id: '111', name: 'general', type: 0 },
|
|
375
375
|
{ id: 'ch2', guild_id: '111', name: 'random', type: 0 },
|
|
@@ -381,7 +381,7 @@ describe('DiscordBotClient', () => {
|
|
|
381
381
|
expect(id).toBe('ch2')
|
|
382
382
|
})
|
|
383
383
|
|
|
384
|
-
|
|
384
|
+
it('strips # prefix when looking up by name', async () => {
|
|
385
385
|
mockResponse([{ id: 'ch1', guild_id: '111', name: 'general', type: 0 }])
|
|
386
386
|
|
|
387
387
|
const client = await new DiscordBotClient().login({ token: 'bot-token' })
|
|
@@ -390,7 +390,7 @@ describe('DiscordBotClient', () => {
|
|
|
390
390
|
expect(id).toBe('ch1')
|
|
391
391
|
})
|
|
392
392
|
|
|
393
|
-
|
|
393
|
+
it('throws when channel name not found', async () => {
|
|
394
394
|
mockResponse([{ id: 'ch1', guild_id: '111', name: 'general', type: 0 }])
|
|
395
395
|
|
|
396
396
|
const client = await new DiscordBotClient().login({ token: 'bot-token' })
|
|
@@ -406,7 +406,7 @@ describe('DiscordBotClient', () => {
|
|
|
406
406
|
})
|
|
407
407
|
|
|
408
408
|
describe('rate limiting', () => {
|
|
409
|
-
|
|
409
|
+
it('waits when bucket is exhausted', async () => {
|
|
410
410
|
mockResponse({ id: '1', username: 'bot' }, 200, {
|
|
411
411
|
'X-RateLimit-Remaining': '0',
|
|
412
412
|
'X-RateLimit-Reset': String(Date.now() / 1000 + 0.1),
|
|
@@ -429,7 +429,7 @@ describe('DiscordBotClient', () => {
|
|
|
429
429
|
expect(fetchCalls.length).toBe(2)
|
|
430
430
|
})
|
|
431
431
|
|
|
432
|
-
|
|
432
|
+
it('retries on 429 with Retry-After header', async () => {
|
|
433
433
|
mockResponse({ message: 'Rate limited', retry_after: 0.1 }, 429, { 'Retry-After': '0.1' })
|
|
434
434
|
mockResponse({ id: '123', username: 'bot' })
|
|
435
435
|
|
|
@@ -440,7 +440,7 @@ describe('DiscordBotClient', () => {
|
|
|
440
440
|
expect(fetchCalls.length).toBe(2)
|
|
441
441
|
})
|
|
442
442
|
|
|
443
|
-
|
|
443
|
+
it('handles global rate limit', async () => {
|
|
444
444
|
mockResponse({ message: 'Global rate limited', global: true }, 429, {
|
|
445
445
|
'Retry-After': '0.1',
|
|
446
446
|
'X-RateLimit-Global': 'true',
|
|
@@ -454,7 +454,7 @@ describe('DiscordBotClient', () => {
|
|
|
454
454
|
expect(fetchCalls.length).toBe(2)
|
|
455
455
|
})
|
|
456
456
|
|
|
457
|
-
|
|
457
|
+
it('throws after max retries exceeded', async () => {
|
|
458
458
|
for (let i = 0; i <= 3; i++) {
|
|
459
459
|
mockResponse({ message: 'Rate limited' }, 429, { 'Retry-After': '0.01' })
|
|
460
460
|
}
|
|
@@ -466,7 +466,7 @@ describe('DiscordBotClient', () => {
|
|
|
466
466
|
})
|
|
467
467
|
|
|
468
468
|
describe('retry logic', () => {
|
|
469
|
-
|
|
469
|
+
it('retries on 500 server error', async () => {
|
|
470
470
|
mockResponse({ message: 'Internal Server Error' }, 500)
|
|
471
471
|
mockResponse({ id: '123', username: 'bot' })
|
|
472
472
|
|
|
@@ -477,7 +477,7 @@ describe('DiscordBotClient', () => {
|
|
|
477
477
|
expect(fetchCalls.length).toBe(2)
|
|
478
478
|
})
|
|
479
479
|
|
|
480
|
-
|
|
480
|
+
it('does not retry on 4xx client errors (except 429)', async () => {
|
|
481
481
|
mockResponse({ message: 'Not Found' }, 404)
|
|
482
482
|
|
|
483
483
|
const client = await new DiscordBotClient().login({ token: 'bot-token' })
|
|
@@ -485,7 +485,7 @@ describe('DiscordBotClient', () => {
|
|
|
485
485
|
expect(fetchCalls.length).toBe(1)
|
|
486
486
|
})
|
|
487
487
|
|
|
488
|
-
|
|
488
|
+
it('exponential backoff increases delay', async () => {
|
|
489
489
|
mockResponse({ message: 'Error' }, 500)
|
|
490
490
|
mockResponse({ message: 'Error' }, 500)
|
|
491
491
|
mockResponse({ id: '123', username: 'bot' })
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, mock,
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, mock, it } from 'bun:test'
|
|
2
2
|
import { existsSync, rmSync } from 'node:fs'
|
|
3
3
|
import { mkdir } from 'node:fs/promises'
|
|
4
4
|
import { tmpdir } from 'node:os'
|
|
@@ -55,7 +55,7 @@ describe('auth commands', () => {
|
|
|
55
55
|
})
|
|
56
56
|
|
|
57
57
|
describe('setAction', () => {
|
|
58
|
-
|
|
58
|
+
it('validates and stores bot token with default bot_id from auth', async () => {
|
|
59
59
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
60
60
|
|
|
61
61
|
const result = await setAction('token123', { _credManager: manager })
|
|
@@ -71,7 +71,7 @@ describe('auth commands', () => {
|
|
|
71
71
|
expect(creds?.bot_id).toBe('bot123')
|
|
72
72
|
})
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
it('uses --bot flag as bot_id', async () => {
|
|
75
75
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
76
76
|
|
|
77
77
|
const result = await setAction('token123', { bot: 'mybot', _credManager: manager })
|
|
@@ -81,7 +81,7 @@ describe('auth commands', () => {
|
|
|
81
81
|
expect(creds?.token).toBe('token123')
|
|
82
82
|
})
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
it('rejects user tokens (bot: false)', async () => {
|
|
85
85
|
mockTestAuth.mockImplementationOnce(() =>
|
|
86
86
|
Promise.resolve({
|
|
87
87
|
id: 'user123',
|
|
@@ -98,7 +98,7 @@ describe('auth commands', () => {
|
|
|
98
98
|
expect(result.error).toContain('not a bot token')
|
|
99
99
|
})
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
it('rejects user tokens (bot: undefined)', async () => {
|
|
102
102
|
mockTestAuth.mockImplementationOnce(() =>
|
|
103
103
|
Promise.resolve({
|
|
104
104
|
id: 'user123',
|
|
@@ -114,7 +114,7 @@ describe('auth commands', () => {
|
|
|
114
114
|
expect(result.error).toContain('not a bot token')
|
|
115
115
|
})
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
it('handles client errors', async () => {
|
|
118
118
|
mockTestAuth.mockImplementationOnce(() => Promise.reject(new Error('Invalid token')))
|
|
119
119
|
|
|
120
120
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
@@ -127,7 +127,7 @@ describe('auth commands', () => {
|
|
|
127
127
|
})
|
|
128
128
|
|
|
129
129
|
describe('clearAction', () => {
|
|
130
|
-
|
|
130
|
+
it('removes all stored credentials', async () => {
|
|
131
131
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
132
132
|
await manager.setCredentials({
|
|
133
133
|
token: 'token123',
|
|
@@ -143,7 +143,7 @@ describe('auth commands', () => {
|
|
|
143
143
|
})
|
|
144
144
|
|
|
145
145
|
describe('statusAction', () => {
|
|
146
|
-
|
|
146
|
+
it('returns no credentials when none set', async () => {
|
|
147
147
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
148
148
|
|
|
149
149
|
const result = await statusAction({ _credManager: manager })
|
|
@@ -152,7 +152,7 @@ describe('auth commands', () => {
|
|
|
152
152
|
expect(result.error).toBeDefined()
|
|
153
153
|
})
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
it('returns valid status for current bot', async () => {
|
|
156
156
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
157
157
|
await manager.setCredentials({
|
|
158
158
|
token: 'token123',
|
|
@@ -169,7 +169,7 @@ describe('auth commands', () => {
|
|
|
169
169
|
expect(result.bot_name).toBe('testbot')
|
|
170
170
|
})
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
it('returns status for specific --bot', async () => {
|
|
173
173
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
174
174
|
await manager.setCredentials({
|
|
175
175
|
token: 'token1',
|
|
@@ -188,7 +188,7 @@ describe('auth commands', () => {
|
|
|
188
188
|
expect(result.bot_id).toBe('bot123')
|
|
189
189
|
})
|
|
190
190
|
|
|
191
|
-
|
|
191
|
+
it('returns invalid when token test fails', async () => {
|
|
192
192
|
mockTestAuth.mockImplementationOnce(() => Promise.reject(new Error('Unauthorized')))
|
|
193
193
|
|
|
194
194
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
@@ -203,7 +203,7 @@ describe('auth commands', () => {
|
|
|
203
203
|
expect(result.valid).toBe(false)
|
|
204
204
|
})
|
|
205
205
|
|
|
206
|
-
|
|
206
|
+
it('returns invalid when bot field is false', async () => {
|
|
207
207
|
mockTestAuth.mockImplementationOnce(() =>
|
|
208
208
|
Promise.resolve({
|
|
209
209
|
id: 'user123',
|
|
@@ -226,7 +226,7 @@ describe('auth commands', () => {
|
|
|
226
226
|
})
|
|
227
227
|
|
|
228
228
|
describe('listAction', () => {
|
|
229
|
-
|
|
229
|
+
it('returns all stored bots', async () => {
|
|
230
230
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
231
231
|
await manager.setCredentials({
|
|
232
232
|
token: 'token1',
|
|
@@ -245,7 +245,7 @@ describe('auth commands', () => {
|
|
|
245
245
|
expect(result.bots?.find((b) => b.bot_id === 'bot2')?.is_current).toBe(true)
|
|
246
246
|
})
|
|
247
247
|
|
|
248
|
-
|
|
248
|
+
it('returns empty list when no bots stored', async () => {
|
|
249
249
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
250
250
|
|
|
251
251
|
const result = await listAction({ _credManager: manager })
|
|
@@ -255,7 +255,7 @@ describe('auth commands', () => {
|
|
|
255
255
|
})
|
|
256
256
|
|
|
257
257
|
describe('useAction', () => {
|
|
258
|
-
|
|
258
|
+
it('switches current bot', async () => {
|
|
259
259
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
260
260
|
await manager.setCredentials({
|
|
261
261
|
token: 'token1',
|
|
@@ -274,7 +274,7 @@ describe('auth commands', () => {
|
|
|
274
274
|
expect(result.bot_id).toBe('bot1')
|
|
275
275
|
})
|
|
276
276
|
|
|
277
|
-
|
|
277
|
+
it('returns error for unknown bot', async () => {
|
|
278
278
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
279
279
|
|
|
280
280
|
const result = await useAction('nonexistent', { _credManager: manager })
|
|
@@ -284,7 +284,7 @@ describe('auth commands', () => {
|
|
|
284
284
|
})
|
|
285
285
|
|
|
286
286
|
describe('removeAction', () => {
|
|
287
|
-
|
|
287
|
+
it('removes a stored bot', async () => {
|
|
288
288
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
289
289
|
await manager.setCredentials({
|
|
290
290
|
token: 'token1',
|
|
@@ -298,7 +298,7 @@ describe('auth commands', () => {
|
|
|
298
298
|
expect(await manager.getCredentials('bot1')).toBeNull()
|
|
299
299
|
})
|
|
300
300
|
|
|
301
|
-
|
|
301
|
+
it('returns error for unknown bot', async () => {
|
|
302
302
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
303
303
|
|
|
304
304
|
const result = await removeAction('nonexistent', { _credManager: manager })
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, mock,
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, mock, it } from 'bun:test'
|
|
2
2
|
import { existsSync, rmSync } from 'node:fs'
|
|
3
3
|
import { mkdir } from 'node:fs/promises'
|
|
4
4
|
import { tmpdir } from 'node:os'
|
|
@@ -66,7 +66,7 @@ describe('channel commands', () => {
|
|
|
66
66
|
})
|
|
67
67
|
|
|
68
68
|
describe('listAction', () => {
|
|
69
|
-
|
|
69
|
+
it('lists text channels from current server', async () => {
|
|
70
70
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
71
71
|
await manager.setCredentials({
|
|
72
72
|
token: 'token123',
|
|
@@ -90,7 +90,7 @@ describe('channel commands', () => {
|
|
|
90
90
|
})
|
|
91
91
|
})
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
it('filters out non-text channels', async () => {
|
|
94
94
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
95
95
|
await manager.setCredentials({
|
|
96
96
|
token: 'token123',
|
|
@@ -105,7 +105,7 @@ describe('channel commands', () => {
|
|
|
105
105
|
expect(hasVoiceChannel).toBe(false)
|
|
106
106
|
})
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
it('returns error when no server set', async () => {
|
|
109
109
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
110
110
|
await manager.setCredentials({
|
|
111
111
|
token: 'token123',
|
|
@@ -119,7 +119,7 @@ describe('channel commands', () => {
|
|
|
119
119
|
expect(result.error).toContain('No server set')
|
|
120
120
|
})
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
it('handles client errors', async () => {
|
|
123
123
|
mockListChannels.mockImplementationOnce(() => Promise.reject(new Error('API Error')))
|
|
124
124
|
|
|
125
125
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
@@ -138,7 +138,7 @@ describe('channel commands', () => {
|
|
|
138
138
|
})
|
|
139
139
|
|
|
140
140
|
describe('infoAction', () => {
|
|
141
|
-
|
|
141
|
+
it('returns channel info by ID', async () => {
|
|
142
142
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
143
143
|
await manager.setCredentials({
|
|
144
144
|
token: 'token123',
|
|
@@ -156,7 +156,7 @@ describe('channel commands', () => {
|
|
|
156
156
|
expect(result.guild_id).toBe('guild1')
|
|
157
157
|
})
|
|
158
158
|
|
|
159
|
-
|
|
159
|
+
it('resolves channel by name', async () => {
|
|
160
160
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
161
161
|
await manager.setCredentials({
|
|
162
162
|
token: 'token123',
|
|
@@ -171,7 +171,7 @@ describe('channel commands', () => {
|
|
|
171
171
|
expect(result.name).toBe('general')
|
|
172
172
|
})
|
|
173
173
|
|
|
174
|
-
|
|
174
|
+
it('resolves channel by name with hash prefix', async () => {
|
|
175
175
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
176
176
|
await manager.setCredentials({
|
|
177
177
|
token: 'token123',
|
|
@@ -186,7 +186,7 @@ describe('channel commands', () => {
|
|
|
186
186
|
expect(result.name).toBe('announcements')
|
|
187
187
|
})
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
it('returns error for nonexistent channel', async () => {
|
|
190
190
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
191
191
|
await manager.setCredentials({
|
|
192
192
|
token: 'token123',
|
|
@@ -201,7 +201,7 @@ describe('channel commands', () => {
|
|
|
201
201
|
expect(result.error).toContain('Channel not found')
|
|
202
202
|
})
|
|
203
203
|
|
|
204
|
-
|
|
204
|
+
it('returns error when no server set', async () => {
|
|
205
205
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
206
206
|
await manager.setCredentials({
|
|
207
207
|
token: 'token123',
|
|
@@ -215,7 +215,7 @@ describe('channel commands', () => {
|
|
|
215
215
|
expect(result.error).toContain('No server set')
|
|
216
216
|
})
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
it('handles client errors', async () => {
|
|
219
219
|
mockGetChannel.mockImplementationOnce(() => Promise.reject(new Error('Channel not found')))
|
|
220
220
|
|
|
221
221
|
const manager = new DiscordBotCredentialManager(tempDir)
|
|
@@ -71,7 +71,7 @@ describe('file commands', () => {
|
|
|
71
71
|
})
|
|
72
72
|
|
|
73
73
|
describe('uploadAction', () => {
|
|
74
|
-
it('
|
|
74
|
+
it('uploads file successfully', async () => {
|
|
75
75
|
const result = await uploadAction('general', './test.txt', {
|
|
76
76
|
...options,
|
|
77
77
|
_credManager: mockCredManager,
|
|
@@ -80,12 +80,12 @@ describe('file commands', () => {
|
|
|
80
80
|
expect(result).toBeDefined()
|
|
81
81
|
})
|
|
82
82
|
|
|
83
|
-
it('
|
|
83
|
+
it('returns error when channel resolution fails', async () => {
|
|
84
84
|
const result = await uploadAction('nonexistent', './test.txt', options)
|
|
85
85
|
expect(result.error).toBeDefined()
|
|
86
86
|
})
|
|
87
87
|
|
|
88
|
-
it('
|
|
88
|
+
it('returns error when file does not exist', async () => {
|
|
89
89
|
const result = await uploadAction('general', '/nonexistent/file.txt', {
|
|
90
90
|
...options,
|
|
91
91
|
_credManager: mockCredManager,
|
|
@@ -95,7 +95,7 @@ describe('file commands', () => {
|
|
|
95
95
|
})
|
|
96
96
|
|
|
97
97
|
describe('listAction', () => {
|
|
98
|
-
it('
|
|
98
|
+
it('lists files successfully', async () => {
|
|
99
99
|
const result = await listAction('general', {
|
|
100
100
|
...options,
|
|
101
101
|
_credManager: mockCredManager,
|
|
@@ -104,14 +104,14 @@ describe('file commands', () => {
|
|
|
104
104
|
expect(result).toBeDefined()
|
|
105
105
|
})
|
|
106
106
|
|
|
107
|
-
it('
|
|
107
|
+
it('returns error when channel resolution fails', async () => {
|
|
108
108
|
const result = await listAction('nonexistent', options)
|
|
109
109
|
expect(result.error).toBeDefined()
|
|
110
110
|
})
|
|
111
111
|
})
|
|
112
112
|
|
|
113
113
|
describe('action result structure', () => {
|
|
114
|
-
it('
|
|
114
|
+
it('returns success result with file info for uploadAction', async () => {
|
|
115
115
|
const result = await uploadAction('general', './test.txt', {
|
|
116
116
|
...options,
|
|
117
117
|
_credManager: mockCredManager,
|
|
@@ -129,7 +129,7 @@ describe('file commands', () => {
|
|
|
129
129
|
}
|
|
130
130
|
})
|
|
131
131
|
|
|
132
|
-
it('
|
|
132
|
+
it('returns success result with files array for listAction', async () => {
|
|
133
133
|
const result = await listAction('general', {
|
|
134
134
|
...options,
|
|
135
135
|
_credManager: mockCredManager,
|