agent-messenger 2.10.0 → 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 +15 -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 +219 -145
- package/src/platforms/teams/token-extractor.ts +13 -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 * as jose from 'node-jose'
|
|
4
4
|
|
|
@@ -50,17 +50,17 @@ describe('WebexClient', () => {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
describe('login', () => {
|
|
53
|
-
|
|
53
|
+
it('accepts valid token', async () => {
|
|
54
54
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
55
55
|
expect(client).toBeInstanceOf(WebexClient)
|
|
56
56
|
})
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
it('throws on empty token', async () => {
|
|
59
59
|
await expect(new WebexClient().login({ token: '' })).rejects.toThrow(WebexError)
|
|
60
60
|
await expect(new WebexClient().login({ token: '' })).rejects.toThrow('Token is required')
|
|
61
61
|
})
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
it('accepts deviceUrl and tokenType', async () => {
|
|
64
64
|
const client = await new WebexClient().login({
|
|
65
65
|
token: 'test-token',
|
|
66
66
|
deviceUrl: 'https://wdm-r.wbx2.com/wdm/api/v1/devices/dev-1',
|
|
@@ -73,7 +73,7 @@ describe('WebexClient', () => {
|
|
|
73
73
|
})
|
|
74
74
|
|
|
75
75
|
describe('testAuth', () => {
|
|
76
|
-
|
|
76
|
+
it('calls GET /people/me and returns person', async () => {
|
|
77
77
|
mockResponse({
|
|
78
78
|
id: 'user-123',
|
|
79
79
|
displayName: 'Test User',
|
|
@@ -92,14 +92,14 @@ describe('WebexClient', () => {
|
|
|
92
92
|
})
|
|
93
93
|
})
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
it('throws WebexError on API error', async () => {
|
|
96
96
|
mockResponse({ message: 'Unauthorized' }, 401)
|
|
97
97
|
|
|
98
98
|
const client = await new WebexClient().login({ token: 'bad-token' })
|
|
99
99
|
await expect(client.testAuth()).rejects.toThrow(WebexError)
|
|
100
100
|
})
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
it('falls back to internal API when public API fails for extracted tokens', async () => {
|
|
103
103
|
// given - public API rejects, internal API succeeds
|
|
104
104
|
mockResponse({ message: 'Unauthorized' }, 401)
|
|
105
105
|
fetchResponses.push(
|
|
@@ -125,7 +125,7 @@ describe('WebexClient', () => {
|
|
|
125
125
|
expect(person).toBeTruthy()
|
|
126
126
|
})
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
it('throws when both public and internal APIs fail for extracted tokens', async () => {
|
|
129
129
|
// given - both APIs reject
|
|
130
130
|
mockResponse({ message: 'Unauthorized' }, 401)
|
|
131
131
|
fetchResponses.push(
|
|
@@ -144,7 +144,7 @@ describe('WebexClient', () => {
|
|
|
144
144
|
await expect(client.testAuth()).rejects.toThrow(WebexError)
|
|
145
145
|
})
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
it('does not use internal API fallback for non-extracted tokens', async () => {
|
|
148
148
|
mockResponse({ message: 'Unauthorized' }, 401)
|
|
149
149
|
|
|
150
150
|
const client = await new WebexClient().login({ token: 'bad-token' })
|
|
@@ -154,7 +154,7 @@ describe('WebexClient', () => {
|
|
|
154
154
|
})
|
|
155
155
|
|
|
156
156
|
describe('listSpaces', () => {
|
|
157
|
-
|
|
157
|
+
it('returns unwrapped items array', async () => {
|
|
158
158
|
mockResponse({
|
|
159
159
|
items: [
|
|
160
160
|
{ id: 'room1', title: 'Room One', type: 'group' },
|
|
@@ -170,7 +170,7 @@ describe('WebexClient', () => {
|
|
|
170
170
|
expect(spaces[1].title).toBe('Room Two')
|
|
171
171
|
})
|
|
172
172
|
|
|
173
|
-
|
|
173
|
+
it('includes default max=50 query param', async () => {
|
|
174
174
|
mockResponse({ items: [] })
|
|
175
175
|
|
|
176
176
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -179,7 +179,7 @@ describe('WebexClient', () => {
|
|
|
179
179
|
expect(fetchCalls[0].url).toContain('max=50')
|
|
180
180
|
})
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
it('passes type and max query params', async () => {
|
|
183
183
|
mockResponse({ items: [] })
|
|
184
184
|
|
|
185
185
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -192,7 +192,7 @@ describe('WebexClient', () => {
|
|
|
192
192
|
})
|
|
193
193
|
|
|
194
194
|
describe('getSpace', () => {
|
|
195
|
-
|
|
195
|
+
it('calls GET /rooms/{spaceId}', async () => {
|
|
196
196
|
mockResponse({ id: 'room1', title: 'Test Room', type: 'group' })
|
|
197
197
|
|
|
198
198
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -204,7 +204,7 @@ describe('WebexClient', () => {
|
|
|
204
204
|
})
|
|
205
205
|
|
|
206
206
|
describe('sendMessage', () => {
|
|
207
|
-
|
|
207
|
+
it('posts text message to room', async () => {
|
|
208
208
|
mockResponse({ id: 'msg1', roomId: 'room1', text: 'Hello world' })
|
|
209
209
|
|
|
210
210
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -216,7 +216,7 @@ describe('WebexClient', () => {
|
|
|
216
216
|
expect(fetchCalls[0].options?.body).toBe(JSON.stringify({ roomId: 'room1', text: 'Hello world' }))
|
|
217
217
|
})
|
|
218
218
|
|
|
219
|
-
|
|
219
|
+
it('sends markdown message when option set', async () => {
|
|
220
220
|
mockResponse({ id: 'msg1', roomId: 'room1', markdown: '**bold**' })
|
|
221
221
|
|
|
222
222
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -227,7 +227,7 @@ describe('WebexClient', () => {
|
|
|
227
227
|
})
|
|
228
228
|
|
|
229
229
|
describe('sendDirectMessage', () => {
|
|
230
|
-
|
|
230
|
+
it('posts message with toPersonEmail', async () => {
|
|
231
231
|
mockResponse({ id: 'msg1', toPersonEmail: 'user@example.com', text: 'Hello' })
|
|
232
232
|
|
|
233
233
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -236,7 +236,7 @@ describe('WebexClient', () => {
|
|
|
236
236
|
expect(fetchCalls[0].options?.body).toBe(JSON.stringify({ toPersonEmail: 'user@example.com', text: 'Hello' }))
|
|
237
237
|
})
|
|
238
238
|
|
|
239
|
-
|
|
239
|
+
it('sends markdown direct message when option set', async () => {
|
|
240
240
|
mockResponse({ id: 'msg1', toPersonEmail: 'user@example.com' })
|
|
241
241
|
|
|
242
242
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -249,7 +249,7 @@ describe('WebexClient', () => {
|
|
|
249
249
|
})
|
|
250
250
|
|
|
251
251
|
describe('listMessages', () => {
|
|
252
|
-
|
|
252
|
+
it('includes roomId query param and unwraps items', async () => {
|
|
253
253
|
mockResponse({
|
|
254
254
|
items: [
|
|
255
255
|
{ id: 'msg1', roomId: 'room1', text: 'Message 1' },
|
|
@@ -266,7 +266,7 @@ describe('WebexClient', () => {
|
|
|
266
266
|
expect(fetchCalls[0].url).toContain('max=50')
|
|
267
267
|
})
|
|
268
268
|
|
|
269
|
-
|
|
269
|
+
it('passes custom max', async () => {
|
|
270
270
|
mockResponse({ items: [] })
|
|
271
271
|
|
|
272
272
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -277,7 +277,7 @@ describe('WebexClient', () => {
|
|
|
277
277
|
})
|
|
278
278
|
|
|
279
279
|
describe('getMessage', () => {
|
|
280
|
-
|
|
280
|
+
it('calls GET /messages/{messageId}', async () => {
|
|
281
281
|
mockResponse({ id: 'msg1', roomId: 'room1', text: 'Hello' })
|
|
282
282
|
|
|
283
283
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -289,7 +289,7 @@ describe('WebexClient', () => {
|
|
|
289
289
|
})
|
|
290
290
|
|
|
291
291
|
describe('deleteMessage', () => {
|
|
292
|
-
|
|
292
|
+
it('calls DELETE /messages/{messageId} and handles 204', async () => {
|
|
293
293
|
mockResponse(null, 204)
|
|
294
294
|
|
|
295
295
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -301,7 +301,7 @@ describe('WebexClient', () => {
|
|
|
301
301
|
})
|
|
302
302
|
|
|
303
303
|
describe('editMessage', () => {
|
|
304
|
-
|
|
304
|
+
it('calls PUT /messages/{messageId} with roomId and text', async () => {
|
|
305
305
|
mockResponse({ id: 'msg1', roomId: 'room1', text: 'Edited text' })
|
|
306
306
|
|
|
307
307
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -312,7 +312,7 @@ describe('WebexClient', () => {
|
|
|
312
312
|
expect(fetchCalls[0].options?.body).toBe(JSON.stringify({ roomId: 'room1', text: 'Edited text' }))
|
|
313
313
|
})
|
|
314
314
|
|
|
315
|
-
|
|
315
|
+
it('sends markdown when option set', async () => {
|
|
316
316
|
mockResponse({ id: 'msg1', roomId: 'room1', markdown: '**edited**' })
|
|
317
317
|
|
|
318
318
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -323,7 +323,7 @@ describe('WebexClient', () => {
|
|
|
323
323
|
})
|
|
324
324
|
|
|
325
325
|
describe('listPeople', () => {
|
|
326
|
-
|
|
326
|
+
it('returns unwrapped items', async () => {
|
|
327
327
|
mockResponse({
|
|
328
328
|
items: [
|
|
329
329
|
{ id: 'u1', displayName: 'User One', emails: ['user1@example.com'] },
|
|
@@ -338,7 +338,7 @@ describe('WebexClient', () => {
|
|
|
338
338
|
expect(people[0].displayName).toBe('User One')
|
|
339
339
|
})
|
|
340
340
|
|
|
341
|
-
|
|
341
|
+
it('passes email, displayName, max query params', async () => {
|
|
342
342
|
mockResponse({ items: [] })
|
|
343
343
|
|
|
344
344
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -351,7 +351,7 @@ describe('WebexClient', () => {
|
|
|
351
351
|
})
|
|
352
352
|
|
|
353
353
|
describe('listMemberships', () => {
|
|
354
|
-
|
|
354
|
+
it('includes roomId and returns unwrapped items', async () => {
|
|
355
355
|
mockResponse({
|
|
356
356
|
items: [
|
|
357
357
|
{ id: 'm1', roomId: 'room1', personEmail: 'user1@example.com', isModerator: false },
|
|
@@ -367,7 +367,7 @@ describe('WebexClient', () => {
|
|
|
367
367
|
expect(fetchCalls[0].url).toContain('roomId=room1')
|
|
368
368
|
})
|
|
369
369
|
|
|
370
|
-
|
|
370
|
+
it('passes max query param', async () => {
|
|
371
371
|
mockResponse({ items: [] })
|
|
372
372
|
|
|
373
373
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -378,7 +378,7 @@ describe('WebexClient', () => {
|
|
|
378
378
|
})
|
|
379
379
|
|
|
380
380
|
describe('rate limiting', () => {
|
|
381
|
-
|
|
381
|
+
it('retries on 429 with Retry-After header', async () => {
|
|
382
382
|
mockResponse({ message: 'Rate limited' }, 429, { 'Retry-After': '0.1' })
|
|
383
383
|
mockResponse({
|
|
384
384
|
id: 'user-123',
|
|
@@ -393,7 +393,7 @@ describe('WebexClient', () => {
|
|
|
393
393
|
expect(fetchCalls.length).toBe(2)
|
|
394
394
|
})
|
|
395
395
|
|
|
396
|
-
|
|
396
|
+
it('throws after max retries exceeded on 429', async () => {
|
|
397
397
|
for (let i = 0; i <= MAX_RETRIES; i++) {
|
|
398
398
|
mockResponse({ message: 'Rate limited' }, 429, { 'Retry-After': '0.01' })
|
|
399
399
|
}
|
|
@@ -405,7 +405,7 @@ describe('WebexClient', () => {
|
|
|
405
405
|
})
|
|
406
406
|
|
|
407
407
|
describe('server errors', () => {
|
|
408
|
-
|
|
408
|
+
it('retries on 500 with exponential backoff', async () => {
|
|
409
409
|
mockResponse({ message: 'Internal Server Error' }, 500)
|
|
410
410
|
mockResponse({
|
|
411
411
|
id: 'user-123',
|
|
@@ -420,7 +420,7 @@ describe('WebexClient', () => {
|
|
|
420
420
|
expect(fetchCalls.length).toBe(2)
|
|
421
421
|
})
|
|
422
422
|
|
|
423
|
-
|
|
423
|
+
it('does not retry on 4xx errors except 429', async () => {
|
|
424
424
|
mockResponse({ message: 'Not Found' }, 404)
|
|
425
425
|
|
|
426
426
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -428,7 +428,7 @@ describe('WebexClient', () => {
|
|
|
428
428
|
expect(fetchCalls.length).toBe(1)
|
|
429
429
|
})
|
|
430
430
|
|
|
431
|
-
|
|
431
|
+
it('backoff increases with multiple retries', async () => {
|
|
432
432
|
mockResponse({ message: 'Error' }, 500)
|
|
433
433
|
mockResponse({ message: 'Error' }, 500)
|
|
434
434
|
mockResponse({
|
|
@@ -477,7 +477,7 @@ describe('WebexClient', () => {
|
|
|
477
477
|
}
|
|
478
478
|
|
|
479
479
|
describe('sendMessage', () => {
|
|
480
|
-
|
|
480
|
+
it('posts activity to /activities with POST method', async () => {
|
|
481
481
|
mockResponse(mockActivity('Hello world'))
|
|
482
482
|
|
|
483
483
|
const client = await createExtractedClient()
|
|
@@ -487,7 +487,7 @@ describe('WebexClient', () => {
|
|
|
487
487
|
expect(fetchCalls[0].options?.method).toBe('POST')
|
|
488
488
|
})
|
|
489
489
|
|
|
490
|
-
|
|
490
|
+
it('body has verb, object type, and displayName (no content for plain text)', async () => {
|
|
491
491
|
mockResponse(mockActivity('Hello world'))
|
|
492
492
|
|
|
493
493
|
const client = await createExtractedClient()
|
|
@@ -500,7 +500,7 @@ describe('WebexClient', () => {
|
|
|
500
500
|
expect(body.object.content).toBeUndefined()
|
|
501
501
|
})
|
|
502
502
|
|
|
503
|
-
|
|
503
|
+
it('body has target with decoded conv UUID and conversation type', async () => {
|
|
504
504
|
mockResponse(mockActivity('Hello world'))
|
|
505
505
|
|
|
506
506
|
const client = await createExtractedClient()
|
|
@@ -511,7 +511,7 @@ describe('WebexClient', () => {
|
|
|
511
511
|
expect(body.target.objectType).toBe('conversation')
|
|
512
512
|
})
|
|
513
513
|
|
|
514
|
-
|
|
514
|
+
it('body has clientTempId starting with tmp-', async () => {
|
|
515
515
|
mockResponse(mockActivity('Hello world'))
|
|
516
516
|
|
|
517
517
|
const client = await createExtractedClient()
|
|
@@ -521,7 +521,7 @@ describe('WebexClient', () => {
|
|
|
521
521
|
expect(body.clientTempId).toStartWith('tmp-')
|
|
522
522
|
})
|
|
523
523
|
|
|
524
|
-
|
|
524
|
+
it('includes cisco-device-url header', async () => {
|
|
525
525
|
mockResponse(mockActivity('Hello world'))
|
|
526
526
|
|
|
527
527
|
const client = await createExtractedClient()
|
|
@@ -532,7 +532,7 @@ describe('WebexClient', () => {
|
|
|
532
532
|
})
|
|
533
533
|
})
|
|
534
534
|
|
|
535
|
-
|
|
535
|
+
it('returns WebexMessage mapped from activity response', async () => {
|
|
536
536
|
mockResponse(mockActivity('Hello world'))
|
|
537
537
|
|
|
538
538
|
const client = await createExtractedClient()
|
|
@@ -544,7 +544,7 @@ describe('WebexClient', () => {
|
|
|
544
544
|
expect(message.created).toBe('2026-01-01T00:00:00.000Z')
|
|
545
545
|
})
|
|
546
546
|
|
|
547
|
-
|
|
547
|
+
it('markdown option converts content to HTML and strips displayName', async () => {
|
|
548
548
|
mockResponse(mockActivity('bold text'))
|
|
549
549
|
|
|
550
550
|
const client = await createExtractedClient()
|
|
@@ -556,7 +556,7 @@ describe('WebexClient', () => {
|
|
|
556
556
|
expect(body.object.markdown).toBeUndefined()
|
|
557
557
|
})
|
|
558
558
|
|
|
559
|
-
|
|
559
|
+
it('plain text messages omit content field', async () => {
|
|
560
560
|
mockResponse(mockActivity('Hello world'))
|
|
561
561
|
|
|
562
562
|
const client = await createExtractedClient()
|
|
@@ -569,7 +569,7 @@ describe('WebexClient', () => {
|
|
|
569
569
|
})
|
|
570
570
|
|
|
571
571
|
describe('listMessages', () => {
|
|
572
|
-
|
|
572
|
+
it('calls GET on conversations endpoint with activitiesLimit and participantsLimit', async () => {
|
|
573
573
|
mockResponse(mockConversation([mockActivity('Hello')]))
|
|
574
574
|
|
|
575
575
|
const client = await createExtractedClient()
|
|
@@ -580,7 +580,7 @@ describe('WebexClient', () => {
|
|
|
580
580
|
)
|
|
581
581
|
})
|
|
582
582
|
|
|
583
|
-
|
|
583
|
+
it('filters activities to only those with verb post', async () => {
|
|
584
584
|
mockResponse(
|
|
585
585
|
mockConversation([
|
|
586
586
|
mockActivity('Hello'),
|
|
@@ -597,7 +597,7 @@ describe('WebexClient', () => {
|
|
|
597
597
|
expect(messages[1].text).toBe('World')
|
|
598
598
|
})
|
|
599
599
|
|
|
600
|
-
|
|
600
|
+
it('maps each activity to WebexMessage format', async () => {
|
|
601
601
|
mockResponse(mockConversation([mockActivity('Hello')]))
|
|
602
602
|
|
|
603
603
|
const client = await createExtractedClient()
|
|
@@ -609,7 +609,7 @@ describe('WebexClient', () => {
|
|
|
609
609
|
expect(messages[0].created).toBe('2026-01-01T00:00:00.000Z')
|
|
610
610
|
})
|
|
611
611
|
|
|
612
|
-
|
|
612
|
+
it('passes custom max to activitiesLimit', async () => {
|
|
613
613
|
mockResponse(mockConversation([]))
|
|
614
614
|
|
|
615
615
|
const client = await createExtractedClient()
|
|
@@ -618,7 +618,7 @@ describe('WebexClient', () => {
|
|
|
618
618
|
expect(fetchCalls[0].url).toContain('activitiesLimit=25')
|
|
619
619
|
})
|
|
620
620
|
|
|
621
|
-
|
|
621
|
+
it('includes cisco-device-url header', async () => {
|
|
622
622
|
mockResponse(mockConversation([]))
|
|
623
623
|
|
|
624
624
|
const client = await createExtractedClient()
|
|
@@ -631,7 +631,7 @@ describe('WebexClient', () => {
|
|
|
631
631
|
})
|
|
632
632
|
|
|
633
633
|
describe('getMessage', () => {
|
|
634
|
-
|
|
634
|
+
it('calls GET on activities endpoint', async () => {
|
|
635
635
|
mockResponse(mockActivity('Hello'))
|
|
636
636
|
|
|
637
637
|
const client = await createExtractedClient()
|
|
@@ -640,7 +640,7 @@ describe('WebexClient', () => {
|
|
|
640
640
|
expect(fetchCalls[0].url).toBe(`${CONV_BASE}/activities/activity-123`)
|
|
641
641
|
})
|
|
642
642
|
|
|
643
|
-
|
|
643
|
+
it('maps activity to WebexMessage format', async () => {
|
|
644
644
|
mockResponse(mockActivity('Hello'))
|
|
645
645
|
|
|
646
646
|
const client = await createExtractedClient()
|
|
@@ -653,7 +653,7 @@ describe('WebexClient', () => {
|
|
|
653
653
|
})
|
|
654
654
|
|
|
655
655
|
describe('deleteMessage', () => {
|
|
656
|
-
|
|
656
|
+
it('first GETs the activity then POSTs a delete activity', async () => {
|
|
657
657
|
mockResponse(mockActivity('Hello'))
|
|
658
658
|
mockResponse({})
|
|
659
659
|
|
|
@@ -665,7 +665,7 @@ describe('WebexClient', () => {
|
|
|
665
665
|
expect(fetchCalls[1].options?.method).toBe('POST')
|
|
666
666
|
})
|
|
667
667
|
|
|
668
|
-
|
|
668
|
+
it('delete activity body has correct verb, object, and target', async () => {
|
|
669
669
|
mockResponse(mockActivity('Hello'))
|
|
670
670
|
mockResponse({})
|
|
671
671
|
|
|
@@ -679,7 +679,7 @@ describe('WebexClient', () => {
|
|
|
679
679
|
expect(body.target.id).toBe(TEST_CONV_UUID)
|
|
680
680
|
})
|
|
681
681
|
|
|
682
|
-
|
|
682
|
+
it('throws WebexError when activity has no target', async () => {
|
|
683
683
|
mockResponse({ ...mockActivity('Hello'), target: undefined })
|
|
684
684
|
|
|
685
685
|
const client = await createExtractedClient()
|
|
@@ -691,7 +691,7 @@ describe('WebexClient', () => {
|
|
|
691
691
|
const mockEditActivity = (text: string, parentId = 'activity-123') =>
|
|
692
692
|
mockActivity(text, { parent: { id: parentId, type: 'edit' } })
|
|
693
693
|
|
|
694
|
-
|
|
694
|
+
it('posts activity with verb post and parent edit reference', async () => {
|
|
695
695
|
mockResponse(mockEditActivity('Edited text'))
|
|
696
696
|
|
|
697
697
|
const client = await createExtractedClient()
|
|
@@ -702,7 +702,7 @@ describe('WebexClient', () => {
|
|
|
702
702
|
expect(body.parent).toEqual({ id: 'activity-123', type: 'edit' })
|
|
703
703
|
})
|
|
704
704
|
|
|
705
|
-
|
|
705
|
+
it('plain text edit populates both displayName and content to avoid auto-tombstone', async () => {
|
|
706
706
|
mockResponse(mockEditActivity('Edited text'))
|
|
707
707
|
|
|
708
708
|
const client = await createExtractedClient()
|
|
@@ -714,7 +714,7 @@ describe('WebexClient', () => {
|
|
|
714
714
|
expect(body.object.content).toBe('Edited text')
|
|
715
715
|
})
|
|
716
716
|
|
|
717
|
-
|
|
717
|
+
it('clientTempId uses -edit suffix to match Webex web client format', async () => {
|
|
718
718
|
mockResponse(mockEditActivity('Edited text'))
|
|
719
719
|
|
|
720
720
|
const client = await createExtractedClient()
|
|
@@ -724,7 +724,7 @@ describe('WebexClient', () => {
|
|
|
724
724
|
expect(body.clientTempId).toMatch(/^tmp-\d+-edit$/)
|
|
725
725
|
})
|
|
726
726
|
|
|
727
|
-
|
|
727
|
+
it('target has decoded conv UUID', async () => {
|
|
728
728
|
mockResponse(mockEditActivity('Edited text'))
|
|
729
729
|
|
|
730
730
|
const client = await createExtractedClient()
|
|
@@ -734,7 +734,7 @@ describe('WebexClient', () => {
|
|
|
734
734
|
expect(body.target.id).toBe(TEST_CONV_UUID)
|
|
735
735
|
})
|
|
736
736
|
|
|
737
|
-
|
|
737
|
+
it('markdown option converts content to HTML and strips displayName', async () => {
|
|
738
738
|
mockResponse(mockEditActivity('italic text'))
|
|
739
739
|
|
|
740
740
|
const client = await createExtractedClient()
|
|
@@ -746,7 +746,7 @@ describe('WebexClient', () => {
|
|
|
746
746
|
expect(body.object.markdown).toBeUndefined()
|
|
747
747
|
})
|
|
748
748
|
|
|
749
|
-
|
|
749
|
+
it('tolerates responses that omit parent (minimal success shape)', async () => {
|
|
750
750
|
mockResponse(mockActivity('Edited text'))
|
|
751
751
|
|
|
752
752
|
const client = await createExtractedClient()
|
|
@@ -754,7 +754,7 @@ describe('WebexClient', () => {
|
|
|
754
754
|
expect(message.id).toBe('activity-123')
|
|
755
755
|
})
|
|
756
756
|
|
|
757
|
-
|
|
757
|
+
it('throws when server returns activity linked to a different parent', async () => {
|
|
758
758
|
mockResponse(mockEditActivity('Edited text', 'activity-999'))
|
|
759
759
|
|
|
760
760
|
const client = await createExtractedClient()
|
|
@@ -781,7 +781,7 @@ describe('WebexClient', () => {
|
|
|
781
781
|
return client
|
|
782
782
|
}
|
|
783
783
|
|
|
784
|
-
|
|
784
|
+
it('plain text send omits content field on encrypted path (preserves prior fix)', async () => {
|
|
785
785
|
mockResponse({ id: TEST_CONV_UUID, defaultActivityEncryptionKeyUrl: TEST_KEY_URI })
|
|
786
786
|
mockResponse(mockActivity('Hello world'))
|
|
787
787
|
|
|
@@ -794,7 +794,7 @@ describe('WebexClient', () => {
|
|
|
794
794
|
expect(body.encryptionKeyUrl).toBe(TEST_KEY_URI)
|
|
795
795
|
})
|
|
796
796
|
|
|
797
|
-
|
|
797
|
+
it('plain text edit encrypts both displayName and content with kid in JWE header', async () => {
|
|
798
798
|
mockResponse({ id: TEST_CONV_UUID, defaultActivityEncryptionKeyUrl: TEST_KEY_URI })
|
|
799
799
|
mockResponse(mockActivity('Edited text', { parent: { id: 'activity-123', type: 'edit' } }))
|
|
800
800
|
|
|
@@ -811,7 +811,7 @@ describe('WebexClient', () => {
|
|
|
811
811
|
})
|
|
812
812
|
|
|
813
813
|
describe('sendDirectMessage', () => {
|
|
814
|
-
|
|
814
|
+
it('calls public rooms and memberships API to find room, then sends via internal API', async () => {
|
|
815
815
|
mockResponse({ items: [{ id: TEST_ROOM_ID, title: 'DM', type: 'direct' }] })
|
|
816
816
|
mockResponse({
|
|
817
817
|
items: [{ id: 'm1', roomId: TEST_ROOM_ID, personEmail: 'target@example.com', isModerator: false }],
|
|
@@ -827,7 +827,7 @@ describe('WebexClient', () => {
|
|
|
827
827
|
expect(message.id).toBe('activity-123')
|
|
828
828
|
})
|
|
829
829
|
|
|
830
|
-
|
|
830
|
+
it('throws WebexError when no existing direct conversation found', async () => {
|
|
831
831
|
mockResponse({ items: [{ id: 'room-x', title: 'DM', type: 'direct' }] })
|
|
832
832
|
mockResponse({
|
|
833
833
|
items: [{ id: 'm1', roomId: 'room-x', personEmail: 'other@example.com', isModerator: false }],
|
|
@@ -839,7 +839,7 @@ describe('WebexClient', () => {
|
|
|
839
839
|
})
|
|
840
840
|
|
|
841
841
|
describe('error handling', () => {
|
|
842
|
-
|
|
842
|
+
it('throws WebexError when internal API returns non-OK response', async () => {
|
|
843
843
|
fetchResponses.push(
|
|
844
844
|
new Response(JSON.stringify({ message: 'Activity not found' }), {
|
|
845
845
|
status: 404,
|
|
@@ -851,7 +851,7 @@ describe('WebexClient', () => {
|
|
|
851
851
|
await expect(client.getMessage('bad-activity')).rejects.toThrow(WebexError)
|
|
852
852
|
})
|
|
853
853
|
|
|
854
|
-
|
|
854
|
+
it('error message extracted from internal API response body', async () => {
|
|
855
855
|
fetchResponses.push(
|
|
856
856
|
new Response(JSON.stringify({ message: 'Activity not found' }), {
|
|
857
857
|
status: 404,
|
|
@@ -874,7 +874,7 @@ describe('WebexClient', () => {
|
|
|
874
874
|
})
|
|
875
875
|
|
|
876
876
|
describe('error handling', () => {
|
|
877
|
-
|
|
877
|
+
it('throws WebexError with parsed message from response body', async () => {
|
|
878
878
|
mockResponse({ message: 'The requested resource could not be found.', trackingId: 'abc' }, 404)
|
|
879
879
|
|
|
880
880
|
const client = await new WebexClient().login({ token: 'test-token' })
|
|
@@ -889,7 +889,7 @@ describe('WebexClient', () => {
|
|
|
889
889
|
expect(error?.message).toBe('The requested resource could not be found.')
|
|
890
890
|
})
|
|
891
891
|
|
|
892
|
-
|
|
892
|
+
it('falls back to HTTP status message when no body', async () => {
|
|
893
893
|
fetchResponses.push(
|
|
894
894
|
new Response(null, {
|
|
895
895
|
status: 403,
|