agent-messenger 2.22.0 → 2.23.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 (102) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +21 -0
  3. package/dist/package.json +1 -1
  4. package/dist/src/platforms/webex/client.d.ts +6 -0
  5. package/dist/src/platforms/webex/client.d.ts.map +1 -1
  6. package/dist/src/platforms/webex/client.js +34 -4
  7. package/dist/src/platforms/webex/client.js.map +1 -1
  8. package/dist/src/platforms/webex/commands/auth.d.ts +9 -1
  9. package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
  10. package/dist/src/platforms/webex/commands/auth.js +141 -25
  11. package/dist/src/platforms/webex/commands/auth.js.map +1 -1
  12. package/dist/src/platforms/webex/credential-manager.d.ts.map +1 -1
  13. package/dist/src/platforms/webex/credential-manager.js +8 -4
  14. package/dist/src/platforms/webex/credential-manager.js.map +1 -1
  15. package/dist/src/platforms/webex/id-normalizer.d.ts +19 -0
  16. package/dist/src/platforms/webex/id-normalizer.d.ts.map +1 -0
  17. package/dist/src/platforms/webex/id-normalizer.js +60 -0
  18. package/dist/src/platforms/webex/id-normalizer.js.map +1 -0
  19. package/dist/src/platforms/webex/index.d.ts +4 -0
  20. package/dist/src/platforms/webex/index.d.ts.map +1 -1
  21. package/dist/src/platforms/webex/index.js +2 -0
  22. package/dist/src/platforms/webex/index.js.map +1 -1
  23. package/dist/src/platforms/webex/listener.d.ts +61 -0
  24. package/dist/src/platforms/webex/listener.d.ts.map +1 -0
  25. package/dist/src/platforms/webex/listener.js +222 -0
  26. package/dist/src/platforms/webex/listener.js.map +1 -0
  27. package/dist/src/platforms/webex/password-login.d.ts +18 -0
  28. package/dist/src/platforms/webex/password-login.d.ts.map +1 -0
  29. package/dist/src/platforms/webex/password-login.js +259 -0
  30. package/dist/src/platforms/webex/password-login.js.map +1 -0
  31. package/dist/src/platforms/webex/types.d.ts +2 -1
  32. package/dist/src/platforms/webex/types.d.ts.map +1 -1
  33. package/dist/src/platforms/webex/types.js +1 -1
  34. package/dist/src/platforms/webex/types.js.map +1 -1
  35. package/dist/src/platforms/webex/wdm-discovery.d.ts.map +1 -0
  36. package/dist/src/platforms/{webexbot → webex}/wdm-discovery.js +3 -3
  37. package/dist/src/platforms/webex/wdm-discovery.js.map +1 -0
  38. package/dist/src/platforms/webexbot/client.d.ts +4 -0
  39. package/dist/src/platforms/webexbot/client.d.ts.map +1 -1
  40. package/dist/src/platforms/webexbot/client.js +70 -8
  41. package/dist/src/platforms/webexbot/client.js.map +1 -1
  42. package/dist/src/platforms/webexbot/index.d.ts +2 -0
  43. package/dist/src/platforms/webexbot/index.d.ts.map +1 -1
  44. package/dist/src/platforms/webexbot/index.js +1 -0
  45. package/dist/src/platforms/webexbot/index.js.map +1 -1
  46. package/dist/src/platforms/webexbot/listener.d.ts +3 -41
  47. package/dist/src/platforms/webexbot/listener.d.ts.map +1 -1
  48. package/dist/src/platforms/webexbot/listener.js +13 -208
  49. package/dist/src/platforms/webexbot/listener.js.map +1 -1
  50. package/dist/src/platforms/webexbot/types.d.ts +1 -18
  51. package/dist/src/platforms/webexbot/types.d.ts.map +1 -1
  52. package/dist/src/platforms/webexbot/types.js.map +1 -1
  53. package/docs/content/docs/cli/webex.mdx +38 -12
  54. package/docs/content/docs/sdk/webexbot.mdx +16 -0
  55. package/package.json +1 -1
  56. package/skills/agent-channeltalk/SKILL.md +1 -1
  57. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  58. package/skills/agent-discord/SKILL.md +1 -1
  59. package/skills/agent-discordbot/SKILL.md +1 -1
  60. package/skills/agent-instagram/SKILL.md +1 -1
  61. package/skills/agent-kakaotalk/SKILL.md +1 -1
  62. package/skills/agent-line/SKILL.md +1 -1
  63. package/skills/agent-slack/SKILL.md +1 -1
  64. package/skills/agent-slackbot/SKILL.md +1 -1
  65. package/skills/agent-teams/SKILL.md +1 -1
  66. package/skills/agent-telegram/SKILL.md +1 -1
  67. package/skills/agent-telegrambot/SKILL.md +1 -1
  68. package/skills/agent-webex/SKILL.md +76 -22
  69. package/skills/agent-webex/references/authentication.md +55 -14
  70. package/skills/agent-webex/references/common-patterns.md +5 -2
  71. package/skills/agent-webexbot/SKILL.md +3 -1
  72. package/skills/agent-wechatbot/SKILL.md +1 -1
  73. package/skills/agent-whatsapp/SKILL.md +1 -1
  74. package/skills/agent-whatsappbot/SKILL.md +1 -1
  75. package/src/platforms/webex/cli.test.ts +31 -1
  76. package/src/platforms/webex/client.test.ts +57 -0
  77. package/src/platforms/webex/client.ts +39 -4
  78. package/src/platforms/webex/commands/auth.test.ts +189 -28
  79. package/src/platforms/webex/commands/auth.ts +194 -35
  80. package/src/platforms/webex/credential-manager.test.ts +40 -0
  81. package/src/platforms/webex/credential-manager.ts +7 -4
  82. package/src/platforms/webex/id-normalizer.test.ts +207 -0
  83. package/src/platforms/webex/id-normalizer.ts +76 -0
  84. package/src/platforms/webex/index.test.ts +6 -0
  85. package/src/platforms/webex/index.ts +4 -0
  86. package/src/platforms/webex/listener.test.ts +243 -0
  87. package/src/platforms/webex/listener.ts +285 -0
  88. package/src/platforms/webex/password-login.test.ts +193 -0
  89. package/src/platforms/webex/password-login.ts +332 -0
  90. package/src/platforms/webex/types.test.ts +16 -0
  91. package/src/platforms/webex/types.ts +2 -2
  92. package/src/platforms/{webexbot → webex}/wdm-discovery.ts +3 -3
  93. package/src/platforms/webexbot/client.test.ts +125 -1
  94. package/src/platforms/webexbot/client.ts +79 -8
  95. package/src/platforms/webexbot/index.ts +2 -0
  96. package/src/platforms/webexbot/listener.test.ts +37 -224
  97. package/src/platforms/webexbot/listener.ts +18 -250
  98. package/src/platforms/webexbot/types.ts +2 -23
  99. package/dist/src/platforms/webexbot/wdm-discovery.d.ts.map +0 -1
  100. package/dist/src/platforms/webexbot/wdm-discovery.js.map +0 -1
  101. /package/dist/src/platforms/{webexbot → webex}/wdm-discovery.d.ts +0 -0
  102. /package/src/platforms/{webexbot → webex}/wdm-discovery.test.ts +0 -0
@@ -1,5 +1,7 @@
1
1
  export { WebexBotClient } from './client'
2
2
  export { WebexBotCredentialManager } from './credential-manager'
3
+ export { fromRestId, toRestId } from '../webex/id-normalizer'
4
+ export type { WebexRestIdType } from '../webex/id-normalizer'
3
5
  export { WebexBotListener } from './listener'
4
6
  export type { WebexBotListenerOptions } from './listener'
5
7
  export type { WebexBotConfig, WebexBotCredentials, WebexBotEntry, WebexBotListenerEventMap } from './types'
@@ -1,234 +1,47 @@
1
1
  import { describe, expect, it, mock } from 'bun:test'
2
- import { EventEmitter } from 'events'
3
-
4
- import type {
5
- DecryptedMessage,
6
- HandlerStatus,
7
- MercuryActivity,
8
- WebexMessageHandlerConfig,
9
- WebexMessageHandlerEvents,
10
- } from 'webex-message-handler'
11
2
 
3
+ import { WebexListener } from '../webex/listener'
12
4
  import { WebexBotListener } from './listener'
13
5
 
14
- const STATUS: HandlerStatus = {
15
- status: 'connected',
16
- webSocketOpen: true,
17
- kmsInitialized: true,
18
- deviceRegistered: true,
19
- reconnectAttempt: 0,
20
- }
21
-
22
- const RAW_ACTIVITY: MercuryActivity = {
23
- id: 'activity-123',
24
- verb: 'post',
25
- actor: { id: 'person-123', objectType: 'person', emailAddress: 'user@example.com' },
26
- object: { id: 'object-123', objectType: 'comment', displayName: 'hello' },
27
- target: { id: 'room-123', objectType: 'conversation' },
28
- published: '2024-01-01T00:00:00Z',
29
- }
30
-
31
- const MESSAGE: DecryptedMessage = {
32
- id: 'message-123',
33
- roomId: 'room-123',
34
- personId: 'person-123',
35
- personEmail: 'user@example.com',
36
- text: 'hello',
37
- created: '2024-01-01T00:00:00Z',
38
- mentionedPeople: [],
39
- mentionedGroups: [],
40
- files: [],
41
- raw: RAW_ACTIVITY,
42
- }
43
-
44
- class FakeWebexMessageHandler extends EventEmitter {
45
- connect = mock(() => Promise.resolve())
46
- disconnect = mock(() => Promise.resolve())
47
- connected = true
48
-
49
- status(): HandlerStatus {
50
- return STATUS
51
- }
52
-
53
- override on<K extends keyof WebexMessageHandlerEvents>(event: K, listener: WebexMessageHandlerEvents[K]): this {
54
- return super.on(event, listener)
55
- }
56
-
57
- override off<K extends keyof WebexMessageHandlerEvents>(event: K, listener: WebexMessageHandlerEvents[K]): this {
58
- return super.off(event, listener)
59
- }
60
-
61
- override once<K extends keyof WebexMessageHandlerEvents>(event: K, listener: WebexMessageHandlerEvents[K]): this {
62
- return super.once(event, listener)
6
+ const httpError = (): Response => new Response('', { status: 500 })
7
+ const missingWdm = (): Response =>
8
+ new Response(JSON.stringify({ serviceLinks: {} }), { status: 200, headers: { 'Content-Type': 'application/json' } })
9
+
10
+ async function withFetch(makeResponse: () => Response, run: () => Promise<void>): Promise<void> {
11
+ const original = globalThis.fetch
12
+ globalThis.fetch = mock(() => Promise.resolve(makeResponse())) as typeof fetch
13
+ try {
14
+ await run()
15
+ } finally {
16
+ globalThis.fetch = original
63
17
  }
64
18
  }
65
19
 
66
20
  describe('WebexBotListener', () => {
67
- it('bridges handler message events and webex_event', async () => {
68
- const handler = new FakeWebexMessageHandler()
69
- const client = { getToken: () => 'token123' }
70
- const listener = new WebexBotListener(client, {
71
- _handlerFactory: (_config: WebexMessageHandlerConfig) => handler,
72
- })
73
- const messageCreated = mock((_event: DecryptedMessage) => undefined)
74
- const webexEvent = mock((_event: DecryptedMessage) => undefined)
75
- listener.on('message_created', messageCreated)
76
- listener.on('webex_event', webexEvent)
77
-
78
- await listener.start()
79
- handler.emit('message:created', MESSAGE)
80
-
81
- expect(messageCreated).toHaveBeenCalledWith(MESSAGE)
82
- expect(webexEvent).toHaveBeenCalledWith(MESSAGE)
83
- })
84
-
85
- it('stop calls handler disconnect', async () => {
86
- const handler = new FakeWebexMessageHandler()
87
- const client = { getToken: () => 'token123' }
88
- const listener = new WebexBotListener(client, {
89
- _handlerFactory: (_config: WebexMessageHandlerConfig) => handler,
90
- })
91
-
92
- await listener.start()
93
- await listener.stop()
94
-
95
- expect(handler.disconnect).toHaveBeenCalled()
96
- })
97
-
98
- it('start is idempotent', async () => {
99
- const handler = new FakeWebexMessageHandler()
100
- const client = { getToken: () => 'token123' }
101
- const listener = new WebexBotListener(client, {
102
- _handlerFactory: (_config: WebexMessageHandlerConfig) => handler,
103
- })
104
-
105
- await listener.start()
106
- await listener.start()
107
-
108
- expect(handler.connect).toHaveBeenCalledTimes(1)
109
- })
110
-
111
- it('start rethrows and resets state when connect fails, allowing retry', async () => {
112
- const failing = new FakeWebexMessageHandler()
113
- failing.connect = mock(() => Promise.reject(new Error('device registration failed')))
114
- const ok = new FakeWebexMessageHandler()
115
- const handlers = [failing, ok]
116
- const client = { getToken: () => 'token123' }
117
- const listener = new WebexBotListener(client, {
118
- _handlerFactory: (_config: WebexMessageHandlerConfig) => handlers.shift()!,
119
- })
120
-
121
- await expect(listener.start()).rejects.toThrow('device registration failed')
122
- expect(failing.disconnect).toHaveBeenCalled()
123
-
124
- await listener.start()
125
- expect(ok.connect).toHaveBeenCalledTimes(1)
126
- })
127
-
128
- it('does not throw when handler emits error with no error listener', async () => {
129
- const handler = new FakeWebexMessageHandler()
130
- const client = { getToken: () => 'token123' }
131
- const listener = new WebexBotListener(client, {
132
- _handlerFactory: (_config: WebexMessageHandlerConfig) => handler,
133
- })
134
- listener.on('message_created', () => undefined)
135
-
136
- await listener.start()
137
-
138
- expect(() => handler.emit('error', new Error('boom'))).not.toThrow()
139
- })
140
-
141
- it('ignores stale handler events after stop', async () => {
142
- const handler = new FakeWebexMessageHandler()
143
- const client = { getToken: () => 'token123' }
144
- const listener = new WebexBotListener(client, {
145
- _handlerFactory: (_config: WebexMessageHandlerConfig) => handler,
146
- })
147
- const messageCreated = mock((_event: DecryptedMessage) => undefined)
148
- listener.on('message_created', messageCreated)
149
-
150
- await listener.start()
151
- await listener.stop()
152
- handler.emit('message:created', MESSAGE)
153
-
154
- expect(messageCreated).not.toHaveBeenCalled()
155
- })
156
-
157
- it('start-stop-start does not cross-talk between handlers', async () => {
158
- const first = new FakeWebexMessageHandler()
159
- const second = new FakeWebexMessageHandler()
160
- const handlers = [first, second]
161
- const client = { getToken: () => 'token123' }
162
- const listener = new WebexBotListener(client, {
163
- _handlerFactory: (_config: WebexMessageHandlerConfig) => handlers.shift()!,
164
- })
165
- const messageCreated = mock((_event: DecryptedMessage) => undefined)
166
- listener.on('message_created', messageCreated)
167
-
168
- await listener.start()
169
- await listener.stop()
170
- await listener.start()
171
-
172
- first.emit('message:created', MESSAGE)
173
- expect(messageCreated).not.toHaveBeenCalled()
174
-
175
- second.emit('message:created', MESSAGE)
176
- expect(messageCreated).toHaveBeenCalledTimes(1)
177
- })
178
-
179
- it('preserves disconnected reason', async () => {
180
- const handler = new FakeWebexMessageHandler()
181
- const client = { getToken: () => 'token123' }
182
- const listener = new WebexBotListener(client, {
183
- _handlerFactory: (_config: WebexMessageHandlerConfig) => handler,
184
- })
185
- const disconnected = mock((_reason: string) => undefined)
186
- listener.on('disconnected', disconnected)
187
-
188
- await listener.start()
189
- handler.emit('disconnected', 'network lost')
190
-
191
- expect(disconnected).toHaveBeenCalledWith('network lost')
192
- })
193
-
194
- it('concurrent start() calls share the same connect failure', async () => {
195
- const handler = new FakeWebexMessageHandler()
196
- handler.connect = mock(() => Promise.reject(new Error('connect failed')))
197
- const client = { getToken: () => 'token123' }
198
- const listener = new WebexBotListener(client, {
199
- _handlerFactory: (_config: WebexMessageHandlerConfig) => handler,
200
- })
201
-
202
- const first = listener.start()
203
- const second = listener.start()
204
- const firstResult = first.then(
205
- () => 'ok',
206
- (e: Error) => e.message,
207
- )
208
- const secondResult = second.then(
209
- () => 'ok',
210
- (e: Error) => e.message,
211
- )
212
-
213
- expect(await firstResult).toBe('connect failed')
214
- expect(await secondResult).toBe('connect failed')
215
- expect(handler.connect).toHaveBeenCalledTimes(1)
216
- })
217
-
218
- it('disconnects a handler whose connect resolves after stop', async () => {
219
- const handler = new FakeWebexMessageHandler()
220
- let resolveConnect: () => void = () => undefined
221
- handler.connect = mock(() => new Promise<void>((resolve) => (resolveConnect = resolve)))
222
- const client = { getToken: () => 'token123' }
223
- const listener = new WebexBotListener(client, {
224
- _handlerFactory: (_config: WebexMessageHandlerConfig) => handler,
21
+ it('is a WebexListener', () => {
22
+ expect(new WebexBotListener({ getToken: () => 'token' })).toBeInstanceOf(WebexListener)
23
+ })
24
+
25
+ for (const [label, makeResponse] of [
26
+ ['HTTP error', httpError],
27
+ ['missing serviceLinks.wdm', missingWdm],
28
+ ] as const) {
29
+ it(`surfaces WDM discovery failures (${label}) as WebexBotError`, async () => {
30
+ await withFetch(makeResponse, async () => {
31
+ await expect(new WebexBotListener({ getToken: () => 'token' }).start()).rejects.toMatchObject({
32
+ name: 'WebexBotError',
33
+ code: 'wdm_discovery_failed',
34
+ })
35
+ })
36
+ })
37
+
38
+ it(`WebexListener surfaces WDM discovery failures (${label}) as WebexError`, async () => {
39
+ await withFetch(makeResponse, async () => {
40
+ await expect(new WebexListener({ getToken: () => 'token' }).start()).rejects.toMatchObject({
41
+ name: 'WebexError',
42
+ code: 'wdm_discovery_failed',
43
+ })
44
+ })
225
45
  })
226
-
227
- const starting = listener.start()
228
- const stopping = listener.stop()
229
- resolveConnect()
230
- await Promise.all([starting, stopping])
231
-
232
- expect(handler.disconnect).toHaveBeenCalled()
233
- })
46
+ }
234
47
  })
@@ -1,255 +1,23 @@
1
- import { EventEmitter } from 'events'
2
-
3
- import { WebexMessageHandler } from 'webex-message-handler'
4
- import type {
5
- AttachmentAction,
6
- DecryptedMessage,
7
- DeletedMessage,
8
- HandlerStatus,
9
- InjectedWebSocket,
10
- MembershipActivity,
11
- RoomActivity,
12
- WebexMessageHandlerConfig,
13
- WebexMessageHandlerEvents,
14
- } from 'webex-message-handler'
15
- import WebSocket from 'ws'
16
-
17
- import type { WebexBotClient } from './client'
18
- import type { WebexBotListenerEventMap } from './types'
19
- import { createWdmRewriteFetch, discoverWdmDevicesUrl } from './wdm-discovery'
20
-
21
- type EventKey = keyof WebexBotListenerEventMap
22
- type WebexBotClientLike = Pick<WebexBotClient, 'getToken'>
23
-
24
- interface WebexMessageHandlerLike {
25
- connect(): Promise<void>
26
- disconnect(): Promise<void>
27
- status(): HandlerStatus
28
- get connected(): boolean
29
- on<K extends keyof WebexMessageHandlerEvents>(event: K, listener: WebexMessageHandlerEvents[K]): this
30
- off<K extends keyof WebexMessageHandlerEvents>(event: K, listener: WebexMessageHandlerEvents[K]): this
31
- once<K extends keyof WebexMessageHandlerEvents>(event: K, listener: WebexMessageHandlerEvents[K]): this
32
- }
33
-
34
- export interface WebexBotListenerOptions {
35
- ignoreSelfMessages?: boolean
36
- pingInterval?: number
37
- pongTimeout?: number
38
- reconnectBackoffMax?: number
39
- maxReconnectAttempts?: number
40
- _handlerFactory?: (config: WebexMessageHandlerConfig) => WebexMessageHandlerLike
41
- }
42
-
43
- export class WebexBotListener {
44
- private client: WebexBotClientLike
45
- private options: WebexBotListenerOptions
46
- private running = false
47
- private emitter = new EventEmitter()
48
- private handler: WebexMessageHandlerLike | null = null
49
- private generation = 0
50
- private detachHandler: (() => void) | null = null
51
- private startPromise: Promise<void> | null = null
52
-
53
- constructor(client: WebexBotClientLike, options: WebexBotListenerOptions = {}) {
54
- this.client = client
55
- this.options = options
56
- }
57
-
1
+ import { WebexListener } from '../webex/listener'
2
+ import { WebexError } from '../webex/types'
3
+ import { WebexBotError } from './types'
4
+
5
+ export type {
6
+ WebexListenerClient as WebexBotListenerClient,
7
+ WebexListenerOptions as WebexBotListenerOptions,
8
+ } from '../webex/listener'
9
+
10
+ export class WebexBotListener extends WebexListener {
11
+ // Preserve the bot error contract: WDM discovery (shared with the user platform)
12
+ // throws WebexError, but existing bot callers catch WebexBotError.
58
13
  async start(): Promise<void> {
59
- if (this.startPromise) return this.startPromise
60
- if (this.running) return
61
-
62
- this.running = true
63
- const generation = ++this.generation
64
-
65
- let startPromise!: Promise<void>
66
- startPromise = (async () => {
67
- let handler: WebexMessageHandlerLike | null = null
68
- try {
69
- handler = await this.createHandler()
70
-
71
- if (!this.running || this.generation !== generation) {
72
- await handler.disconnect().catch(() => undefined)
73
- return
74
- }
75
- this.handler = handler
76
- this.detachHandler = this.wireHandler(handler, generation)
77
-
78
- await handler.connect()
79
-
80
- if (!this.running || this.handler !== handler || this.generation !== generation) {
81
- await handler.disconnect().catch(() => undefined)
82
- return
83
- }
84
- } catch (error) {
85
- if (this.handler === handler && this.generation === generation) {
86
- this.detachHandler?.()
87
- this.detachHandler = null
88
- this.handler = null
89
- }
90
- if (this.generation === generation) {
91
- this.running = false
92
- }
93
- await handler?.disconnect().catch(() => undefined)
94
- throw error
95
- } finally {
96
- if (this.startPromise === startPromise) {
97
- this.startPromise = null
98
- }
14
+ try {
15
+ await super.start()
16
+ } catch (error) {
17
+ if (error instanceof WebexError) {
18
+ throw new WebexBotError(error.message, error.code)
99
19
  }
100
- })()
101
-
102
- this.startPromise = startPromise
103
- return startPromise
104
- }
105
-
106
- async stop(): Promise<void> {
107
- const pendingStart = this.startPromise
108
- this.startPromise = null
109
-
110
- this.running = false
111
- this.generation++
112
-
113
- const detach = this.detachHandler
114
- this.detachHandler = null
115
- detach?.()
116
-
117
- const handler = this.handler
118
- this.handler = null
119
- if (handler) {
120
- await handler.disconnect().catch(() => undefined)
121
- }
122
-
123
- if (pendingStart) {
124
- await pendingStart.catch(() => undefined)
125
- }
126
- }
127
-
128
- on<K extends EventKey>(event: K, listener: (...args: WebexBotListenerEventMap[K]) => void): this {
129
- this.emitter.on(event, listener as (...args: any[]) => void)
130
- return this
131
- }
132
-
133
- off<K extends EventKey>(event: K, listener: (...args: WebexBotListenerEventMap[K]) => void): this {
134
- this.emitter.off(event, listener as (...args: any[]) => void)
135
- return this
136
- }
137
-
138
- once<K extends EventKey>(event: K, listener: (...args: WebexBotListenerEventMap[K]) => void): this {
139
- this.emitter.once(event, listener as (...args: any[]) => void)
140
- return this
141
- }
142
-
143
- private isCurrent(handler: WebexMessageHandlerLike, generation: number): boolean {
144
- return this.running && this.handler === handler && this.generation === generation
145
- }
146
-
147
- // Node's EventEmitter throws synchronously if an 'error' event is emitted with
148
- // no registered listener. Guard it so SDK consumers that only subscribe to
149
- // message events are never crashed by a transient connection error.
150
- private emitError(error: Error): void {
151
- if (this.emitter.listenerCount('error') > 0) {
152
- this.emitter.emit('error', error)
153
- }
154
- }
155
-
156
- private async createHandler(): Promise<WebexMessageHandlerLike> {
157
- const token = this.client.getToken()
158
- const config: WebexMessageHandlerConfig = { token }
159
- if (this.options.ignoreSelfMessages !== undefined) config.ignoreSelfMessages = this.options.ignoreSelfMessages
160
- if (this.options.pingInterval !== undefined) config.pingInterval = this.options.pingInterval
161
- if (this.options.pongTimeout !== undefined) config.pongTimeout = this.options.pongTimeout
162
- if (this.options.reconnectBackoffMax !== undefined) config.reconnectBackoffMax = this.options.reconnectBackoffMax
163
- if (this.options.maxReconnectAttempts !== undefined) config.maxReconnectAttempts = this.options.maxReconnectAttempts
164
-
165
- if (this.options._handlerFactory) {
166
- return this.options._handlerFactory(config)
167
- }
168
-
169
- const wdmDevicesUrl = await discoverWdmDevicesUrl(token)
170
- config.mode = 'injected'
171
- config.fetch = createWdmRewriteFetch(wdmDevicesUrl)
172
- config.webSocketFactory = (url: string) => new WebSocket(url) as unknown as InjectedWebSocket
173
- return new WebexMessageHandler(config)
174
- }
175
-
176
- private wireHandler(handler: WebexMessageHandlerLike, generation: number): () => void {
177
- const onMessageCreated = (event: DecryptedMessage) => {
178
- if (!this.isCurrent(handler, generation)) return
179
- this.emitter.emit('message_created', event)
180
- this.emitter.emit('webex_event', event)
181
- }
182
- const onMessageUpdated = (event: DecryptedMessage) => {
183
- if (!this.isCurrent(handler, generation)) return
184
- this.emitter.emit('message_updated', event)
185
- this.emitter.emit('webex_event', event)
186
- }
187
- const onMessageDeleted = (event: DeletedMessage) => {
188
- if (!this.isCurrent(handler, generation)) return
189
- this.emitter.emit('message_deleted', event)
190
- this.emitter.emit('webex_event', event)
191
- }
192
- const onMembershipCreated = (event: MembershipActivity) => {
193
- if (!this.isCurrent(handler, generation)) return
194
- this.emitter.emit('membership_created', event)
195
- this.emitter.emit('webex_event', event)
196
- }
197
- const onAttachmentAction = (event: AttachmentAction) => {
198
- if (!this.isCurrent(handler, generation)) return
199
- this.emitter.emit('attachment_action', event)
200
- this.emitter.emit('webex_event', event)
201
- }
202
- const onRoomCreated = (event: RoomActivity) => {
203
- if (!this.isCurrent(handler, generation)) return
204
- this.emitter.emit('room_created', event)
205
- this.emitter.emit('webex_event', event)
206
- }
207
- const onRoomUpdated = (event: RoomActivity) => {
208
- if (!this.isCurrent(handler, generation)) return
209
- this.emitter.emit('room_updated', event)
210
- this.emitter.emit('webex_event', event)
211
- }
212
- const onConnected = () => {
213
- if (!this.isCurrent(handler, generation)) return
214
- this.emitter.emit('connected', { connected: handler.connected, status: handler.status() })
215
- }
216
- const onReconnecting = (attempt: number) => {
217
- if (!this.isCurrent(handler, generation)) return
218
- this.emitter.emit('reconnecting', attempt)
219
- }
220
- const onDisconnected = (reason: string) => {
221
- if (!this.isCurrent(handler, generation)) return
222
- this.emitter.emit('disconnected', reason)
223
- }
224
- const onError = (error: Error) => {
225
- if (!this.isCurrent(handler, generation)) return
226
- this.emitError(error)
227
- }
228
-
229
- handler.on('message:created', onMessageCreated)
230
- handler.on('message:updated', onMessageUpdated)
231
- handler.on('message:deleted', onMessageDeleted)
232
- handler.on('membership:created', onMembershipCreated)
233
- handler.on('attachmentAction:created', onAttachmentAction)
234
- handler.on('room:created', onRoomCreated)
235
- handler.on('room:updated', onRoomUpdated)
236
- handler.on('connected', onConnected)
237
- handler.on('reconnecting', onReconnecting)
238
- handler.on('disconnected', onDisconnected)
239
- handler.on('error', onError)
240
-
241
- return () => {
242
- handler.off('message:created', onMessageCreated)
243
- handler.off('message:updated', onMessageUpdated)
244
- handler.off('message:deleted', onMessageDeleted)
245
- handler.off('membership:created', onMembershipCreated)
246
- handler.off('attachmentAction:created', onAttachmentAction)
247
- handler.off('room:created', onRoomCreated)
248
- handler.off('room:updated', onRoomUpdated)
249
- handler.off('connected', onConnected)
250
- handler.off('reconnecting', onReconnecting)
251
- handler.off('disconnected', onDisconnected)
252
- handler.off('error', onError)
20
+ throw error
253
21
  }
254
22
  }
255
23
  }
@@ -1,13 +1,7 @@
1
- import type {
2
- AttachmentAction,
3
- DecryptedMessage,
4
- DeletedMessage,
5
- HandlerStatus,
6
- MembershipActivity,
7
- RoomActivity,
8
- } from 'webex-message-handler'
9
1
  import { z } from 'zod'
10
2
 
3
+ export type { WebexListenerEventMap as WebexBotListenerEventMap } from '../webex/listener'
4
+
11
5
  export interface WebexBotEntry {
12
6
  bot_id: string
13
7
  bot_name: string
@@ -55,18 +49,3 @@ export const WebexBotCredentialsSchema = z.object({
55
49
  bot_id: z.string(),
56
50
  bot_name: z.string(),
57
51
  })
58
-
59
- export interface WebexBotListenerEventMap {
60
- message_created: [event: DecryptedMessage]
61
- message_updated: [event: DecryptedMessage]
62
- message_deleted: [event: DeletedMessage]
63
- membership_created: [event: MembershipActivity]
64
- attachment_action: [event: AttachmentAction]
65
- room_created: [event: RoomActivity]
66
- room_updated: [event: RoomActivity]
67
- webex_event: [event: DecryptedMessage | DeletedMessage | MembershipActivity | AttachmentAction | RoomActivity]
68
- connected: [info: { connected: boolean; status: HandlerStatus }]
69
- reconnecting: [attempt: number]
70
- disconnected: [reason: string]
71
- error: [error: Error]
72
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"wdm-discovery.d.ts","sourceRoot":"","sources":["../../../../src/platforms/webexbot/wdm-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAA+B,MAAM,uBAAuB,CAAA;AAavF,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAa1E;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM,GAAG,aAAa,CAc1E"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"wdm-discovery.js","sourceRoot":"","sources":["../../../../src/platforms/webexbot/wdm-discovery.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAEvC,MAAM,eAAe,GAAG,wDAAwD,CAAA;AAChF,MAAM,yBAAyB,GAAG,2CAA2C,CAAA;AAE7E,kFAAkF;AAClF,gFAAgF;AAChF,gFAAgF;AAChF,mFAAmF;AACnF,+EAA+E;AAC/E,4BAA4B;AAC5B,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAa;IACvD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,eAAe,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,EAAE,CAAC,CAAA;IAChG,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,aAAa,CAAC,8CAA8C,QAAQ,CAAC,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAA;IAClH,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwC,CAAA;IAC9E,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,GAAG,CAAA;IACrC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,aAAa,CAAC,oDAAoD,EAAE,sBAAsB,CAAC,CAAA;IACvG,CAAC;IAED,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAA;AAC5C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,aAAqB;IACzD,OAAO,KAAK,EAAE,GAAiB,EAA0B,EAAE;QACzD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,yBAAyB,CAAC;YACvD,CAAC,CAAC,aAAa,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,yBAAyB,CAAC,MAAM,CAAC;YACjE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAA;QAEX,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;QAC1F,OAAO;YACL,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,IAAI,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE;YACtB,IAAI,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE;SACvB,CAAA;IACH,CAAC,CAAA;AACH,CAAC"}