agent-messenger 2.27.0 → 2.27.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/discord/listener.d.ts +9 -1
- package/dist/src/platforms/discord/listener.d.ts.map +1 -1
- package/dist/src/platforms/discord/listener.js +79 -3
- package/dist/src/platforms/discord/listener.js.map +1 -1
- package/dist/src/platforms/discordbot/listener.d.ts +6 -0
- package/dist/src/platforms/discordbot/listener.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/listener.js +78 -2
- package/dist/src/platforms/discordbot/listener.js.map +1 -1
- package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/client.js +4 -4
- package/dist/src/platforms/kakaotalk/client.js.map +1 -1
- 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-telegrambot/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +1 -1
- package/skills/agent-webexbot/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/discord/listener.test.ts +175 -143
- package/src/platforms/discord/listener.ts +87 -3
- package/src/platforms/discordbot/listener.test.ts +186 -184
- package/src/platforms/discordbot/listener.ts +83 -2
- package/src/platforms/kakaotalk/client.test.ts +40 -0
- package/src/platforms/kakaotalk/client.ts +6 -4
|
@@ -107,11 +107,40 @@ function createMockClient(overrides: Record<string, any> = {}) {
|
|
|
107
107
|
} as any
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
// start() now resolves only once the gateway emits READY, so the handshake must be
|
|
111
|
+
// driven concurrently while start() is pending. This waits for connect() to create the
|
|
112
|
+
// socket (after the awaited gatewayConnect microtask) before the caller drives it.
|
|
113
|
+
async function waitForSocket(): Promise<MockWs> {
|
|
114
|
+
for (let i = 0; i < 50 && !mockWsInstance; i++) {
|
|
115
|
+
await Promise.resolve()
|
|
116
|
+
}
|
|
117
|
+
return mockWsInstance
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function startAndReady(listener: DiscordBotListener): Promise<void> {
|
|
121
|
+
const started = listener.start()
|
|
122
|
+
const ws = await waitForSocket()
|
|
123
|
+
ws.simulateOpen()
|
|
124
|
+
ws.simulateHello()
|
|
125
|
+
ws.simulateReady()
|
|
126
|
+
await started
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// For tests that exercise pre-READY behavior (Identify/heartbeat/close paths): start() stays
|
|
130
|
+
// pending here. The start promise's rejection is swallowed; afterEach stop() clears its timer.
|
|
131
|
+
async function startConnecting(listener: DiscordBotListener): Promise<MockWs> {
|
|
132
|
+
listener.start().catch(() => {})
|
|
133
|
+
const ws = await waitForSocket()
|
|
134
|
+
ws.simulateOpen()
|
|
135
|
+
return ws
|
|
136
|
+
}
|
|
137
|
+
|
|
110
138
|
describe('DiscordBotListener', () => {
|
|
111
139
|
let listener: DiscordBotListener
|
|
112
140
|
|
|
113
141
|
afterEach(() => {
|
|
114
142
|
listener?.stop()
|
|
143
|
+
mockWsInstance = undefined as unknown as MockWs
|
|
115
144
|
})
|
|
116
145
|
|
|
117
146
|
describe('start', () => {
|
|
@@ -119,21 +148,75 @@ describe('DiscordBotListener', () => {
|
|
|
119
148
|
const client = createMockClient()
|
|
120
149
|
listener = new DiscordBotListener(client)
|
|
121
150
|
|
|
122
|
-
await listener
|
|
123
|
-
mockWsInstance.simulateOpen()
|
|
151
|
+
await startAndReady(listener)
|
|
124
152
|
|
|
125
153
|
expect(client.gatewayConnect).toHaveBeenCalledTimes(1)
|
|
126
154
|
})
|
|
127
155
|
|
|
156
|
+
it('does not resolve until a READY dispatch is delivered', async () => {
|
|
157
|
+
const client = createMockClient()
|
|
158
|
+
listener = new DiscordBotListener(client)
|
|
159
|
+
|
|
160
|
+
let resolved = false
|
|
161
|
+
const started = listener.start().then(() => {
|
|
162
|
+
resolved = true
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
const ws = await waitForSocket()
|
|
166
|
+
ws.simulateOpen()
|
|
167
|
+
ws.simulateHello()
|
|
168
|
+
|
|
169
|
+
// given: socket open + Hello (Identify sent) but no READY yet
|
|
170
|
+
await Promise.resolve()
|
|
171
|
+
expect(resolved).toBe(false)
|
|
172
|
+
|
|
173
|
+
// when: READY arrives
|
|
174
|
+
ws.simulateReady()
|
|
175
|
+
await started
|
|
176
|
+
|
|
177
|
+
expect(resolved).toBe(true)
|
|
178
|
+
})
|
|
179
|
+
|
|
128
180
|
it('is idempotent', async () => {
|
|
129
181
|
const client = createMockClient()
|
|
130
182
|
listener = new DiscordBotListener(client)
|
|
131
183
|
|
|
132
|
-
await listener
|
|
184
|
+
await startAndReady(listener)
|
|
133
185
|
await listener.start()
|
|
134
186
|
|
|
135
187
|
expect(client.gatewayConnect).toHaveBeenCalledTimes(1)
|
|
136
188
|
})
|
|
189
|
+
|
|
190
|
+
it('shares one readiness promise across concurrent start() calls', async () => {
|
|
191
|
+
const client = createMockClient()
|
|
192
|
+
listener = new DiscordBotListener(client)
|
|
193
|
+
|
|
194
|
+
const first = listener.start()
|
|
195
|
+
const second = listener.start()
|
|
196
|
+
|
|
197
|
+
const ws = await waitForSocket()
|
|
198
|
+
ws.simulateOpen()
|
|
199
|
+
ws.simulateHello()
|
|
200
|
+
ws.simulateReady()
|
|
201
|
+
|
|
202
|
+
await Promise.all([first, second])
|
|
203
|
+
expect(client.gatewayConnect).toHaveBeenCalledTimes(1)
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it('rejects an in-flight start() when stop() is called before READY', async () => {
|
|
207
|
+
const client = createMockClient()
|
|
208
|
+
listener = new DiscordBotListener(client)
|
|
209
|
+
|
|
210
|
+
const started = listener.start()
|
|
211
|
+
const ws = await waitForSocket()
|
|
212
|
+
ws.simulateOpen()
|
|
213
|
+
ws.simulateHello()
|
|
214
|
+
|
|
215
|
+
// given: start() is still awaiting READY when the consumer stops the listener
|
|
216
|
+
listener.stop()
|
|
217
|
+
|
|
218
|
+
await expect(started).rejects.toThrow(/stopped before becoming ready/)
|
|
219
|
+
})
|
|
137
220
|
})
|
|
138
221
|
|
|
139
222
|
describe('connected event', () => {
|
|
@@ -144,10 +227,7 @@ describe('DiscordBotListener', () => {
|
|
|
144
227
|
const connected: any[] = []
|
|
145
228
|
listener.on('connected', (info) => connected.push(info))
|
|
146
229
|
|
|
147
|
-
await listener
|
|
148
|
-
mockWsInstance.simulateOpen()
|
|
149
|
-
mockWsInstance.simulateHello()
|
|
150
|
-
mockWsInstance.simulateReady()
|
|
230
|
+
await startAndReady(listener)
|
|
151
231
|
|
|
152
232
|
expect(connected.length).toBe(1)
|
|
153
233
|
expect(connected[0].user.id).toBe('BOT_SELF')
|
|
@@ -160,9 +240,8 @@ describe('DiscordBotListener', () => {
|
|
|
160
240
|
const client = createMockClient()
|
|
161
241
|
listener = new DiscordBotListener(client)
|
|
162
242
|
|
|
163
|
-
await listener
|
|
164
|
-
|
|
165
|
-
mockWsInstance.simulateHello()
|
|
243
|
+
const ws = await startConnecting(listener)
|
|
244
|
+
ws.simulateHello()
|
|
166
245
|
|
|
167
246
|
const sentMessages = mockWsInstance.sent.map((s) => JSON.parse(s))
|
|
168
247
|
const identifyMsg = sentMessages.find((m) => m.op === 2)
|
|
@@ -176,9 +255,8 @@ describe('DiscordBotListener', () => {
|
|
|
176
255
|
const customIntents = (1 << 9) | (1 << 15) // GuildMessages | MessageContent
|
|
177
256
|
listener = new DiscordBotListener(client, { intents: customIntents })
|
|
178
257
|
|
|
179
|
-
await listener
|
|
180
|
-
|
|
181
|
-
mockWsInstance.simulateHello()
|
|
258
|
+
const ws = await startConnecting(listener)
|
|
259
|
+
ws.simulateHello()
|
|
182
260
|
|
|
183
261
|
const sentMessages = mockWsInstance.sent.map((s) => JSON.parse(s))
|
|
184
262
|
const identifyMsg = sentMessages.find((m) => m.op === 2)
|
|
@@ -191,9 +269,8 @@ describe('DiscordBotListener', () => {
|
|
|
191
269
|
const client = createMockClient()
|
|
192
270
|
listener = new DiscordBotListener(client)
|
|
193
271
|
|
|
194
|
-
await listener
|
|
195
|
-
|
|
196
|
-
mockWsInstance.simulateHello()
|
|
272
|
+
const ws = await startConnecting(listener)
|
|
273
|
+
ws.simulateHello()
|
|
197
274
|
|
|
198
275
|
const sentMessages = mockWsInstance.sent.map((s) => JSON.parse(s))
|
|
199
276
|
const identifyMsg = sentMessages.find((m) => m.op === 2)
|
|
@@ -214,10 +291,7 @@ describe('DiscordBotListener', () => {
|
|
|
214
291
|
const messages: DiscordGatewayMessageCreateEvent[] = []
|
|
215
292
|
listener.on('message_create', (event) => messages.push(event))
|
|
216
293
|
|
|
217
|
-
await listener
|
|
218
|
-
mockWsInstance.simulateOpen()
|
|
219
|
-
mockWsInstance.simulateHello()
|
|
220
|
-
mockWsInstance.simulateReady()
|
|
294
|
+
await startAndReady(listener)
|
|
221
295
|
mockWsInstance.simulateDispatch(
|
|
222
296
|
'MESSAGE_CREATE',
|
|
223
297
|
{
|
|
@@ -242,10 +316,7 @@ describe('DiscordBotListener', () => {
|
|
|
242
316
|
const messages: DiscordGatewayMessageCreateEvent[] = []
|
|
243
317
|
listener.on('message_create', (event) => messages.push(event))
|
|
244
318
|
|
|
245
|
-
await listener
|
|
246
|
-
mockWsInstance.simulateOpen()
|
|
247
|
-
mockWsInstance.simulateHello()
|
|
248
|
-
mockWsInstance.simulateReady()
|
|
319
|
+
await startAndReady(listener)
|
|
249
320
|
mockWsInstance.simulateDispatch(
|
|
250
321
|
'MESSAGE_CREATE',
|
|
251
322
|
{
|
|
@@ -283,10 +354,7 @@ describe('DiscordBotListener', () => {
|
|
|
283
354
|
const updates: DiscordGatewayMessageUpdateEvent[] = []
|
|
284
355
|
listener.on('message_update', (event) => updates.push(event))
|
|
285
356
|
|
|
286
|
-
await listener
|
|
287
|
-
mockWsInstance.simulateOpen()
|
|
288
|
-
mockWsInstance.simulateHello()
|
|
289
|
-
mockWsInstance.simulateReady()
|
|
357
|
+
await startAndReady(listener)
|
|
290
358
|
mockWsInstance.simulateDispatch(
|
|
291
359
|
'MESSAGE_UPDATE',
|
|
292
360
|
{ id: 'msg_1', channel_id: 'C123', content: 'edited', edited_timestamp: '2024-01-01T00:01:00Z' },
|
|
@@ -305,10 +373,7 @@ describe('DiscordBotListener', () => {
|
|
|
305
373
|
const deletes: DiscordGatewayMessageDeleteEvent[] = []
|
|
306
374
|
listener.on('message_delete', (event) => deletes.push(event))
|
|
307
375
|
|
|
308
|
-
await listener
|
|
309
|
-
mockWsInstance.simulateOpen()
|
|
310
|
-
mockWsInstance.simulateHello()
|
|
311
|
-
mockWsInstance.simulateReady()
|
|
376
|
+
await startAndReady(listener)
|
|
312
377
|
mockWsInstance.simulateDispatch('MESSAGE_DELETE', { id: 'msg_1', channel_id: 'C123' }, 2)
|
|
313
378
|
|
|
314
379
|
expect(deletes.length).toBe(1)
|
|
@@ -324,10 +389,7 @@ describe('DiscordBotListener', () => {
|
|
|
324
389
|
const reactions: DiscordGatewayReactionEvent[] = []
|
|
325
390
|
listener.on('message_reaction_add', (event) => reactions.push(event))
|
|
326
391
|
|
|
327
|
-
await listener
|
|
328
|
-
mockWsInstance.simulateOpen()
|
|
329
|
-
mockWsInstance.simulateHello()
|
|
330
|
-
mockWsInstance.simulateReady()
|
|
392
|
+
await startAndReady(listener)
|
|
331
393
|
mockWsInstance.simulateDispatch(
|
|
332
394
|
'MESSAGE_REACTION_ADD',
|
|
333
395
|
{
|
|
@@ -353,10 +415,7 @@ describe('DiscordBotListener', () => {
|
|
|
353
415
|
const interactions: any[] = []
|
|
354
416
|
listener.on('interaction_create', (event) => interactions.push(event))
|
|
355
417
|
|
|
356
|
-
await listener
|
|
357
|
-
mockWsInstance.simulateOpen()
|
|
358
|
-
mockWsInstance.simulateHello()
|
|
359
|
-
mockWsInstance.simulateReady()
|
|
418
|
+
await startAndReady(listener)
|
|
360
419
|
mockWsInstance.simulateDispatch(
|
|
361
420
|
'INTERACTION_CREATE',
|
|
362
421
|
{
|
|
@@ -383,10 +442,7 @@ describe('DiscordBotListener', () => {
|
|
|
383
442
|
const events: DiscordGatewayGenericEvent[] = []
|
|
384
443
|
listener.on('discord_event', (event) => events.push(event))
|
|
385
444
|
|
|
386
|
-
await listener
|
|
387
|
-
mockWsInstance.simulateOpen()
|
|
388
|
-
mockWsInstance.simulateHello()
|
|
389
|
-
mockWsInstance.simulateReady()
|
|
445
|
+
await startAndReady(listener)
|
|
390
446
|
mockWsInstance.simulateDispatch(
|
|
391
447
|
'MESSAGE_CREATE',
|
|
392
448
|
{ id: 'm1', channel_id: 'C1', content: 'hi', timestamp: 't', author: { id: 'U1', username: 'u' } },
|
|
@@ -409,9 +465,8 @@ describe('DiscordBotListener', () => {
|
|
|
409
465
|
const client = createMockClient()
|
|
410
466
|
listener = new DiscordBotListener(client)
|
|
411
467
|
|
|
412
|
-
await listener
|
|
413
|
-
|
|
414
|
-
mockWsInstance.simulateHello(50)
|
|
468
|
+
const ws = await startConnecting(listener)
|
|
469
|
+
ws.simulateHello(50)
|
|
415
470
|
|
|
416
471
|
await new Promise((r) => setTimeout(r, 150))
|
|
417
472
|
|
|
@@ -431,10 +486,7 @@ describe('DiscordBotListener', () => {
|
|
|
431
486
|
const events: DiscordGatewayGenericEvent[] = []
|
|
432
487
|
listener.on('discord_event', (event) => events.push(event))
|
|
433
488
|
|
|
434
|
-
await listener
|
|
435
|
-
mockWsInstance.simulateOpen()
|
|
436
|
-
mockWsInstance.simulateHello()
|
|
437
|
-
mockWsInstance.simulateReady()
|
|
489
|
+
await startAndReady(listener)
|
|
438
490
|
mockWsInstance.simulateHeartbeatACK()
|
|
439
491
|
|
|
440
492
|
expect(events.length).toBe(0)
|
|
@@ -451,9 +503,8 @@ describe('DiscordBotListener', () => {
|
|
|
451
503
|
const disconnected: boolean[] = []
|
|
452
504
|
listener.on('disconnected', () => disconnected.push(true))
|
|
453
505
|
|
|
454
|
-
await listener
|
|
455
|
-
|
|
456
|
-
mockWsInstance.simulateHello(50)
|
|
506
|
+
const ws = await startConnecting(listener)
|
|
507
|
+
ws.simulateHello(50)
|
|
457
508
|
|
|
458
509
|
await new Promise((r) => setTimeout(r, 300))
|
|
459
510
|
|
|
@@ -469,8 +520,7 @@ describe('DiscordBotListener', () => {
|
|
|
469
520
|
const client = createMockClient()
|
|
470
521
|
listener = new DiscordBotListener(client)
|
|
471
522
|
|
|
472
|
-
await listener
|
|
473
|
-
mockWsInstance.simulateOpen()
|
|
523
|
+
await startConnecting(listener)
|
|
474
524
|
|
|
475
525
|
listener.stop()
|
|
476
526
|
|
|
@@ -487,9 +537,8 @@ describe('DiscordBotListener', () => {
|
|
|
487
537
|
const disconnected: boolean[] = []
|
|
488
538
|
listener.on('disconnected', () => disconnected.push(true))
|
|
489
539
|
|
|
490
|
-
await listener
|
|
491
|
-
|
|
492
|
-
mockWsInstance.simulateClose()
|
|
540
|
+
const ws = await startConnecting(listener)
|
|
541
|
+
ws.simulateClose()
|
|
493
542
|
|
|
494
543
|
expect(disconnected.length).toBe(1)
|
|
495
544
|
|
|
@@ -497,28 +546,20 @@ describe('DiscordBotListener', () => {
|
|
|
497
546
|
expect(client.gatewayConnect.mock.calls.length).toBeGreaterThanOrEqual(2)
|
|
498
547
|
})
|
|
499
548
|
|
|
500
|
-
it('
|
|
501
|
-
let callCount = 0
|
|
549
|
+
it('rejects start() and stops on gatewayConnect failure during initial connect', async () => {
|
|
502
550
|
const client = createMockClient({
|
|
503
|
-
gatewayConnect: mock(() =>
|
|
504
|
-
callCount++
|
|
505
|
-
if (callCount === 1) return Promise.reject(new Error('network_error'))
|
|
506
|
-
return Promise.resolve({ token: 'fake-bot-token' })
|
|
507
|
-
}),
|
|
551
|
+
gatewayConnect: mock(() => Promise.reject(new Error('network_error'))),
|
|
508
552
|
})
|
|
509
553
|
|
|
510
554
|
listener = new DiscordBotListener(client)
|
|
555
|
+
listener.on('error', () => {})
|
|
511
556
|
|
|
512
|
-
|
|
513
|
-
listener.on('error', (err) => errors.push(err))
|
|
514
|
-
|
|
515
|
-
await listener.start()
|
|
557
|
+
await expect(listener.start()).rejects.toThrow('network_error')
|
|
516
558
|
|
|
559
|
+
// given: a pre-READY connect error tears down the listener (no resurrected reconnect loop)
|
|
517
560
|
await new Promise((r) => setTimeout(r, 1500))
|
|
518
|
-
|
|
519
|
-
expect(
|
|
520
|
-
expect(errors[0].message).toBe('network_error')
|
|
521
|
-
expect(client.gatewayConnect.mock.calls.length).toBeGreaterThanOrEqual(2)
|
|
561
|
+
expect((listener as any).running).toBe(false)
|
|
562
|
+
expect(client.gatewayConnect).toHaveBeenCalledTimes(1)
|
|
522
563
|
})
|
|
523
564
|
})
|
|
524
565
|
|
|
@@ -531,10 +572,7 @@ describe('DiscordBotListener', () => {
|
|
|
531
572
|
const handler = (event: DiscordGatewayMessageCreateEvent) => messages.push(event)
|
|
532
573
|
listener.on('message_create', handler)
|
|
533
574
|
|
|
534
|
-
await listener
|
|
535
|
-
mockWsInstance.simulateOpen()
|
|
536
|
-
mockWsInstance.simulateHello()
|
|
537
|
-
mockWsInstance.simulateReady()
|
|
575
|
+
await startAndReady(listener)
|
|
538
576
|
mockWsInstance.simulateDispatch(
|
|
539
577
|
'MESSAGE_CREATE',
|
|
540
578
|
{ id: 'm1', channel_id: 'C1', content: 'a', timestamp: 't', author: { id: 'U1', username: 'u' } },
|
|
@@ -559,10 +597,7 @@ describe('DiscordBotListener', () => {
|
|
|
559
597
|
const messages: DiscordGatewayMessageCreateEvent[] = []
|
|
560
598
|
listener.once('message_create', (event) => messages.push(event))
|
|
561
599
|
|
|
562
|
-
await listener
|
|
563
|
-
mockWsInstance.simulateOpen()
|
|
564
|
-
mockWsInstance.simulateHello()
|
|
565
|
-
mockWsInstance.simulateReady()
|
|
600
|
+
await startAndReady(listener)
|
|
566
601
|
mockWsInstance.simulateDispatch(
|
|
567
602
|
'MESSAGE_CREATE',
|
|
568
603
|
{ id: 'm1', channel_id: 'C1', content: 'first', timestamp: 't', author: { id: 'U1', username: 'u' } },
|
|
@@ -584,10 +619,7 @@ describe('DiscordBotListener', () => {
|
|
|
584
619
|
const client = createMockClient()
|
|
585
620
|
listener = new DiscordBotListener(client)
|
|
586
621
|
|
|
587
|
-
await listener
|
|
588
|
-
mockWsInstance.simulateOpen()
|
|
589
|
-
mockWsInstance.simulateHello()
|
|
590
|
-
mockWsInstance.simulateReady()
|
|
622
|
+
await startAndReady(listener)
|
|
591
623
|
|
|
592
624
|
;(listener as any).reconnectAttempts = 5
|
|
593
625
|
mockWsInstance.simulateReconnect()
|
|
@@ -601,10 +633,7 @@ describe('DiscordBotListener', () => {
|
|
|
601
633
|
const client = createMockClient()
|
|
602
634
|
listener = new DiscordBotListener(client)
|
|
603
635
|
|
|
604
|
-
await listener
|
|
605
|
-
mockWsInstance.simulateOpen()
|
|
606
|
-
mockWsInstance.simulateHello()
|
|
607
|
-
mockWsInstance.simulateReady()
|
|
636
|
+
await startAndReady(listener)
|
|
608
637
|
|
|
609
638
|
expect((listener as any).sessionId).toBe('session_123')
|
|
610
639
|
|
|
@@ -619,10 +648,7 @@ describe('DiscordBotListener', () => {
|
|
|
619
648
|
const client = createMockClient()
|
|
620
649
|
listener = new DiscordBotListener(client)
|
|
621
650
|
|
|
622
|
-
await listener
|
|
623
|
-
mockWsInstance.simulateOpen()
|
|
624
|
-
mockWsInstance.simulateHello()
|
|
625
|
-
mockWsInstance.simulateReady()
|
|
651
|
+
await startAndReady(listener)
|
|
626
652
|
|
|
627
653
|
const sessionIdBefore = (listener as any).sessionId
|
|
628
654
|
|
|
@@ -637,10 +663,7 @@ describe('DiscordBotListener', () => {
|
|
|
637
663
|
const client = createMockClient()
|
|
638
664
|
listener = new DiscordBotListener(client)
|
|
639
665
|
|
|
640
|
-
await listener
|
|
641
|
-
mockWsInstance.simulateOpen()
|
|
642
|
-
mockWsInstance.simulateHello()
|
|
643
|
-
mockWsInstance.simulateReady()
|
|
666
|
+
await startAndReady(listener)
|
|
644
667
|
|
|
645
668
|
mockWsInstance.simulateClose()
|
|
646
669
|
|
|
@@ -658,39 +681,38 @@ describe('DiscordBotListener', () => {
|
|
|
658
681
|
})
|
|
659
682
|
|
|
660
683
|
describe('non-recoverable close codes', () => {
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
listener.on('error', (err) => errors.push(err))
|
|
667
|
-
|
|
668
|
-
await listener.start()
|
|
669
|
-
mockWsInstance.simulateOpen()
|
|
670
|
-
mockWsInstance.simulateClose(4014)
|
|
684
|
+
for (const code of [4004, 4013, 4014]) {
|
|
685
|
+
it(`rejects start() and stops on non-recoverable close ${code}`, async () => {
|
|
686
|
+
const client = createMockClient()
|
|
687
|
+
listener = new DiscordBotListener(client)
|
|
688
|
+
listener.on('error', () => {})
|
|
671
689
|
|
|
672
|
-
|
|
690
|
+
const started = listener.start()
|
|
691
|
+
const ws = await waitForSocket()
|
|
692
|
+
ws.simulateOpen()
|
|
693
|
+
ws.simulateClose(code)
|
|
673
694
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
695
|
+
await expect(started).rejects.toThrow(String(code))
|
|
696
|
+
expect((listener as any).running).toBe(false)
|
|
697
|
+
expect(client.gatewayConnect).toHaveBeenCalledTimes(1)
|
|
698
|
+
})
|
|
699
|
+
}
|
|
700
|
+
})
|
|
678
701
|
|
|
679
|
-
|
|
702
|
+
describe('connect timeout', () => {
|
|
703
|
+
it('rejects start() and tears down when READY never arrives', async () => {
|
|
680
704
|
const client = createMockClient()
|
|
681
|
-
listener = new DiscordBotListener(client)
|
|
682
|
-
|
|
683
|
-
const errors: Error[] = []
|
|
684
|
-
listener.on('error', (err) => errors.push(err))
|
|
685
|
-
|
|
686
|
-
await listener.start()
|
|
687
|
-
mockWsInstance.simulateOpen()
|
|
688
|
-
mockWsInstance.simulateClose(4004)
|
|
705
|
+
listener = new DiscordBotListener(client, { connectTimeoutMs: 100 })
|
|
706
|
+
listener.on('error', () => {})
|
|
689
707
|
|
|
690
|
-
|
|
708
|
+
const started = listener.start()
|
|
709
|
+
const ws = await waitForSocket()
|
|
710
|
+
ws.simulateOpen()
|
|
711
|
+
ws.simulateHello()
|
|
712
|
+
// given: Identify sent but the gateway never delivers READY
|
|
691
713
|
|
|
692
|
-
expect(
|
|
693
|
-
expect(
|
|
714
|
+
await expect(started).rejects.toThrow(/did not become ready/)
|
|
715
|
+
expect((listener as any).running).toBe(false)
|
|
694
716
|
})
|
|
695
717
|
})
|
|
696
718
|
|
|
@@ -699,10 +721,7 @@ describe('DiscordBotListener', () => {
|
|
|
699
721
|
const client = createMockClient()
|
|
700
722
|
listener = new DiscordBotListener(client)
|
|
701
723
|
|
|
702
|
-
await listener
|
|
703
|
-
mockWsInstance.simulateOpen()
|
|
704
|
-
mockWsInstance.simulateHello()
|
|
705
|
-
mockWsInstance.simulateReady()
|
|
724
|
+
await startAndReady(listener)
|
|
706
725
|
|
|
707
726
|
expect((listener as any).sessionId).toBe('session_123')
|
|
708
727
|
|
|
@@ -729,10 +748,7 @@ describe('DiscordBotListener', () => {
|
|
|
729
748
|
const client = createMockClient()
|
|
730
749
|
listener = new DiscordBotListener(client)
|
|
731
750
|
|
|
732
|
-
await listener
|
|
733
|
-
mockWsInstance.simulateOpen()
|
|
734
|
-
mockWsInstance.simulateHello()
|
|
735
|
-
mockWsInstance.simulateReady()
|
|
751
|
+
await startAndReady(listener)
|
|
736
752
|
|
|
737
753
|
mockWsInstance.simulateClose(4009)
|
|
738
754
|
|
|
@@ -749,10 +765,12 @@ describe('DiscordBotListener', () => {
|
|
|
749
765
|
const client = createMockClient()
|
|
750
766
|
listener = new DiscordBotListener(client)
|
|
751
767
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
768
|
+
const started = listener.start()
|
|
769
|
+
const ws = await waitForSocket()
|
|
770
|
+
ws.simulateOpen()
|
|
771
|
+
ws.simulateHello(50)
|
|
772
|
+
ws.simulateReady()
|
|
773
|
+
await started
|
|
756
774
|
|
|
757
775
|
mockWsInstance.simulateHello(50)
|
|
758
776
|
|
|
@@ -777,10 +795,7 @@ describe('DiscordBotListener', () => {
|
|
|
777
795
|
const client = createMockClient()
|
|
778
796
|
listener = new DiscordBotListener(client)
|
|
779
797
|
|
|
780
|
-
await listener
|
|
781
|
-
mockWsInstance.simulateOpen()
|
|
782
|
-
mockWsInstance.simulateHello()
|
|
783
|
-
mockWsInstance.simulateReady()
|
|
798
|
+
await startAndReady(listener)
|
|
784
799
|
|
|
785
800
|
mockWsInstance.simulateInvalidSession(true)
|
|
786
801
|
|
|
@@ -798,10 +813,7 @@ describe('DiscordBotListener', () => {
|
|
|
798
813
|
const client = createMockClient()
|
|
799
814
|
listener = new DiscordBotListener(client)
|
|
800
815
|
|
|
801
|
-
await listener
|
|
802
|
-
mockWsInstance.simulateOpen()
|
|
803
|
-
mockWsInstance.simulateHello()
|
|
804
|
-
mockWsInstance.simulateReady()
|
|
816
|
+
await startAndReady(listener)
|
|
805
817
|
|
|
806
818
|
const sentBefore = mockWsInstance.sent.length
|
|
807
819
|
mockWsInstance.simulateMessage({ op: 1 })
|
|
@@ -818,10 +830,7 @@ describe('DiscordBotListener', () => {
|
|
|
818
830
|
const client = createMockClient()
|
|
819
831
|
listener = new DiscordBotListener(client)
|
|
820
832
|
|
|
821
|
-
await listener
|
|
822
|
-
mockWsInstance.simulateOpen()
|
|
823
|
-
mockWsInstance.simulateHello()
|
|
824
|
-
mockWsInstance.simulateReady()
|
|
833
|
+
await startAndReady(listener)
|
|
825
834
|
|
|
826
835
|
mockWsInstance.simulateDispatch(
|
|
827
836
|
'MESSAGE_CREATE',
|
|
@@ -836,10 +845,7 @@ describe('DiscordBotListener', () => {
|
|
|
836
845
|
const client = createMockClient()
|
|
837
846
|
listener = new DiscordBotListener(client)
|
|
838
847
|
|
|
839
|
-
await listener
|
|
840
|
-
mockWsInstance.simulateOpen()
|
|
841
|
-
mockWsInstance.simulateHello()
|
|
842
|
-
mockWsInstance.simulateReady()
|
|
848
|
+
await startAndReady(listener)
|
|
843
849
|
|
|
844
850
|
mockWsInstance.simulateDispatch(
|
|
845
851
|
'MESSAGE_CREATE',
|
|
@@ -863,11 +869,11 @@ describe('DiscordBotListener', () => {
|
|
|
863
869
|
const client = createMockClient()
|
|
864
870
|
listener = new DiscordBotListener(client)
|
|
865
871
|
|
|
866
|
-
await listener
|
|
872
|
+
await startConnecting(listener)
|
|
867
873
|
;(listener as any).reconnectAttempts = 5
|
|
868
874
|
listener.stop()
|
|
869
875
|
|
|
870
|
-
await listener
|
|
876
|
+
await startConnecting(listener)
|
|
871
877
|
expect((listener as any).reconnectAttempts).toBe(0)
|
|
872
878
|
})
|
|
873
879
|
})
|
|
@@ -877,10 +883,11 @@ describe('DiscordBotListener', () => {
|
|
|
877
883
|
const client = createMockClient()
|
|
878
884
|
listener = new DiscordBotListener(client)
|
|
879
885
|
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
886
|
+
const started = listener.start()
|
|
887
|
+
const ws = await waitForSocket()
|
|
888
|
+
ws.simulateOpen()
|
|
889
|
+
ws.simulateHello()
|
|
890
|
+
ws.simulateMessage({
|
|
884
891
|
op: 0,
|
|
885
892
|
t: 'READY',
|
|
886
893
|
s: 1,
|
|
@@ -890,6 +897,7 @@ describe('DiscordBotListener', () => {
|
|
|
890
897
|
user: { id: 'BOT', username: 'bot' },
|
|
891
898
|
},
|
|
892
899
|
})
|
|
900
|
+
await started
|
|
893
901
|
|
|
894
902
|
mockWsInstance.simulateClose()
|
|
895
903
|
await new Promise((r) => setTimeout(r, 1500))
|
|
@@ -901,7 +909,8 @@ describe('DiscordBotListener', () => {
|
|
|
901
909
|
const client = createMockClient()
|
|
902
910
|
listener = new DiscordBotListener(client)
|
|
903
911
|
|
|
904
|
-
|
|
912
|
+
listener.start().catch(() => {})
|
|
913
|
+
await waitForSocket()
|
|
905
914
|
|
|
906
915
|
expect(MockWs.lastUrl).toBe('wss://gateway.discord.gg/?v=10&encoding=json')
|
|
907
916
|
})
|
|
@@ -912,10 +921,11 @@ describe('DiscordBotListener', () => {
|
|
|
912
921
|
const client = createMockClient()
|
|
913
922
|
listener = new DiscordBotListener(client)
|
|
914
923
|
|
|
915
|
-
|
|
924
|
+
listener.start().catch(() => {})
|
|
925
|
+
const ws = await waitForSocket()
|
|
916
926
|
;(listener as any).reconnectAttempts = 5
|
|
917
927
|
|
|
918
|
-
|
|
928
|
+
ws.simulateOpen()
|
|
919
929
|
|
|
920
930
|
// given: a socket opens but no READY received yet
|
|
921
931
|
// then: reconnectAttempts must NOT be reset (open alone is not a successful session)
|
|
@@ -926,12 +936,14 @@ describe('DiscordBotListener', () => {
|
|
|
926
936
|
const client = createMockClient()
|
|
927
937
|
listener = new DiscordBotListener(client)
|
|
928
938
|
|
|
929
|
-
|
|
939
|
+
const started = listener.start()
|
|
940
|
+
const ws = await waitForSocket()
|
|
930
941
|
;(listener as any).reconnectAttempts = 5
|
|
931
942
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
943
|
+
ws.simulateOpen()
|
|
944
|
+
ws.simulateHello()
|
|
945
|
+
ws.simulateReady()
|
|
946
|
+
await started
|
|
935
947
|
|
|
936
948
|
expect((listener as any).reconnectAttempts).toBe(0)
|
|
937
949
|
})
|
|
@@ -940,10 +952,7 @@ describe('DiscordBotListener', () => {
|
|
|
940
952
|
const client = createMockClient()
|
|
941
953
|
listener = new DiscordBotListener(client)
|
|
942
954
|
|
|
943
|
-
await listener
|
|
944
|
-
mockWsInstance.simulateOpen()
|
|
945
|
-
mockWsInstance.simulateHello()
|
|
946
|
-
mockWsInstance.simulateReady()
|
|
955
|
+
await startAndReady(listener)
|
|
947
956
|
|
|
948
957
|
mockWsInstance.simulateClose()
|
|
949
958
|
await new Promise((r) => setTimeout(r, 1500))
|
|
@@ -966,10 +975,7 @@ describe('DiscordBotListener', () => {
|
|
|
966
975
|
const connectedEvents: any[] = []
|
|
967
976
|
listener.on('connected', (info) => connectedEvents.push(info))
|
|
968
977
|
|
|
969
|
-
await listener
|
|
970
|
-
mockWsInstance.simulateOpen()
|
|
971
|
-
mockWsInstance.simulateHello()
|
|
972
|
-
mockWsInstance.simulateReady()
|
|
978
|
+
await startAndReady(listener)
|
|
973
979
|
|
|
974
980
|
expect(connectedEvents.length).toBe(1)
|
|
975
981
|
|
|
@@ -991,15 +997,13 @@ describe('DiscordBotListener', () => {
|
|
|
991
997
|
const client = createMockClient()
|
|
992
998
|
listener = new DiscordBotListener(client)
|
|
993
999
|
|
|
994
|
-
await listener
|
|
995
|
-
mockWsInstance.simulateOpen()
|
|
996
|
-
mockWsInstance.simulateHello()
|
|
997
|
-
mockWsInstance.simulateReady()
|
|
1000
|
+
await startAndReady(listener)
|
|
998
1001
|
|
|
999
1002
|
const oldWs = mockWsInstance
|
|
1000
1003
|
|
|
1001
1004
|
listener.stop()
|
|
1002
|
-
|
|
1005
|
+
mockWsInstance = undefined as unknown as MockWs
|
|
1006
|
+
await startConnecting(listener)
|
|
1003
1007
|
|
|
1004
1008
|
// given: a fresh socket from the second start()
|
|
1005
1009
|
// when: the OLD socket fires a stale close event
|
|
@@ -1018,10 +1022,7 @@ describe('DiscordBotListener', () => {
|
|
|
1018
1022
|
const client = createMockClient()
|
|
1019
1023
|
listener = new DiscordBotListener(client)
|
|
1020
1024
|
|
|
1021
|
-
await listener
|
|
1022
|
-
mockWsInstance.simulateOpen()
|
|
1023
|
-
mockWsInstance.simulateHello()
|
|
1024
|
-
mockWsInstance.simulateReady()
|
|
1025
|
+
await startAndReady(listener)
|
|
1025
1026
|
|
|
1026
1027
|
const initialGeneration = (listener as any).generation
|
|
1027
1028
|
|
|
@@ -1029,7 +1030,8 @@ describe('DiscordBotListener', () => {
|
|
|
1029
1030
|
|
|
1030
1031
|
// when: stop()+start() before the d=true delay fires
|
|
1031
1032
|
listener.stop()
|
|
1032
|
-
|
|
1033
|
+
mockWsInstance = undefined as unknown as MockWs
|
|
1034
|
+
await startConnecting(listener)
|
|
1033
1035
|
|
|
1034
1036
|
await new Promise((r) => setTimeout(r, 1500))
|
|
1035
1037
|
|