agent-messenger 2.10.1 → 2.11.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.
- package/.claude-plugin/plugin.json +1 -1
- package/.env.template +4 -1
- package/README.md +77 -27
- package/bun.lock +26 -0
- package/dist/package.json +14 -1
- package/dist/src/platforms/channeltalk/commands/auth.d.ts +2 -1
- package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/commands/auth.js +5 -3
- package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts +2 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.js +22 -6
- package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/cli.js +11 -1
- package/dist/src/platforms/channeltalkbot/cli.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/auth.js +1 -5
- package/dist/src/platforms/channeltalkbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/bot.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/bot.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/bot.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/chat.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/chat.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/chat.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/group.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/group.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/group.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/manager.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/manager.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/manager.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/message.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/message.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/whoami.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/credential-manager.d.ts +5 -0
- package/dist/src/platforms/channeltalkbot/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/credential-manager.js +34 -4
- package/dist/src/platforms/channeltalkbot/credential-manager.js.map +1 -1
- package/dist/src/platforms/discord/commands/auth.d.ts +1 -0
- package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/auth.js +3 -1
- package/dist/src/platforms/discord/commands/auth.js.map +1 -1
- package/dist/src/platforms/discord/listener.d.ts +2 -0
- package/dist/src/platforms/discord/listener.d.ts.map +1 -1
- package/dist/src/platforms/discord/listener.js +51 -21
- package/dist/src/platforms/discord/listener.js.map +1 -1
- package/dist/src/platforms/discord/token-extractor.d.ts +2 -1
- package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/discord/token-extractor.js +21 -6
- package/dist/src/platforms/discord/token-extractor.js.map +1 -1
- package/dist/src/platforms/discordbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/cli.js +12 -1
- package/dist/src/platforms/discordbot/cli.js.map +1 -1
- package/dist/src/platforms/discordbot/client.d.ts +3 -0
- package/dist/src/platforms/discordbot/client.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/client.js +3 -0
- package/dist/src/platforms/discordbot/client.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/auth.js +1 -5
- package/dist/src/platforms/discordbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/message.js +1 -6
- package/dist/src/platforms/discordbot/commands/message.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/server.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/server.js +1 -4
- package/dist/src/platforms/discordbot/commands/server.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/whoami.js +1 -6
- package/dist/src/platforms/discordbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/discordbot/index.d.ts +3 -1
- package/dist/src/platforms/discordbot/index.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/index.js +2 -1
- package/dist/src/platforms/discordbot/index.js.map +1 -1
- package/dist/src/platforms/discordbot/listener.d.ts +43 -0
- package/dist/src/platforms/discordbot/listener.d.ts.map +1 -0
- package/dist/src/platforms/discordbot/listener.js +292 -0
- package/dist/src/platforms/discordbot/listener.js.map +1 -0
- package/dist/src/platforms/discordbot/types.d.ts +161 -0
- package/dist/src/platforms/discordbot/types.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/types.js +34 -0
- package/dist/src/platforms/discordbot/types.js.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.js +3 -1
- package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
- package/dist/src/platforms/instagram/token-extractor.d.ts +2 -1
- package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/instagram/token-extractor.js +11 -2
- package/dist/src/platforms/instagram/token-extractor.js.map +1 -1
- package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/auth.js +4 -2
- package/dist/src/platforms/slack/commands/auth.js.map +1 -1
- package/dist/src/platforms/slack/token-extractor.d.ts +4 -1
- package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/slack/token-extractor.js +64 -15
- package/dist/src/platforms/slack/token-extractor.js.map +1 -1
- package/dist/src/platforms/slackbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/cli.js +15 -3
- package/dist/src/platforms/slackbot/cli.js.map +1 -1
- package/dist/src/platforms/slackbot/client.d.ts +22 -1
- package/dist/src/platforms/slackbot/client.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/client.js +104 -1
- package/dist/src/platforms/slackbot/client.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/auth.js +1 -5
- package/dist/src/platforms/slackbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/file.d.ts +3 -0
- package/dist/src/platforms/slackbot/commands/file.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/commands/file.js +164 -0
- package/dist/src/platforms/slackbot/commands/file.js.map +1 -0
- package/dist/src/platforms/slackbot/commands/index.d.ts +1 -0
- package/dist/src/platforms/slackbot/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/index.js +1 -0
- package/dist/src/platforms/slackbot/commands/index.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/message.js +19 -0
- package/dist/src/platforms/slackbot/commands/message.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/whoami.js +1 -6
- package/dist/src/platforms/slackbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/slackbot/credential-manager.d.ts +1 -0
- package/dist/src/platforms/slackbot/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/credential-manager.js +30 -2
- package/dist/src/platforms/slackbot/credential-manager.js.map +1 -1
- package/dist/src/platforms/slackbot/index.d.ts +4 -1
- package/dist/src/platforms/slackbot/index.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/index.js +1 -0
- package/dist/src/platforms/slackbot/index.js.map +1 -1
- package/dist/src/platforms/slackbot/listener.d.ts +44 -0
- package/dist/src/platforms/slackbot/listener.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/listener.js +313 -0
- package/dist/src/platforms/slackbot/listener.js.map +1 -0
- package/dist/src/platforms/slackbot/types.d.ts +196 -1
- package/dist/src/platforms/slackbot/types.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/types.js +4 -1
- package/dist/src/platforms/slackbot/types.js.map +1 -1
- package/dist/src/platforms/teams/commands/auth.d.ts +1 -0
- package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/auth.js +37 -6
- package/dist/src/platforms/teams/commands/auth.js.map +1 -1
- package/dist/src/platforms/teams/ensure-auth.js +31 -9
- package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
- package/dist/src/platforms/teams/token-extractor.d.ts +4 -1
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/teams/token-extractor.js +80 -31
- package/dist/src/platforms/teams/token-extractor.js.map +1 -1
- package/dist/src/platforms/webex/commands/auth.d.ts +1 -0
- package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/auth.js +3 -1
- package/dist/src/platforms/webex/commands/auth.js.map +1 -1
- package/dist/src/platforms/webex/token-extractor.d.ts +3 -1
- package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/webex/token-extractor.js +16 -2
- package/dist/src/platforms/webex/token-extractor.js.map +1 -1
- package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/cli.js +11 -1
- package/dist/src/platforms/wechatbot/cli.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/auth.js +1 -5
- package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/message.js +1 -6
- package/dist/src/platforms/wechatbot/commands/message.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/template.js +1 -6
- package/dist/src/platforms/wechatbot/commands/template.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/user.js +1 -6
- package/dist/src/platforms/wechatbot/commands/user.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/whoami.js +1 -6
- package/dist/src/platforms/wechatbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/whatsappbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/cli.js +11 -1
- package/dist/src/platforms/whatsappbot/cli.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/auth.js +1 -5
- package/dist/src/platforms/whatsappbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/message.js +1 -6
- package/dist/src/platforms/whatsappbot/commands/message.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/template.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/template.js +1 -6
- package/dist/src/platforms/whatsappbot/commands/template.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/whoami.js +1 -6
- package/dist/src/platforms/whatsappbot/commands/whoami.js.map +1 -1
- package/dist/src/shared/chromium/browsers.d.ts +8 -0
- package/dist/src/shared/chromium/browsers.d.ts.map +1 -1
- package/dist/src/shared/chromium/browsers.js +58 -3
- package/dist/src/shared/chromium/browsers.js.map +1 -1
- package/dist/src/shared/chromium/cli-options.d.ts +5 -0
- package/dist/src/shared/chromium/cli-options.d.ts.map +1 -0
- package/dist/src/shared/chromium/cli-options.js +8 -0
- package/dist/src/shared/chromium/cli-options.js.map +1 -0
- 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/dist/src/shared/chromium/index.d.ts +3 -1
- package/dist/src/shared/chromium/index.d.ts.map +1 -1
- package/dist/src/shared/chromium/index.js +2 -1
- package/dist/src/shared/chromium/index.js.map +1 -1
- package/dist/src/shared/utils/cli-output.d.ts +7 -0
- package/dist/src/shared/utils/cli-output.d.ts.map +1 -0
- package/dist/src/shared/utils/cli-output.js +7 -0
- package/dist/src/shared/utils/cli-output.js.map +1 -0
- package/dist/src/tui/app.d.ts.map +1 -1
- package/dist/src/tui/app.js +73 -20
- package/dist/src/tui/app.js.map +1 -1
- package/docs/content/docs/cli/channeltalk.mdx +4 -0
- package/docs/content/docs/cli/discord.mdx +5 -0
- package/docs/content/docs/cli/instagram.mdx +3 -0
- package/docs/content/docs/cli/slack.mdx +5 -0
- package/docs/content/docs/cli/slackbot.mdx +60 -22
- package/docs/content/docs/cli/teams.mdx +5 -0
- package/docs/content/docs/cli/webex.mdx +3 -0
- package/docs/content/docs/sdk/channeltalkbot.mdx +38 -1
- package/docs/content/docs/sdk/discordbot.mdx +501 -0
- package/docs/content/docs/sdk/meta.json +2 -0
- package/docs/content/docs/sdk/slackbot.mdx +576 -0
- package/e2e/README.md +1 -1
- package/e2e/channeltalk.e2e.test.ts +13 -13
- package/e2e/channeltalkbot.e2e.test.ts +13 -13
- package/e2e/config.ts +9 -4
- 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/examples/discordbot-listen.ts +65 -0
- package/examples/slackbot-listen.ts +65 -0
- package/package.json +14 -1
- package/skills/agent-channeltalk/SKILL.md +5 -1
- package/skills/agent-channeltalk/references/authentication.md +5 -1
- package/skills/agent-channeltalkbot/SKILL.md +17 -3
- package/skills/agent-channeltalkbot/references/authentication.md +7 -5
- package/skills/agent-discord/SKILL.md +5 -1
- package/skills/agent-discord/references/authentication.md +7 -1
- package/skills/agent-discordbot/SKILL.md +13 -2
- package/skills/agent-discordbot/references/common-patterns.md +1 -1
- package/skills/agent-instagram/SKILL.md +7 -1
- package/skills/agent-instagram/references/authentication.md +6 -0
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +5 -1
- package/skills/agent-slack/references/authentication.md +7 -1
- package/skills/agent-slackbot/SKILL.md +56 -4
- package/skills/agent-slackbot/references/authentication.md +4 -0
- package/skills/agent-teams/SKILL.md +5 -1
- package/skills/agent-teams/references/authentication.md +7 -1
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +7 -1
- package/skills/agent-webex/references/authentication.md +6 -0
- package/skills/agent-wechatbot/SKILL.md +16 -1
- package/skills/agent-wechatbot/references/authentication.md +219 -0
- package/skills/agent-wechatbot/references/common-patterns.md +358 -0
- package/skills/agent-wechatbot/templates/account-summary.sh +122 -0
- package/skills/agent-wechatbot/templates/post-message.sh +122 -0
- package/skills/agent-wechatbot/templates/send-template.sh +152 -0
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +30 -1
- package/src/platforms/channeltalk/client.test.ts +26 -26
- package/src/platforms/channeltalk/commands/auth.test.ts +31 -19
- package/src/platforms/channeltalk/commands/auth.ts +15 -5
- 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/token-extractor.ts +24 -5
- package/src/platforms/channeltalk/types.test.ts +12 -12
- package/src/platforms/channeltalkbot/cli.ts +9 -0
- package/src/platforms/channeltalkbot/client.test.ts +14 -14
- package/src/platforms/channeltalkbot/commands/auth.test.ts +16 -16
- package/src/platforms/channeltalkbot/commands/auth.ts +1 -5
- package/src/platforms/channeltalkbot/commands/bot.test.ts +6 -6
- package/src/platforms/channeltalkbot/commands/bot.ts +1 -6
- package/src/platforms/channeltalkbot/commands/chat.test.ts +9 -9
- package/src/platforms/channeltalkbot/commands/chat.ts +1 -6
- package/src/platforms/channeltalkbot/commands/group.test.ts +6 -6
- package/src/platforms/channeltalkbot/commands/group.ts +1 -6
- package/src/platforms/channeltalkbot/commands/manager.test.ts +3 -3
- package/src/platforms/channeltalkbot/commands/manager.ts +1 -6
- package/src/platforms/channeltalkbot/commands/message.test.ts +10 -10
- package/src/platforms/channeltalkbot/commands/message.ts +1 -6
- package/src/platforms/channeltalkbot/commands/snapshot.test.ts +7 -7
- package/src/platforms/channeltalkbot/commands/whoami.test.ts +6 -4
- package/src/platforms/channeltalkbot/commands/whoami.ts +1 -6
- package/src/platforms/channeltalkbot/credential-manager.test.ts +123 -29
- package/src/platforms/channeltalkbot/credential-manager.ts +37 -4
- 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/auth.ts +13 -2
- 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 +92 -34
- package/src/platforms/discord/listener.ts +43 -19
- package/src/platforms/discord/token-extractor.test.ts +53 -53
- package/src/platforms/discord/token-extractor.ts +30 -6
- package/src/platforms/discord/types.test.ts +26 -26
- package/src/platforms/discordbot/cli.ts +10 -0
- package/src/platforms/discordbot/client.test.ts +31 -31
- package/src/platforms/discordbot/client.ts +4 -0
- package/src/platforms/discordbot/commands/auth.test.ts +18 -18
- package/src/platforms/discordbot/commands/auth.ts +1 -5
- 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/message.ts +1 -6
- 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/server.ts +1 -5
- 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/commands/whoami.ts +1 -6
- package/src/platforms/discordbot/credential-manager.test.ts +28 -28
- package/src/platforms/discordbot/index.test.ts +82 -0
- package/src/platforms/discordbot/index.ts +27 -9
- package/src/platforms/discordbot/listener.test.ts +1002 -0
- package/src/platforms/discordbot/listener.ts +321 -0
- package/src/platforms/discordbot/types.ts +163 -0
- package/src/platforms/instagram/client.test.ts +18 -18
- package/src/platforms/instagram/commands/auth.test.ts +11 -11
- package/src/platforms/instagram/commands/auth.ts +9 -1
- 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/instagram/token-extractor.ts +13 -1
- 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/auth.ts +11 -2
- 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 +133 -37
- package/src/platforms/slack/token-extractor.ts +76 -13
- package/src/platforms/slack/types.test.ts +21 -21
- package/src/platforms/slackbot/cli.ts +13 -1
- package/src/platforms/slackbot/client.test.ts +296 -22
- package/src/platforms/slackbot/client.ts +130 -2
- package/src/platforms/slackbot/commands/auth.test.ts +14 -14
- package/src/platforms/slackbot/commands/auth.ts +1 -5
- package/src/platforms/slackbot/commands/channel.test.ts +7 -7
- package/src/platforms/slackbot/commands/file.test.ts +201 -0
- package/src/platforms/slackbot/commands/file.ts +212 -0
- package/src/platforms/slackbot/commands/index.ts +1 -0
- package/src/platforms/slackbot/commands/message.test.ts +13 -13
- package/src/platforms/slackbot/commands/message.ts +22 -0
- 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/commands/whoami.ts +1 -6
- package/src/platforms/slackbot/credential-manager.test.ts +83 -23
- package/src/platforms/slackbot/credential-manager.ts +32 -2
- package/src/platforms/slackbot/index.test.ts +59 -0
- package/src/platforms/slackbot/index.ts +31 -7
- package/src/platforms/slackbot/listener.test.ts +1012 -0
- package/src/platforms/slackbot/listener.ts +362 -0
- package/src/platforms/slackbot/types.test.ts +7 -7
- package/src/platforms/slackbot/types.ts +224 -1
- package/src/platforms/teams/client.test.ts +30 -30
- package/src/platforms/teams/commands/auth.test.ts +9 -9
- package/src/platforms/teams/commands/auth.ts +66 -7
- 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 +69 -18
- package/src/platforms/teams/ensure-auth.ts +39 -11
- package/src/platforms/teams/index.test.ts +15 -15
- package/src/platforms/teams/token-extractor.test.ts +251 -69
- package/src/platforms/teams/token-extractor.ts +94 -31
- 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/auth.ts +13 -2
- 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/token-extractor.ts +25 -3
- package/src/platforms/webex/types.test.ts +27 -27
- package/src/platforms/wechatbot/cli.ts +9 -0
- package/src/platforms/wechatbot/client.test.ts +27 -27
- package/src/platforms/wechatbot/commands/auth.test.ts +15 -15
- package/src/platforms/wechatbot/commands/auth.ts +1 -5
- package/src/platforms/wechatbot/commands/message.test.ts +8 -8
- package/src/platforms/wechatbot/commands/message.ts +1 -6
- package/src/platforms/wechatbot/commands/template.test.ts +9 -9
- package/src/platforms/wechatbot/commands/template.ts +1 -6
- package/src/platforms/wechatbot/commands/user.test.ts +7 -7
- package/src/platforms/wechatbot/commands/user.ts +1 -6
- package/src/platforms/wechatbot/commands/whoami.test.ts +5 -5
- package/src/platforms/wechatbot/commands/whoami.ts +1 -6
- 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/cli.ts +9 -0
- package/src/platforms/whatsappbot/client.test.ts +27 -27
- package/src/platforms/whatsappbot/commands/auth.test.ts +14 -14
- package/src/platforms/whatsappbot/commands/auth.ts +1 -5
- package/src/platforms/whatsappbot/commands/message.test.ts +16 -16
- package/src/platforms/whatsappbot/commands/message.ts +1 -6
- package/src/platforms/whatsappbot/commands/template.test.ts +9 -9
- package/src/platforms/whatsappbot/commands/template.ts +1 -6
- package/src/platforms/whatsappbot/commands/whoami.test.ts +5 -5
- package/src/platforms/whatsappbot/commands/whoami.ts +1 -6
- 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 +102 -22
- package/src/shared/chromium/browsers.ts +72 -3
- package/src/shared/chromium/cli-options.test.ts +22 -0
- package/src/shared/chromium/cli-options.ts +12 -0
- 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/chromium/index.ts +3 -0
- package/src/shared/utils/cli-output.test.ts +57 -0
- package/src/shared/utils/cli-output.ts +8 -0
- package/src/shared/utils/concurrency.test.ts +6 -6
- package/src/shared/utils/derived-key-cache.test.ts +11 -11
- package/src/tui/app.ts +129 -20
- package/src/tui/utils.test.ts +31 -31
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterEach, describe, expect, mock,
|
|
1
|
+
import { afterEach, describe, expect, mock, it } from 'bun:test'
|
|
2
2
|
|
|
3
3
|
import { DiscordListener } from '@/platforms/discord/listener'
|
|
4
4
|
import type {
|
|
@@ -16,12 +16,16 @@ let mockWsInstance: MockWs
|
|
|
16
16
|
class MockWs {
|
|
17
17
|
static OPEN = 1
|
|
18
18
|
static CLOSED = 3
|
|
19
|
+
static lastUrl: string | null = null
|
|
19
20
|
readyState = MockWs.OPEN
|
|
20
21
|
|
|
21
22
|
private handlers = new Map<string, WsHandler[]>()
|
|
22
23
|
sent: string[] = []
|
|
24
|
+
url: string
|
|
23
25
|
|
|
24
|
-
constructor(
|
|
26
|
+
constructor(url: string, _options?: any) {
|
|
27
|
+
this.url = url
|
|
28
|
+
MockWs.lastUrl = url
|
|
25
29
|
// oxlint-disable-next-line typescript-eslint/no-this-alias
|
|
26
30
|
mockWsInstance = this
|
|
27
31
|
}
|
|
@@ -111,7 +115,7 @@ describe('DiscordListener', () => {
|
|
|
111
115
|
})
|
|
112
116
|
|
|
113
117
|
describe('start', () => {
|
|
114
|
-
|
|
118
|
+
it('calls gatewayConnect and opens WebSocket', async () => {
|
|
115
119
|
const client = createMockClient()
|
|
116
120
|
listener = new DiscordListener(client)
|
|
117
121
|
|
|
@@ -121,7 +125,7 @@ describe('DiscordListener', () => {
|
|
|
121
125
|
expect(client.gatewayConnect).toHaveBeenCalledTimes(1)
|
|
122
126
|
})
|
|
123
127
|
|
|
124
|
-
|
|
128
|
+
it('is idempotent', async () => {
|
|
125
129
|
const client = createMockClient()
|
|
126
130
|
listener = new DiscordListener(client)
|
|
127
131
|
|
|
@@ -133,7 +137,7 @@ describe('DiscordListener', () => {
|
|
|
133
137
|
})
|
|
134
138
|
|
|
135
139
|
describe('connected event', () => {
|
|
136
|
-
|
|
140
|
+
it('emits connected with user/sessionId on READY', async () => {
|
|
137
141
|
const client = createMockClient()
|
|
138
142
|
listener = new DiscordListener(client)
|
|
139
143
|
|
|
@@ -152,7 +156,7 @@ describe('DiscordListener', () => {
|
|
|
152
156
|
})
|
|
153
157
|
|
|
154
158
|
describe('identify', () => {
|
|
155
|
-
|
|
159
|
+
it('sends Identify after Hello', async () => {
|
|
156
160
|
const client = createMockClient()
|
|
157
161
|
listener = new DiscordListener(client)
|
|
158
162
|
|
|
@@ -167,7 +171,7 @@ describe('DiscordListener', () => {
|
|
|
167
171
|
expect(identifyMsg.d.token).toBe('fake-token')
|
|
168
172
|
})
|
|
169
173
|
|
|
170
|
-
|
|
174
|
+
it('sends Identify with custom intents', async () => {
|
|
171
175
|
const client = createMockClient()
|
|
172
176
|
const customIntents = 1 << 9
|
|
173
177
|
listener = new DiscordListener(client, { intents: customIntents })
|
|
@@ -185,7 +189,7 @@ describe('DiscordListener', () => {
|
|
|
185
189
|
})
|
|
186
190
|
|
|
187
191
|
describe('message events', () => {
|
|
188
|
-
|
|
192
|
+
it('emits message_create events', async () => {
|
|
189
193
|
const client = createMockClient()
|
|
190
194
|
listener = new DiscordListener(client)
|
|
191
195
|
|
|
@@ -213,7 +217,7 @@ describe('DiscordListener', () => {
|
|
|
213
217
|
expect(messages[0].channel_id).toBe('C123')
|
|
214
218
|
})
|
|
215
219
|
|
|
216
|
-
|
|
220
|
+
it('emits message_update events', async () => {
|
|
217
221
|
const client = createMockClient()
|
|
218
222
|
listener = new DiscordListener(client)
|
|
219
223
|
|
|
@@ -235,7 +239,7 @@ describe('DiscordListener', () => {
|
|
|
235
239
|
expect(updates[0].content).toBe('edited')
|
|
236
240
|
})
|
|
237
241
|
|
|
238
|
-
|
|
242
|
+
it('emits message_delete events', async () => {
|
|
239
243
|
const client = createMockClient()
|
|
240
244
|
listener = new DiscordListener(client)
|
|
241
245
|
|
|
@@ -254,7 +258,7 @@ describe('DiscordListener', () => {
|
|
|
254
258
|
})
|
|
255
259
|
|
|
256
260
|
describe('reaction events', () => {
|
|
257
|
-
|
|
261
|
+
it('emits message_reaction_add events', async () => {
|
|
258
262
|
const client = createMockClient()
|
|
259
263
|
listener = new DiscordListener(client)
|
|
260
264
|
|
|
@@ -283,7 +287,7 @@ describe('DiscordListener', () => {
|
|
|
283
287
|
})
|
|
284
288
|
|
|
285
289
|
describe('discord_event catch-all', () => {
|
|
286
|
-
|
|
290
|
+
it('emits discord_event for every dispatch (not READY)', async () => {
|
|
287
291
|
const client = createMockClient()
|
|
288
292
|
listener = new DiscordListener(client)
|
|
289
293
|
|
|
@@ -308,7 +312,7 @@ describe('DiscordListener', () => {
|
|
|
308
312
|
})
|
|
309
313
|
|
|
310
314
|
describe('heartbeat', () => {
|
|
311
|
-
|
|
315
|
+
it('sends heartbeat after Hello (with jitter)', async () => {
|
|
312
316
|
const originalRandom = Math.random
|
|
313
317
|
Math.random = () => 0
|
|
314
318
|
|
|
@@ -331,7 +335,7 @@ describe('DiscordListener', () => {
|
|
|
331
335
|
}
|
|
332
336
|
})
|
|
333
337
|
|
|
334
|
-
|
|
338
|
+
it('heartbeat ACK not emitted as user event', async () => {
|
|
335
339
|
const client = createMockClient()
|
|
336
340
|
listener = new DiscordListener(client)
|
|
337
341
|
|
|
@@ -347,7 +351,7 @@ describe('DiscordListener', () => {
|
|
|
347
351
|
expect(events.length).toBe(0)
|
|
348
352
|
})
|
|
349
353
|
|
|
350
|
-
|
|
354
|
+
it('zombie connection triggers reconnect (no ACK received)', async () => {
|
|
351
355
|
const originalRandom = Math.random
|
|
352
356
|
Math.random = () => 0
|
|
353
357
|
|
|
@@ -372,7 +376,7 @@ describe('DiscordListener', () => {
|
|
|
372
376
|
})
|
|
373
377
|
|
|
374
378
|
describe('stop', () => {
|
|
375
|
-
|
|
379
|
+
it('closes WebSocket and prevents reconnection', async () => {
|
|
376
380
|
const client = createMockClient()
|
|
377
381
|
listener = new DiscordListener(client)
|
|
378
382
|
|
|
@@ -387,7 +391,7 @@ describe('DiscordListener', () => {
|
|
|
387
391
|
})
|
|
388
392
|
|
|
389
393
|
describe('reconnection', () => {
|
|
390
|
-
|
|
394
|
+
it('reconnects on WebSocket close when running', async () => {
|
|
391
395
|
const client = createMockClient()
|
|
392
396
|
listener = new DiscordListener(client)
|
|
393
397
|
|
|
@@ -404,7 +408,7 @@ describe('DiscordListener', () => {
|
|
|
404
408
|
expect(client.gatewayConnect.mock.calls.length).toBeGreaterThanOrEqual(2)
|
|
405
409
|
})
|
|
406
410
|
|
|
407
|
-
|
|
411
|
+
it('emits error and reconnects on gatewayConnect failure', async () => {
|
|
408
412
|
let callCount = 0
|
|
409
413
|
const client = createMockClient({
|
|
410
414
|
gatewayConnect: mock(() => {
|
|
@@ -430,7 +434,7 @@ describe('DiscordListener', () => {
|
|
|
430
434
|
})
|
|
431
435
|
|
|
432
436
|
describe('on/off/once', () => {
|
|
433
|
-
|
|
437
|
+
it('off removes listener', async () => {
|
|
434
438
|
const client = createMockClient()
|
|
435
439
|
listener = new DiscordListener(client)
|
|
436
440
|
|
|
@@ -459,7 +463,7 @@ describe('DiscordListener', () => {
|
|
|
459
463
|
expect(messages[0].content).toBe('a')
|
|
460
464
|
})
|
|
461
465
|
|
|
462
|
-
|
|
466
|
+
it('once fires only once', async () => {
|
|
463
467
|
const client = createMockClient()
|
|
464
468
|
listener = new DiscordListener(client)
|
|
465
469
|
|
|
@@ -487,7 +491,7 @@ describe('DiscordListener', () => {
|
|
|
487
491
|
})
|
|
488
492
|
|
|
489
493
|
describe('opcode 7 Reconnect', () => {
|
|
490
|
-
|
|
494
|
+
it('triggers immediate reconnect without backoff', async () => {
|
|
491
495
|
const client = createMockClient()
|
|
492
496
|
listener = new DiscordListener(client)
|
|
493
497
|
|
|
@@ -504,7 +508,7 @@ describe('DiscordListener', () => {
|
|
|
504
508
|
})
|
|
505
509
|
|
|
506
510
|
describe('opcode 9 InvalidSession', () => {
|
|
507
|
-
|
|
511
|
+
it('d=false clears session state, reconnects with fresh identify', async () => {
|
|
508
512
|
const client = createMockClient()
|
|
509
513
|
listener = new DiscordListener(client)
|
|
510
514
|
|
|
@@ -522,7 +526,7 @@ describe('DiscordListener', () => {
|
|
|
522
526
|
expect((listener as any).resumeGatewayUrl).toBeNull()
|
|
523
527
|
})
|
|
524
528
|
|
|
525
|
-
|
|
529
|
+
it('d=true allows resume on reconnect', async () => {
|
|
526
530
|
const client = createMockClient()
|
|
527
531
|
listener = new DiscordListener(client)
|
|
528
532
|
|
|
@@ -540,7 +544,7 @@ describe('DiscordListener', () => {
|
|
|
540
544
|
})
|
|
541
545
|
|
|
542
546
|
describe('resume', () => {
|
|
543
|
-
|
|
547
|
+
it('sends Resume instead of Identify when session exists', async () => {
|
|
544
548
|
const client = createMockClient()
|
|
545
549
|
listener = new DiscordListener(client)
|
|
546
550
|
|
|
@@ -565,7 +569,7 @@ describe('DiscordListener', () => {
|
|
|
565
569
|
})
|
|
566
570
|
|
|
567
571
|
describe('non-recoverable close codes', () => {
|
|
568
|
-
|
|
572
|
+
it('emits error and stops on code 4004', async () => {
|
|
569
573
|
const client = createMockClient()
|
|
570
574
|
listener = new DiscordListener(client)
|
|
571
575
|
|
|
@@ -585,7 +589,7 @@ describe('DiscordListener', () => {
|
|
|
585
589
|
})
|
|
586
590
|
|
|
587
591
|
describe('session reset close codes', () => {
|
|
588
|
-
|
|
592
|
+
it('4007 clears session and reconnects with fresh identify', async () => {
|
|
589
593
|
const client = createMockClient()
|
|
590
594
|
listener = new DiscordListener(client)
|
|
591
595
|
|
|
@@ -615,7 +619,7 @@ describe('DiscordListener', () => {
|
|
|
615
619
|
expect(resumeMsg).toBeUndefined()
|
|
616
620
|
})
|
|
617
621
|
|
|
618
|
-
|
|
622
|
+
it('4009 clears session and reconnects with fresh identify', async () => {
|
|
619
623
|
const client = createMockClient()
|
|
620
624
|
listener = new DiscordListener(client)
|
|
621
625
|
|
|
@@ -631,7 +635,7 @@ describe('DiscordListener', () => {
|
|
|
631
635
|
})
|
|
632
636
|
|
|
633
637
|
describe('duplicate Hello', () => {
|
|
634
|
-
|
|
638
|
+
it('does not stack heartbeat timers on second Hello', async () => {
|
|
635
639
|
const originalRandom = Math.random
|
|
636
640
|
Math.random = () => 0
|
|
637
641
|
|
|
@@ -659,7 +663,7 @@ describe('DiscordListener', () => {
|
|
|
659
663
|
})
|
|
660
664
|
|
|
661
665
|
describe('InvalidSession timer safety', () => {
|
|
662
|
-
|
|
666
|
+
it('stop cancels pending InvalidSession d=true timeout', async () => {
|
|
663
667
|
const originalRandom = Math.random
|
|
664
668
|
Math.random = () => 0
|
|
665
669
|
|
|
@@ -682,7 +686,7 @@ describe('DiscordListener', () => {
|
|
|
682
686
|
}
|
|
683
687
|
})
|
|
684
688
|
|
|
685
|
-
|
|
689
|
+
it('InvalidSession d=false sends fresh identify on reconnect', async () => {
|
|
686
690
|
const client = createMockClient()
|
|
687
691
|
listener = new DiscordListener(client)
|
|
688
692
|
|
|
@@ -708,7 +712,7 @@ describe('DiscordListener', () => {
|
|
|
708
712
|
})
|
|
709
713
|
|
|
710
714
|
describe('server-requested heartbeat', () => {
|
|
711
|
-
|
|
715
|
+
it('responds to opcode 1 with heartbeat', async () => {
|
|
712
716
|
const client = createMockClient()
|
|
713
717
|
listener = new DiscordListener(client)
|
|
714
718
|
|
|
@@ -728,7 +732,7 @@ describe('DiscordListener', () => {
|
|
|
728
732
|
})
|
|
729
733
|
|
|
730
734
|
describe('sequence tracking', () => {
|
|
731
|
-
|
|
735
|
+
it('tracks sequence from dispatch events', async () => {
|
|
732
736
|
const client = createMockClient()
|
|
733
737
|
listener = new DiscordListener(client)
|
|
734
738
|
|
|
@@ -746,7 +750,7 @@ describe('DiscordListener', () => {
|
|
|
746
750
|
expect((listener as any).sequence).toBe(5)
|
|
747
751
|
})
|
|
748
752
|
|
|
749
|
-
|
|
753
|
+
it('ignores null sequence values', async () => {
|
|
750
754
|
const client = createMockClient()
|
|
751
755
|
listener = new DiscordListener(client)
|
|
752
756
|
|
|
@@ -773,7 +777,7 @@ describe('DiscordListener', () => {
|
|
|
773
777
|
})
|
|
774
778
|
|
|
775
779
|
describe('start after stop', () => {
|
|
776
|
-
|
|
780
|
+
it('resets reconnect attempts on fresh start', async () => {
|
|
777
781
|
const client = createMockClient()
|
|
778
782
|
listener = new DiscordListener(client)
|
|
779
783
|
|
|
@@ -785,4 +789,58 @@ describe('DiscordListener', () => {
|
|
|
785
789
|
expect((listener as any).reconnectAttempts).toBe(0)
|
|
786
790
|
})
|
|
787
791
|
})
|
|
792
|
+
|
|
793
|
+
describe('reconnect URL', () => {
|
|
794
|
+
it('appends ?v=10&encoding=json to resume_gateway_url on reconnect', async () => {
|
|
795
|
+
const client = createMockClient()
|
|
796
|
+
listener = new DiscordListener(client)
|
|
797
|
+
|
|
798
|
+
await listener.start()
|
|
799
|
+
mockWsInstance.simulateOpen()
|
|
800
|
+
mockWsInstance.simulateHello()
|
|
801
|
+
mockWsInstance.simulateMessage({
|
|
802
|
+
op: 0,
|
|
803
|
+
t: 'READY',
|
|
804
|
+
s: 1,
|
|
805
|
+
d: {
|
|
806
|
+
session_id: 'session_xyz',
|
|
807
|
+
resume_gateway_url: 'wss://gateway-us-east1-b.discord.gg',
|
|
808
|
+
user: { id: 'U_SELF', username: 'user' },
|
|
809
|
+
},
|
|
810
|
+
})
|
|
811
|
+
|
|
812
|
+
mockWsInstance.simulateClose()
|
|
813
|
+
await new Promise((r) => setTimeout(r, 1500))
|
|
814
|
+
|
|
815
|
+
expect(MockWs.lastUrl).toBe('wss://gateway-us-east1-b.discord.gg?v=10&encoding=json')
|
|
816
|
+
})
|
|
817
|
+
})
|
|
818
|
+
|
|
819
|
+
describe('reconnectAttempts deferred to READY/RESUMED', () => {
|
|
820
|
+
it('does not reset reconnectAttempts on socket open alone', async () => {
|
|
821
|
+
const client = createMockClient()
|
|
822
|
+
listener = new DiscordListener(client)
|
|
823
|
+
|
|
824
|
+
await listener.start()
|
|
825
|
+
;(listener as any).reconnectAttempts = 5
|
|
826
|
+
|
|
827
|
+
mockWsInstance.simulateOpen()
|
|
828
|
+
|
|
829
|
+
expect((listener as any).reconnectAttempts).toBe(5)
|
|
830
|
+
})
|
|
831
|
+
|
|
832
|
+
it('resets reconnectAttempts on READY dispatch', async () => {
|
|
833
|
+
const client = createMockClient()
|
|
834
|
+
listener = new DiscordListener(client)
|
|
835
|
+
|
|
836
|
+
await listener.start()
|
|
837
|
+
;(listener as any).reconnectAttempts = 5
|
|
838
|
+
|
|
839
|
+
mockWsInstance.simulateOpen()
|
|
840
|
+
mockWsInstance.simulateHello()
|
|
841
|
+
mockWsInstance.simulateReady()
|
|
842
|
+
|
|
843
|
+
expect((listener as any).reconnectAttempts).toBe(0)
|
|
844
|
+
})
|
|
845
|
+
})
|
|
788
846
|
})
|
|
@@ -7,6 +7,7 @@ import type { DiscordListenerEventMap, DiscordGatewayGenericEvent } from './type
|
|
|
7
7
|
import { DiscordGatewayOpcode, DiscordIntent } from './types'
|
|
8
8
|
|
|
9
9
|
const GATEWAY_URL = 'wss://gateway.discord.gg/?v=10&encoding=json'
|
|
10
|
+
const GATEWAY_QUERY = '?v=10&encoding=json'
|
|
10
11
|
const RECONNECT_BASE_DELAY = 1_000
|
|
11
12
|
const RECONNECT_MAX_DELAY = 30_000
|
|
12
13
|
const NON_RECOVERABLE_CLOSE_CODES = [4004, 4010, 4011, 4012, 4013, 4014]
|
|
@@ -40,6 +41,7 @@ export class DiscordListener {
|
|
|
40
41
|
private resumeGatewayUrl: string | null = null
|
|
41
42
|
private token: string | null = null
|
|
42
43
|
private cachedUser: { id: string; username: string } | null = null
|
|
44
|
+
private generation = 0
|
|
43
45
|
|
|
44
46
|
constructor(client: DiscordClient, options?: { intents?: number }) {
|
|
45
47
|
this.client = client
|
|
@@ -50,11 +52,13 @@ export class DiscordListener {
|
|
|
50
52
|
if (this.running) return
|
|
51
53
|
this.running = true
|
|
52
54
|
this.reconnectAttempts = 0
|
|
53
|
-
|
|
55
|
+
this.generation++
|
|
56
|
+
await this.connect(this.generation)
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
stop(): void {
|
|
57
60
|
this.running = false
|
|
61
|
+
this.generation++
|
|
58
62
|
this.clearTimers()
|
|
59
63
|
if (this.ws) {
|
|
60
64
|
this.ws.close()
|
|
@@ -82,39 +86,46 @@ export class DiscordListener {
|
|
|
82
86
|
return this
|
|
83
87
|
}
|
|
84
88
|
|
|
85
|
-
private
|
|
86
|
-
if (!this.running) return
|
|
89
|
+
private isCurrent(generation: number, ws?: WebSocket): boolean {
|
|
90
|
+
if (generation !== this.generation || !this.running) return false
|
|
91
|
+
if (ws !== undefined && this.ws !== ws) return false
|
|
92
|
+
return true
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private async connect(generation: number): Promise<void> {
|
|
96
|
+
if (!this.isCurrent(generation)) return
|
|
87
97
|
|
|
88
98
|
try {
|
|
89
99
|
const { token } = await this.client.gatewayConnect()
|
|
90
|
-
if (!this.
|
|
100
|
+
if (!this.isCurrent(generation)) return
|
|
91
101
|
|
|
92
102
|
this.token = token
|
|
93
103
|
|
|
94
|
-
const url = this.resumeGatewayUrl
|
|
104
|
+
const url = this.resumeGatewayUrl ? `${this.resumeGatewayUrl}${GATEWAY_QUERY}` : GATEWAY_URL
|
|
95
105
|
const ws = new WebSocket(url)
|
|
96
106
|
this.ws = ws
|
|
97
107
|
|
|
98
108
|
ws.on('open', () => {
|
|
99
|
-
if (!this.
|
|
109
|
+
if (!this.isCurrent(generation, ws)) {
|
|
100
110
|
ws.close()
|
|
101
111
|
return
|
|
102
112
|
}
|
|
103
|
-
this.reconnectAttempts = 0
|
|
104
113
|
})
|
|
105
114
|
|
|
106
115
|
ws.on('message', (raw) => {
|
|
116
|
+
if (!this.isCurrent(generation, ws)) return
|
|
107
117
|
try {
|
|
108
118
|
const data = JSON.parse(raw.toString())
|
|
109
|
-
this.handleMessage(data)
|
|
119
|
+
this.handleMessage(data, generation, ws)
|
|
110
120
|
} catch {
|
|
111
|
-
// malformed
|
|
121
|
+
// malformed gateway frame; ignore and let heartbeat handle liveness
|
|
112
122
|
}
|
|
113
123
|
})
|
|
114
124
|
|
|
115
125
|
ws.on('close', (code) => {
|
|
126
|
+
if (!this.isCurrent(generation, ws)) return
|
|
116
127
|
this.clearTimers()
|
|
117
|
-
|
|
128
|
+
this.ws = null
|
|
118
129
|
if (NON_RECOVERABLE_CLOSE_CODES.includes(code)) {
|
|
119
130
|
this.emitter.emit('error', new Error(`Discord gateway closed with non-recoverable code ${code}`))
|
|
120
131
|
this.running = false
|
|
@@ -132,9 +143,11 @@ export class DiscordListener {
|
|
|
132
143
|
})
|
|
133
144
|
|
|
134
145
|
ws.on('error', (err) => {
|
|
146
|
+
if (!this.isCurrent(generation, ws)) return
|
|
135
147
|
this.emitter.emit('error', err instanceof Error ? err : new Error(String(err)))
|
|
136
148
|
})
|
|
137
149
|
} catch (error) {
|
|
150
|
+
if (!this.isCurrent(generation)) return
|
|
138
151
|
this.emitter.emit('error', error instanceof Error ? error : new Error(String(error)))
|
|
139
152
|
if (this.running) {
|
|
140
153
|
this.scheduleReconnect()
|
|
@@ -142,12 +155,13 @@ export class DiscordListener {
|
|
|
142
155
|
}
|
|
143
156
|
}
|
|
144
157
|
|
|
145
|
-
private handleMessage(data: { op: number; d: any; s?: number; t?: string }): void {
|
|
158
|
+
private handleMessage(data: { op: number; d: any; s?: number; t?: string }, generation: number, ws: WebSocket): void {
|
|
159
|
+
if (!this.isCurrent(generation, ws)) return
|
|
146
160
|
const { op, d, s, t } = data
|
|
147
161
|
|
|
148
162
|
switch (op) {
|
|
149
163
|
case DiscordGatewayOpcode.Hello:
|
|
150
|
-
this.startHeartbeat(d.heartbeat_interval)
|
|
164
|
+
this.startHeartbeat(d.heartbeat_interval, generation, ws)
|
|
151
165
|
if (this.sessionId) {
|
|
152
166
|
this.sendResume()
|
|
153
167
|
} else {
|
|
@@ -166,22 +180,21 @@ export class DiscordListener {
|
|
|
166
180
|
|
|
167
181
|
case DiscordGatewayOpcode.Reconnect:
|
|
168
182
|
this.reconnectAttempts = 0
|
|
169
|
-
|
|
183
|
+
ws.close()
|
|
170
184
|
break
|
|
171
185
|
|
|
172
186
|
case DiscordGatewayOpcode.InvalidSession: {
|
|
173
|
-
const currentWs = this.ws
|
|
174
187
|
if (d === true) {
|
|
175
188
|
const delay = 1000 + Math.random() * 4000
|
|
176
189
|
this.invalidSessionTimer = setTimeout(() => {
|
|
177
190
|
this.invalidSessionTimer = null
|
|
178
|
-
if (
|
|
191
|
+
if (this.isCurrent(generation, ws)) ws.close()
|
|
179
192
|
}, delay)
|
|
180
193
|
} else {
|
|
181
194
|
this.sequence = null
|
|
182
195
|
this.sessionId = null
|
|
183
196
|
this.resumeGatewayUrl = null
|
|
184
|
-
|
|
197
|
+
ws.close()
|
|
185
198
|
}
|
|
186
199
|
break
|
|
187
200
|
}
|
|
@@ -197,11 +210,13 @@ export class DiscordListener {
|
|
|
197
210
|
this.sessionId = d.session_id
|
|
198
211
|
this.resumeGatewayUrl = d.resume_gateway_url
|
|
199
212
|
this.cachedUser = d.user
|
|
213
|
+
this.reconnectAttempts = 0
|
|
200
214
|
this.emitter.emit('connected', { user: d.user, sessionId: d.session_id })
|
|
201
215
|
return
|
|
202
216
|
}
|
|
203
217
|
|
|
204
218
|
if (t === 'RESUMED') {
|
|
219
|
+
this.reconnectAttempts = 0
|
|
205
220
|
this.emitter.emit('connected', { user: this.cachedUser!, sessionId: this.sessionId! })
|
|
206
221
|
return
|
|
207
222
|
}
|
|
@@ -246,18 +261,23 @@ export class DiscordListener {
|
|
|
246
261
|
this.ws?.send(JSON.stringify({ op: DiscordGatewayOpcode.Heartbeat, d: this.sequence }))
|
|
247
262
|
}
|
|
248
263
|
|
|
249
|
-
private startHeartbeat(interval: number): void {
|
|
264
|
+
private startHeartbeat(interval: number, generation: number, ws: WebSocket): void {
|
|
250
265
|
this.clearHeartbeatTimers()
|
|
251
266
|
this.heartbeatAckReceived = true
|
|
252
267
|
|
|
253
268
|
this.heartbeatJitterTimer = setTimeout(() => {
|
|
254
269
|
this.heartbeatJitterTimer = null
|
|
270
|
+
if (!this.isCurrent(generation, ws)) return
|
|
255
271
|
this.heartbeatAckReceived = false
|
|
256
272
|
this.sendHeartbeat()
|
|
257
273
|
|
|
258
274
|
this.heartbeatTimer = setInterval(() => {
|
|
275
|
+
if (!this.isCurrent(generation, ws)) {
|
|
276
|
+
this.clearHeartbeatTimers()
|
|
277
|
+
return
|
|
278
|
+
}
|
|
259
279
|
if (!this.heartbeatAckReceived) {
|
|
260
|
-
|
|
280
|
+
ws.close()
|
|
261
281
|
return
|
|
262
282
|
}
|
|
263
283
|
this.heartbeatAckReceived = false
|
|
@@ -269,7 +289,11 @@ export class DiscordListener {
|
|
|
269
289
|
private scheduleReconnect(): void {
|
|
270
290
|
const delay = Math.min(RECONNECT_BASE_DELAY * 2 ** this.reconnectAttempts, RECONNECT_MAX_DELAY)
|
|
271
291
|
this.reconnectAttempts++
|
|
272
|
-
|
|
292
|
+
const generation = this.generation
|
|
293
|
+
this.reconnectTimer = setTimeout(() => {
|
|
294
|
+
this.reconnectTimer = null
|
|
295
|
+
this.connect(generation)
|
|
296
|
+
}, delay)
|
|
273
297
|
}
|
|
274
298
|
|
|
275
299
|
private clearHeartbeatTimers(): void {
|