agent-messenger 2.10.1 → 2.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/package.json +1 -1
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/teams/token-extractor.js +9 -2
- package/dist/src/platforms/teams/token-extractor.js.map +1 -1
- package/dist/src/shared/chromium/decryptor.d.ts +6 -0
- package/dist/src/shared/chromium/decryptor.d.ts.map +1 -1
- package/dist/src/shared/chromium/decryptor.js +26 -6
- package/dist/src/shared/chromium/decryptor.js.map +1 -1
- package/e2e/channeltalk.e2e.test.ts +13 -13
- package/e2e/channeltalkbot.e2e.test.ts +13 -13
- package/e2e/discord.e2e.test.ts +24 -24
- package/e2e/discordbot.e2e.test.ts +16 -16
- package/e2e/instagram.e2e.test.ts +10 -10
- package/e2e/kakaotalk.e2e.test.ts +7 -7
- package/e2e/line.e2e.test.ts +8 -8
- package/e2e/slack.e2e.test.ts +34 -34
- package/e2e/slackbot.e2e.test.ts +14 -14
- package/e2e/teams.e2e.test.ts +23 -23
- package/e2e/telegram.e2e.test.ts +8 -8
- package/e2e/webex.e2e.test.ts +14 -14
- package/e2e/whatsapp.e2e.test.ts +8 -8
- package/e2e/whatsappbot.e2e.test.ts +6 -6
- package/package.json +1 -1
- package/skills/agent-channeltalk/SKILL.md +1 -1
- package/skills/agent-channeltalkbot/SKILL.md +1 -1
- package/skills/agent-discord/SKILL.md +1 -1
- package/skills/agent-discordbot/SKILL.md +1 -1
- package/skills/agent-instagram/SKILL.md +1 -1
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +1 -1
- package/skills/agent-slackbot/SKILL.md +1 -1
- package/skills/agent-teams/SKILL.md +1 -1
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +1 -1
- package/skills/agent-wechatbot/SKILL.md +1 -1
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +1 -1
- package/src/platforms/channeltalk/client.test.ts +26 -26
- package/src/platforms/channeltalk/commands/auth.test.ts +16 -16
- package/src/platforms/channeltalk/commands/bot.test.ts +2 -2
- package/src/platforms/channeltalk/commands/chat.test.ts +3 -3
- package/src/platforms/channeltalk/commands/group.test.ts +4 -4
- package/src/platforms/channeltalk/commands/manager.test.ts +2 -2
- package/src/platforms/channeltalk/commands/message.test.ts +17 -17
- package/src/platforms/channeltalk/commands/snapshot.test.ts +7 -7
- package/src/platforms/channeltalk/commands/whoami.test.ts +3 -3
- package/src/platforms/channeltalk/credential-manager.test.ts +18 -18
- package/src/platforms/channeltalk/ensure-auth.test.ts +5 -5
- package/src/platforms/channeltalk/index.test.ts +23 -23
- package/src/platforms/channeltalk/token-extractor.test.ts +21 -21
- package/src/platforms/channeltalk/types.test.ts +12 -12
- package/src/platforms/channeltalkbot/client.test.ts +14 -14
- package/src/platforms/channeltalkbot/commands/auth.test.ts +16 -16
- package/src/platforms/channeltalkbot/commands/bot.test.ts +6 -6
- package/src/platforms/channeltalkbot/commands/chat.test.ts +9 -9
- package/src/platforms/channeltalkbot/commands/group.test.ts +6 -6
- package/src/platforms/channeltalkbot/commands/manager.test.ts +3 -3
- package/src/platforms/channeltalkbot/commands/message.test.ts +10 -10
- package/src/platforms/channeltalkbot/commands/snapshot.test.ts +7 -7
- package/src/platforms/channeltalkbot/commands/whoami.test.ts +4 -4
- package/src/platforms/channeltalkbot/credential-manager.test.ts +27 -27
- package/src/platforms/channeltalkbot/index.test.ts +15 -15
- package/src/platforms/discord/client.test.ts +28 -28
- package/src/platforms/discord/commands/auth.test.ts +7 -7
- package/src/platforms/discord/commands/channel.test.ts +7 -7
- package/src/platforms/discord/commands/dm.test.ts +4 -4
- package/src/platforms/discord/commands/file.test.ts +4 -4
- package/src/platforms/discord/commands/friend.test.ts +6 -6
- package/src/platforms/discord/commands/member.test.ts +5 -5
- package/src/platforms/discord/commands/mention.test.ts +5 -5
- package/src/platforms/discord/commands/message.test.ts +9 -9
- package/src/platforms/discord/commands/note.test.ts +6 -6
- package/src/platforms/discord/commands/profile.test.ts +4 -4
- package/src/platforms/discord/commands/reaction.test.ts +5 -5
- package/src/platforms/discord/commands/server.test.ts +7 -7
- package/src/platforms/discord/commands/snapshot.test.ts +6 -6
- package/src/platforms/discord/commands/thread.test.ts +6 -6
- package/src/platforms/discord/commands/user.test.ts +5 -5
- package/src/platforms/discord/commands/whoami.test.ts +6 -6
- package/src/platforms/discord/credential-manager.test.ts +16 -16
- package/src/platforms/discord/ensure-auth.test.ts +8 -8
- package/src/platforms/discord/index.test.ts +17 -17
- package/src/platforms/discord/listener.test.ts +33 -33
- package/src/platforms/discord/token-extractor.test.ts +53 -53
- package/src/platforms/discord/types.test.ts +26 -26
- package/src/platforms/discordbot/client.test.ts +31 -31
- package/src/platforms/discordbot/commands/auth.test.ts +18 -18
- package/src/platforms/discordbot/commands/channel.test.ts +11 -11
- package/src/platforms/discordbot/commands/file.test.ts +7 -7
- package/src/platforms/discordbot/commands/message.test.ts +25 -25
- package/src/platforms/discordbot/commands/reaction.test.ts +6 -6
- package/src/platforms/discordbot/commands/server.test.ts +12 -12
- package/src/platforms/discordbot/commands/snapshot.test.ts +13 -13
- package/src/platforms/discordbot/commands/thread.test.ts +10 -10
- package/src/platforms/discordbot/commands/user.test.ts +9 -9
- package/src/platforms/discordbot/commands/whoami.test.ts +4 -4
- package/src/platforms/discordbot/credential-manager.test.ts +28 -28
- package/src/platforms/instagram/client.test.ts +18 -18
- package/src/platforms/instagram/commands/auth.test.ts +11 -11
- package/src/platforms/instagram/commands/chat.test.ts +6 -6
- package/src/platforms/instagram/commands/message.test.ts +11 -11
- package/src/platforms/instagram/commands/shared.test.ts +12 -12
- package/src/platforms/instagram/commands/whoami.test.ts +3 -3
- package/src/platforms/instagram/credential-manager.test.ts +21 -21
- package/src/platforms/instagram/ensure-auth.test.ts +4 -4
- package/src/platforms/instagram/index.test.ts +9 -9
- package/src/platforms/instagram/listener.test.ts +8 -8
- package/src/platforms/instagram/token-extractor.test.ts +35 -35
- package/src/platforms/kakaotalk/client.test.ts +33 -33
- package/src/platforms/kakaotalk/commands/auth.test.ts +11 -11
- package/src/platforms/kakaotalk/commands/chat.test.ts +6 -6
- package/src/platforms/kakaotalk/commands/message.test.ts +7 -7
- package/src/platforms/kakaotalk/commands/whoami.test.ts +5 -5
- package/src/platforms/kakaotalk/credential-manager.test.ts +15 -15
- package/src/platforms/kakaotalk/index.test.ts +15 -15
- package/src/platforms/kakaotalk/listener.test.ts +17 -17
- package/src/platforms/line/client.test.ts +17 -17
- package/src/platforms/line/commands/auth.test.ts +8 -8
- package/src/platforms/line/commands/chat.test.ts +7 -7
- package/src/platforms/line/commands/friend.test.ts +6 -6
- package/src/platforms/line/commands/message.test.ts +7 -7
- package/src/platforms/line/commands/whoami.test.ts +6 -6
- package/src/platforms/line/credential-manager.test.ts +17 -17
- package/src/platforms/line/index.test.ts +10 -10
- package/src/platforms/line/listener.test.ts +15 -15
- package/src/platforms/line/types.test.ts +14 -14
- package/src/platforms/slack/cli.test.ts +8 -8
- package/src/platforms/slack/client.test.ts +151 -151
- package/src/platforms/slack/commands/activity.test.ts +13 -13
- package/src/platforms/slack/commands/auth.test.ts +34 -34
- package/src/platforms/slack/commands/bookmark.test.ts +9 -9
- package/src/platforms/slack/commands/channel.test.ts +17 -17
- package/src/platforms/slack/commands/drafts.test.ts +7 -7
- package/src/platforms/slack/commands/emoji.test.ts +3 -3
- package/src/platforms/slack/commands/file.test.ts +12 -12
- package/src/platforms/slack/commands/message.test.ts +19 -19
- package/src/platforms/slack/commands/pin.test.ts +7 -7
- package/src/platforms/slack/commands/reaction.test.ts +10 -10
- package/src/platforms/slack/commands/reminder.test.ts +9 -9
- package/src/platforms/slack/commands/saved.test.ts +7 -7
- package/src/platforms/slack/commands/sections.test.ts +5 -5
- package/src/platforms/slack/commands/snapshot.test.ts +13 -13
- package/src/platforms/slack/commands/unread.test.ts +6 -6
- package/src/platforms/slack/commands/user.test.ts +10 -10
- package/src/platforms/slack/commands/usergroup.test.ts +15 -15
- package/src/platforms/slack/commands/whoami.test.ts +6 -6
- package/src/platforms/slack/commands/workspace.test.ts +26 -26
- package/src/platforms/slack/credential-manager.test.ts +14 -14
- package/src/platforms/slack/ensure-auth.test.ts +21 -21
- package/src/platforms/slack/index.test.ts +12 -12
- package/src/platforms/slack/listener.test.ts +17 -17
- package/src/platforms/slack/token-extractor-node.test.ts +2 -2
- package/src/platforms/slack/token-extractor.test.ts +37 -37
- package/src/platforms/slack/types.test.ts +21 -21
- package/src/platforms/slackbot/client.test.ts +22 -22
- package/src/platforms/slackbot/commands/auth.test.ts +14 -14
- package/src/platforms/slackbot/commands/channel.test.ts +7 -7
- package/src/platforms/slackbot/commands/message.test.ts +13 -13
- package/src/platforms/slackbot/commands/reaction.test.ts +6 -6
- package/src/platforms/slackbot/commands/user.test.ts +7 -7
- package/src/platforms/slackbot/commands/whoami.test.ts +4 -4
- package/src/platforms/slackbot/credential-manager.test.ts +22 -22
- package/src/platforms/slackbot/types.test.ts +7 -7
- package/src/platforms/teams/client.test.ts +30 -30
- package/src/platforms/teams/commands/auth.test.ts +8 -8
- package/src/platforms/teams/commands/channel.test.ts +7 -7
- package/src/platforms/teams/commands/file.test.ts +4 -4
- package/src/platforms/teams/commands/message.test.ts +5 -5
- package/src/platforms/teams/commands/reaction.test.ts +4 -4
- package/src/platforms/teams/commands/snapshot.test.ts +7 -7
- package/src/platforms/teams/commands/team.test.ts +8 -8
- package/src/platforms/teams/commands/user.test.ts +4 -4
- package/src/platforms/teams/commands/whoami.test.ts +6 -6
- package/src/platforms/teams/credential-manager.test.ts +17 -17
- package/src/platforms/teams/ensure-auth.test.ts +13 -13
- package/src/platforms/teams/index.test.ts +15 -15
- package/src/platforms/teams/token-extractor.test.ts +109 -49
- package/src/platforms/teams/token-extractor.ts +7 -2
- package/src/platforms/teams/types.test.ts +26 -26
- package/src/platforms/telegram/app-config.test.ts +4 -4
- package/src/platforms/telegram/chat-utils.test.ts +12 -12
- package/src/platforms/telegram/client.test.ts +4 -4
- package/src/platforms/telegram/commands/auth.test.ts +16 -16
- package/src/platforms/telegram/commands/chat.test.ts +9 -9
- package/src/platforms/telegram/commands/message.test.ts +6 -6
- package/src/platforms/telegram/commands/shared.test.ts +3 -3
- package/src/platforms/telegram/commands/whoami.test.ts +3 -3
- package/src/platforms/telegram/credential-manager.test.ts +10 -10
- package/src/platforms/telegram/types.test.ts +6 -6
- package/src/platforms/webex/app-config.test.ts +8 -8
- package/src/platforms/webex/cli.test.ts +5 -5
- package/src/platforms/webex/client.test.ts +65 -65
- package/src/platforms/webex/commands/auth.test.ts +18 -18
- package/src/platforms/webex/commands/member.test.ts +5 -5
- package/src/platforms/webex/commands/message.test.ts +12 -12
- package/src/platforms/webex/commands/snapshot.test.ts +5 -5
- package/src/platforms/webex/commands/space.test.ts +10 -10
- package/src/platforms/webex/commands/whoami.test.ts +6 -6
- package/src/platforms/webex/credential-manager.test.ts +22 -22
- package/src/platforms/webex/encryption.test.ts +4 -4
- package/src/platforms/webex/ensure-auth.test.ts +5 -5
- package/src/platforms/webex/index.test.ts +5 -5
- package/src/platforms/webex/markdown-to-html.test.ts +33 -33
- package/src/platforms/webex/token-extractor.test.ts +23 -23
- package/src/platforms/webex/types.test.ts +27 -27
- package/src/platforms/wechatbot/client.test.ts +27 -27
- package/src/platforms/wechatbot/commands/auth.test.ts +15 -15
- package/src/platforms/wechatbot/commands/message.test.ts +8 -8
- package/src/platforms/wechatbot/commands/template.test.ts +9 -9
- package/src/platforms/wechatbot/commands/user.test.ts +7 -7
- package/src/platforms/wechatbot/commands/whoami.test.ts +5 -5
- package/src/platforms/wechatbot/credential-manager.test.ts +18 -18
- package/src/platforms/wechatbot/index.test.ts +10 -10
- package/src/platforms/wechatbot/types.test.ts +25 -25
- package/src/platforms/whatsapp/commands/auth.test.ts +13 -13
- package/src/platforms/whatsapp/commands/chat.test.ts +8 -8
- package/src/platforms/whatsapp/commands/message.test.ts +10 -10
- package/src/platforms/whatsapp/commands/whoami.test.ts +3 -3
- package/src/platforms/whatsapp/credential-manager.test.ts +23 -23
- package/src/platforms/whatsapp/ensure-auth.test.ts +4 -4
- package/src/platforms/whatsapp/index.test.ts +8 -8
- package/src/platforms/whatsapp/types.test.ts +42 -42
- package/src/platforms/whatsappbot/client.test.ts +27 -27
- package/src/platforms/whatsappbot/commands/auth.test.ts +14 -14
- package/src/platforms/whatsappbot/commands/message.test.ts +16 -16
- package/src/platforms/whatsappbot/commands/template.test.ts +9 -9
- package/src/platforms/whatsappbot/commands/whoami.test.ts +5 -5
- package/src/platforms/whatsappbot/credential-manager.test.ts +18 -18
- package/src/platforms/whatsappbot/index.test.ts +7 -7
- package/src/platforms/whatsappbot/types.test.ts +18 -18
- package/src/shared/chromium/browsers.test.ts +22 -22
- package/src/shared/chromium/cookie-reader.test.ts +13 -13
- package/src/shared/chromium/decryptor.test.ts +97 -32
- package/src/shared/chromium/decryptor.ts +27 -6
- package/src/shared/utils/concurrency.test.ts +6 -6
- package/src/shared/utils/derived-key-cache.test.ts +11 -11
- package/src/tui/utils.test.ts +31 -31
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, mock, spyOn,
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, mock, spyOn, it } from 'bun:test'
|
|
2
2
|
import { homedir } from 'node:os'
|
|
3
3
|
import { join } from 'node:path'
|
|
4
4
|
|
|
@@ -21,7 +21,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
21
21
|
})
|
|
22
22
|
|
|
23
23
|
describe('getDiscordDirs', () => {
|
|
24
|
-
|
|
24
|
+
it('returns darwin paths on macOS', () => {
|
|
25
25
|
const darwinExtractor = new DiscordTokenExtractor('darwin')
|
|
26
26
|
const dirs = darwinExtractor.getDiscordDirs()
|
|
27
27
|
|
|
@@ -30,7 +30,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
30
30
|
expect(dirs).toContain(join(homedir(), 'Library', 'Application Support', 'discordptb'))
|
|
31
31
|
})
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
it('returns linux paths on Linux', () => {
|
|
34
34
|
const linuxExtractor = new DiscordTokenExtractor('linux')
|
|
35
35
|
const dirs = linuxExtractor.getDiscordDirs()
|
|
36
36
|
|
|
@@ -39,7 +39,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
39
39
|
expect(dirs).toContain(join(homedir(), '.config', 'discordptb'))
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
it('returns win32 paths on Windows', () => {
|
|
43
43
|
const winExtractor = new DiscordTokenExtractor('win32')
|
|
44
44
|
const dirs = winExtractor.getDiscordDirs()
|
|
45
45
|
|
|
@@ -49,14 +49,14 @@ describe('DiscordTokenExtractor', () => {
|
|
|
49
49
|
expect(dirs).toContain(join(appdata, 'discordptb'))
|
|
50
50
|
})
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
it('returns multiple paths for all 3 variants', () => {
|
|
53
53
|
const dirs = extractor.getDiscordDirs()
|
|
54
54
|
expect(dirs.length).toBe(3)
|
|
55
55
|
})
|
|
56
56
|
})
|
|
57
57
|
|
|
58
58
|
describe('getBrowserLevelDBDirs', () => {
|
|
59
|
-
|
|
59
|
+
it('returns browser LevelDB paths on macOS', () => {
|
|
60
60
|
const darwinExtractor = new DiscordTokenExtractor('darwin')
|
|
61
61
|
const dirs = darwinExtractor.getBrowserLevelDBDirs()
|
|
62
62
|
|
|
@@ -64,7 +64,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
64
64
|
expect(dirs).toContain(join(chromeBase, 'Default', 'Local Storage', 'leveldb'))
|
|
65
65
|
})
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
it('returns browser LevelDB paths on Linux', () => {
|
|
68
68
|
const linuxExtractor = new DiscordTokenExtractor('linux')
|
|
69
69
|
const dirs = linuxExtractor.getBrowserLevelDBDirs()
|
|
70
70
|
|
|
@@ -72,7 +72,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
72
72
|
expect(dirs).toContain(join(chromeBase, 'Default', 'Local Storage', 'leveldb'))
|
|
73
73
|
})
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
it('returns browser LevelDB paths on Windows', () => {
|
|
76
76
|
const winExtractor = new DiscordTokenExtractor('win32')
|
|
77
77
|
const dirs = winExtractor.getBrowserLevelDBDirs()
|
|
78
78
|
|
|
@@ -81,37 +81,37 @@ describe('DiscordTokenExtractor', () => {
|
|
|
81
81
|
expect(dirs).toContain(join(chromeBase, 'Default', 'Local Storage', 'leveldb'))
|
|
82
82
|
})
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
it('returns empty array for unsupported platform', () => {
|
|
85
85
|
const unsupportedExtractor = new DiscordTokenExtractor('freebsd' as NodeJS.Platform)
|
|
86
86
|
expect(unsupportedExtractor.getBrowserLevelDBDirs()).toEqual([])
|
|
87
87
|
})
|
|
88
88
|
})
|
|
89
89
|
|
|
90
90
|
describe('token patterns', () => {
|
|
91
|
-
|
|
91
|
+
it('validates standard token format (base64.base64.base64)', () => {
|
|
92
92
|
const validToken = 'XXXXXXXXXXXXXXXXXXXXXXXX.YYYYYY.ZZZZZZZZZZZZZZZZZZZZZZZZZ'
|
|
93
93
|
expect(extractor.isValidToken(validToken)).toBe(true)
|
|
94
94
|
})
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
it('validates MFA token format', () => {
|
|
97
97
|
const mfaToken = `mfa.${'a'.repeat(84)}`
|
|
98
98
|
expect(extractor.isValidToken(mfaToken)).toBe(true)
|
|
99
99
|
})
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
it('rejects invalid tokens', () => {
|
|
102
102
|
expect(extractor.isValidToken('')).toBe(false)
|
|
103
103
|
expect(extractor.isValidToken('invalid')).toBe(false)
|
|
104
104
|
expect(extractor.isValidToken('xoxc-123')).toBe(false)
|
|
105
105
|
})
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
it('validates tokens with >24 char first segment (newer Discord user IDs)', () => {
|
|
108
108
|
// User IDs created ~2023+ produce base64 segments longer than 24 chars.
|
|
109
109
|
// e.g. user ID 1295726388820709399 -> 'MTI5NTcyNjM4ODgyMDcwOTM5OQ' (26 chars)
|
|
110
110
|
const longSegmentToken = 'MTI5NTcyNjM4ODgyMDcwOTM5OQ.YYYYYY.ZZZZZZZZZZZZZZZZZZZZZZZZZ'
|
|
111
111
|
expect(extractor.isValidToken(longSegmentToken)).toBe(true)
|
|
112
112
|
})
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
it('detects encrypted tokens by prefix', () => {
|
|
115
115
|
const encryptedToken = 'dQw4w9WgXcQ:' + 'encrypted_data'
|
|
116
116
|
expect(extractor.isEncryptedToken(encryptedToken)).toBe(true)
|
|
117
117
|
expect(extractor.isEncryptedToken('MTIzNDU2.xxx.yyy')).toBe(false)
|
|
@@ -119,7 +119,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
119
119
|
})
|
|
120
120
|
|
|
121
121
|
describe('Linux token decryption', () => {
|
|
122
|
-
|
|
122
|
+
it('decrypts encrypted token using peanuts password on Linux', () => {
|
|
123
123
|
// given — AES-128-CBC encrypted token with Linux Chromium key
|
|
124
124
|
const { createCipheriv, pbkdf2Sync } = require('node:crypto')
|
|
125
125
|
const plainToken = 'XXXXXXXXXXXXXXXXXXXXXXXX.YYYYYY.ZZZZZZZZZZZZZZZZZZZZZZZZZ'
|
|
@@ -144,7 +144,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
144
144
|
})
|
|
145
145
|
|
|
146
146
|
describe('Linux v11 token decryption', () => {
|
|
147
|
-
|
|
147
|
+
it('decrypts v11 token using gnome-keyring password on Linux', () => {
|
|
148
148
|
// given — AES-128-CBC encrypted token with keyring-derived key and v11 prefix
|
|
149
149
|
const { createCipheriv, pbkdf2Sync } = require('node:crypto')
|
|
150
150
|
const testPassword = 'test-discord-keyring-secret'
|
|
@@ -173,7 +173,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
173
173
|
keyringPasswordSpy.mockRestore()
|
|
174
174
|
})
|
|
175
175
|
|
|
176
|
-
|
|
176
|
+
it('falls back to peanuts key when keyring is unavailable for v11 token', () => {
|
|
177
177
|
// given — v11-prefixed token encrypted with peanuts (tests fallback code path)
|
|
178
178
|
const { createCipheriv, pbkdf2Sync } = require('node:crypto')
|
|
179
179
|
const plainToken = 'XXXXXXXXXXXXXXXXXXXXXXXX.YYYYYY.ZZZZZZZZZZZZZZZZZZZZZZZZZ'
|
|
@@ -199,7 +199,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
199
199
|
})
|
|
200
200
|
|
|
201
201
|
describe('extract', () => {
|
|
202
|
-
|
|
202
|
+
it('returns empty array when no Discord directories exist on linux', async () => {
|
|
203
203
|
const linuxExtractor = new DiscordTokenExtractor('linux')
|
|
204
204
|
const extractFromLevelDBSpy = spyOn(linuxExtractor as any, 'extractFromLevelDB').mockResolvedValue([])
|
|
205
205
|
const extractFromBrowserLevelDBSpy = spyOn(linuxExtractor as any, 'extractFromBrowserLevelDB').mockResolvedValue(
|
|
@@ -213,7 +213,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
213
213
|
extractFromBrowserLevelDBSpy.mockRestore()
|
|
214
214
|
})
|
|
215
215
|
|
|
216
|
-
|
|
216
|
+
it('extracts token from LevelDB when available', async () => {
|
|
217
217
|
const mockToken = 'XXXXXXXXXXXXXXXXXXXXXXXX.YYYYYY.ZZZZZZZZZZZZZZZZZZZZZZZZZ'
|
|
218
218
|
|
|
219
219
|
const linuxExtractor = new DiscordTokenExtractor('linux')
|
|
@@ -233,7 +233,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
233
233
|
extractFromBrowserLevelDBSpy.mockRestore()
|
|
234
234
|
})
|
|
235
235
|
|
|
236
|
-
|
|
236
|
+
it('tries browser LevelDB when desktop LevelDB extraction fails', async () => {
|
|
237
237
|
const mockToken = 'XXXXXXXXXXXXXXXXXXXXXXXX.YYYYYY.browser_token_1234567890123'
|
|
238
238
|
|
|
239
239
|
const linuxExtractor = new DiscordTokenExtractor('linux')
|
|
@@ -252,7 +252,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
252
252
|
extractFromBrowserLevelDBSpy.mockRestore()
|
|
253
253
|
})
|
|
254
254
|
|
|
255
|
-
|
|
255
|
+
it('tries CDP on macOS when both LevelDB extractions fail', async () => {
|
|
256
256
|
const mockToken = 'XXXXXXXXXXXXXXXXXXXXXXXX.YYYYYY.cdp_token_12345678901234567'
|
|
257
257
|
|
|
258
258
|
const darwinExtractor = new DiscordTokenExtractor('darwin', 0)
|
|
@@ -274,7 +274,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
274
274
|
tryExtractViaCDPSpy.mockRestore()
|
|
275
275
|
})
|
|
276
276
|
|
|
277
|
-
|
|
277
|
+
it('browser LevelDB tried before CDP on macOS', async () => {
|
|
278
278
|
const callOrder: string[] = []
|
|
279
279
|
|
|
280
280
|
const darwinExtractor = new DiscordTokenExtractor('darwin', 0)
|
|
@@ -303,7 +303,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
303
303
|
tryExtractViaCDPSpy.mockRestore()
|
|
304
304
|
})
|
|
305
305
|
|
|
306
|
-
|
|
306
|
+
it('returns all valid tokens found across variants', async () => {
|
|
307
307
|
const mockToken = 'XXXXXXXXXXXXXXXXXXXXXXXX.YYYYYY.first_token_found_1234567'
|
|
308
308
|
|
|
309
309
|
const linuxExtractor = new DiscordTokenExtractor('linux')
|
|
@@ -323,7 +323,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
323
323
|
extractFromBrowserLevelDBSpy.mockRestore()
|
|
324
324
|
})
|
|
325
325
|
|
|
326
|
-
|
|
326
|
+
it('deduplicates the same token found in desktop and browser sources', async () => {
|
|
327
327
|
const mockToken = 'XXXXXXXXXXXXXXXXXXXXXXXX.YYYYYY.ZZZZZZZZZZZZZZZZZZZZZZZZZ'
|
|
328
328
|
|
|
329
329
|
const linuxExtractor = new DiscordTokenExtractor('linux')
|
|
@@ -342,7 +342,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
342
342
|
extractFromBrowserLevelDBSpy.mockRestore()
|
|
343
343
|
})
|
|
344
344
|
|
|
345
|
-
|
|
345
|
+
it('collects multiple distinct tokens from browser profiles', async () => {
|
|
346
346
|
const token1 = 'XXXXXXXXXXXXXXXXXXXXXXXX.YYYYYY.browser_token_1234567890123'
|
|
347
347
|
const token2 = 'YYYYYYYYYYYYYYYYYYYYYYYY.ZZZZZZ.browser_token_2345678901234'
|
|
348
348
|
|
|
@@ -362,7 +362,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
362
362
|
extractFromBrowserLevelDBSpy.mockRestore()
|
|
363
363
|
})
|
|
364
364
|
|
|
365
|
-
|
|
365
|
+
it('does not call CDP when desktop LevelDB extraction returns results', async () => {
|
|
366
366
|
const mockToken = 'XXXXXXXXXXXXXXXXXXXXXXXX.YYYYYY.ZZZZZZZZZZZZZZZZZZZZZZZZZ'
|
|
367
367
|
|
|
368
368
|
const darwinExtractor = new DiscordTokenExtractor('darwin', 0)
|
|
@@ -384,7 +384,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
384
384
|
})
|
|
385
385
|
|
|
386
386
|
describe('getKeychainVariants', () => {
|
|
387
|
-
|
|
387
|
+
it('includes Discord-specific keychain variants', () => {
|
|
388
388
|
const macExtractor = new DiscordTokenExtractor('darwin')
|
|
389
389
|
const variants = macExtractor.getKeychainVariants()
|
|
390
390
|
|
|
@@ -396,7 +396,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
396
396
|
expect(variants).toContainEqual({ service: 'Discord PTB Safe Storage', account: 'Discord PTB' })
|
|
397
397
|
})
|
|
398
398
|
|
|
399
|
-
|
|
399
|
+
it('includes browser keychain variants appended after Discord entries', () => {
|
|
400
400
|
const macExtractor = new DiscordTokenExtractor('darwin')
|
|
401
401
|
const variants = macExtractor.getKeychainVariants()
|
|
402
402
|
|
|
@@ -409,7 +409,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
409
409
|
expect(variants).toContainEqual({ service: 'Chromium Safe Storage', account: 'Chromium' })
|
|
410
410
|
})
|
|
411
411
|
|
|
412
|
-
|
|
412
|
+
it('Discord entries come before browser entries', () => {
|
|
413
413
|
const macExtractor = new DiscordTokenExtractor('darwin')
|
|
414
414
|
const variants = macExtractor.getKeychainVariants()
|
|
415
415
|
|
|
@@ -420,17 +420,17 @@ describe('DiscordTokenExtractor', () => {
|
|
|
420
420
|
})
|
|
421
421
|
|
|
422
422
|
describe('variant detection', () => {
|
|
423
|
-
|
|
423
|
+
it('identifies Discord Stable', () => {
|
|
424
424
|
expect(extractor.getVariantFromPath('/path/to/Discord')).toBe('stable')
|
|
425
425
|
expect(extractor.getVariantFromPath('/path/to/discord')).toBe('stable')
|
|
426
426
|
})
|
|
427
427
|
|
|
428
|
-
|
|
428
|
+
it('identifies Discord Canary', () => {
|
|
429
429
|
expect(extractor.getVariantFromPath('/path/to/discordcanary')).toBe('canary')
|
|
430
430
|
expect(extractor.getVariantFromPath('/path/to/Discord Canary')).toBe('canary')
|
|
431
431
|
})
|
|
432
432
|
|
|
433
|
-
|
|
433
|
+
it('identifies Discord PTB', () => {
|
|
434
434
|
expect(extractor.getVariantFromPath('/path/to/discordptb')).toBe('ptb')
|
|
435
435
|
expect(extractor.getVariantFromPath('/path/to/Discord PTB')).toBe('ptb')
|
|
436
436
|
})
|
|
@@ -438,7 +438,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
438
438
|
|
|
439
439
|
describe('process management', () => {
|
|
440
440
|
describe('isDiscordRunning', () => {
|
|
441
|
-
|
|
441
|
+
it('returns true when Discord process is found', async () => {
|
|
442
442
|
const darwinExtractor = new DiscordTokenExtractor('darwin', 0, 0)
|
|
443
443
|
const checkProcessRunningSpy = spyOn(darwinExtractor as any, 'checkProcessRunning').mockReturnValue(true)
|
|
444
444
|
|
|
@@ -448,7 +448,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
448
448
|
checkProcessRunningSpy.mockRestore()
|
|
449
449
|
})
|
|
450
450
|
|
|
451
|
-
|
|
451
|
+
it('returns false when no Discord process is found', async () => {
|
|
452
452
|
const darwinExtractor = new DiscordTokenExtractor('darwin', 0, 0)
|
|
453
453
|
const checkProcessRunningSpy = spyOn(darwinExtractor as any, 'checkProcessRunning').mockReturnValue(false)
|
|
454
454
|
|
|
@@ -458,7 +458,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
458
458
|
checkProcessRunningSpy.mockRestore()
|
|
459
459
|
})
|
|
460
460
|
|
|
461
|
-
|
|
461
|
+
it('checks all variants when no specific variant provided', async () => {
|
|
462
462
|
const darwinExtractor = new DiscordTokenExtractor('darwin', 0, 0)
|
|
463
463
|
const checkedProcesses: string[] = []
|
|
464
464
|
const checkProcessRunningSpy = spyOn(darwinExtractor as any, 'checkProcessRunning').mockImplementation(
|
|
@@ -479,7 +479,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
479
479
|
})
|
|
480
480
|
|
|
481
481
|
describe('killDiscord', () => {
|
|
482
|
-
|
|
482
|
+
it('kills Discord process', async () => {
|
|
483
483
|
const darwinExtractor = new DiscordTokenExtractor('darwin', 0, 0)
|
|
484
484
|
const killedProcesses: string[] = []
|
|
485
485
|
const killProcessSpy = spyOn(darwinExtractor as any, 'killProcess').mockImplementation((name: string) => {
|
|
@@ -493,7 +493,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
493
493
|
killProcessSpy.mockRestore()
|
|
494
494
|
})
|
|
495
495
|
|
|
496
|
-
|
|
496
|
+
it('kills all variants when no specific variant provided', async () => {
|
|
497
497
|
const darwinExtractor = new DiscordTokenExtractor('darwin', 0, 0)
|
|
498
498
|
const killedProcesses: string[] = []
|
|
499
499
|
const killProcessSpy = spyOn(darwinExtractor as any, 'killProcess').mockImplementation((name: string) => {
|
|
@@ -511,7 +511,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
511
511
|
})
|
|
512
512
|
|
|
513
513
|
describe('launchDiscordWithDebug', () => {
|
|
514
|
-
|
|
514
|
+
it('throws error when Discord app not found', async () => {
|
|
515
515
|
const darwinExtractor = new DiscordTokenExtractor('darwin', 0, 0)
|
|
516
516
|
const getAppPathSpy = spyOn(darwinExtractor as any, 'getAppPath').mockReturnValue('/nonexistent/path')
|
|
517
517
|
|
|
@@ -524,7 +524,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
524
524
|
|
|
525
525
|
describe('CDP client methods', () => {
|
|
526
526
|
describe('discoverCDPTargets', () => {
|
|
527
|
-
|
|
527
|
+
it('returns empty array when CDP endpoint is not reachable', async () => {
|
|
528
528
|
globalThis.fetch = mock(async () => {
|
|
529
529
|
throw new Error('Connection refused')
|
|
530
530
|
}) as unknown as typeof fetch
|
|
@@ -534,7 +534,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
534
534
|
expect(targets).toEqual([])
|
|
535
535
|
})
|
|
536
536
|
|
|
537
|
-
|
|
537
|
+
it('returns targets from CDP endpoint', async () => {
|
|
538
538
|
const mockTargets = [
|
|
539
539
|
{
|
|
540
540
|
id: '1',
|
|
@@ -555,7 +555,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
555
555
|
expect(targets).toEqual(mockTargets)
|
|
556
556
|
})
|
|
557
557
|
|
|
558
|
-
|
|
558
|
+
it('returns empty array on HTTP error', async () => {
|
|
559
559
|
globalThis.fetch = mock(async () => ({
|
|
560
560
|
ok: false,
|
|
561
561
|
status: 500,
|
|
@@ -568,7 +568,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
568
568
|
})
|
|
569
569
|
|
|
570
570
|
describe('findDiscordPageTarget', () => {
|
|
571
|
-
|
|
571
|
+
it('finds target by discord.com URL', () => {
|
|
572
572
|
const targets = [
|
|
573
573
|
{
|
|
574
574
|
id: '1',
|
|
@@ -593,7 +593,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
593
593
|
expect(target?.id).toBe('1')
|
|
594
594
|
})
|
|
595
595
|
|
|
596
|
-
|
|
596
|
+
it('finds target by Discord title', () => {
|
|
597
597
|
const targets = [
|
|
598
598
|
{
|
|
599
599
|
id: '1',
|
|
@@ -611,7 +611,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
611
611
|
expect(target?.id).toBe('1')
|
|
612
612
|
})
|
|
613
613
|
|
|
614
|
-
|
|
614
|
+
it('returns null when no Discord page found', () => {
|
|
615
615
|
const targets = [
|
|
616
616
|
{
|
|
617
617
|
id: '1',
|
|
@@ -628,7 +628,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
628
628
|
expect(target).toBeNull()
|
|
629
629
|
})
|
|
630
630
|
|
|
631
|
-
|
|
631
|
+
it('returns null for empty targets', () => {
|
|
632
632
|
const extractor = new DiscordTokenExtractor('darwin')
|
|
633
633
|
const target = extractor.findDiscordPageTarget([])
|
|
634
634
|
expect(target).toBeNull()
|
|
@@ -636,7 +636,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
636
636
|
})
|
|
637
637
|
|
|
638
638
|
describe('executeJSViaCDP', () => {
|
|
639
|
-
|
|
639
|
+
it('executes JavaScript and returns result', async () => {
|
|
640
640
|
const mockToken = 'test_token_12345'
|
|
641
641
|
|
|
642
642
|
const mockWebSocket = class {
|
|
@@ -672,7 +672,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
672
672
|
expect(result).toBe(mockToken)
|
|
673
673
|
})
|
|
674
674
|
|
|
675
|
-
|
|
675
|
+
it('rejects on CDP error response', async () => {
|
|
676
676
|
const mockWebSocket = class {
|
|
677
677
|
onopen: (() => void) | null = null
|
|
678
678
|
onmessage: ((event: { data: string }) => void) | null = null
|
|
@@ -707,7 +707,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
707
707
|
).rejects.toThrow('Evaluation failed')
|
|
708
708
|
})
|
|
709
709
|
|
|
710
|
-
|
|
710
|
+
it('rejects on WebSocket error', async () => {
|
|
711
711
|
const mockWebSocket = class {
|
|
712
712
|
onopen: (() => void) | null = null
|
|
713
713
|
onmessage: ((event: { data: string }) => void) | null = null
|
|
@@ -733,7 +733,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
733
733
|
})
|
|
734
734
|
|
|
735
735
|
describe('extractViaCDP', () => {
|
|
736
|
-
|
|
736
|
+
it('returns null when no CDP targets available', async () => {
|
|
737
737
|
globalThis.fetch = mock(async () => ({
|
|
738
738
|
ok: true,
|
|
739
739
|
json: async () => [],
|
|
@@ -744,7 +744,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
744
744
|
expect(result).toBeNull()
|
|
745
745
|
})
|
|
746
746
|
|
|
747
|
-
|
|
747
|
+
it('returns null when no Discord page target found', async () => {
|
|
748
748
|
globalThis.fetch = mock(async () => ({
|
|
749
749
|
ok: true,
|
|
750
750
|
json: async () => [
|
|
@@ -763,7 +763,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
763
763
|
expect(result).toBeNull()
|
|
764
764
|
})
|
|
765
765
|
|
|
766
|
-
|
|
766
|
+
it('extracts token via CDP when Discord is running with debug port', async () => {
|
|
767
767
|
const mockToken = 'XXXXXXXXXXXXXXXXXXXXXXXX.YYYYYY.ZZZZZZZZZZZZZZZZZZZZZZZZZ'
|
|
768
768
|
|
|
769
769
|
globalThis.fetch = mock(async () => ({
|
|
@@ -810,7 +810,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
810
810
|
expect(result).toBe(mockToken)
|
|
811
811
|
})
|
|
812
812
|
|
|
813
|
-
|
|
813
|
+
it('returns null when token extraction JS fails', async () => {
|
|
814
814
|
globalThis.fetch = mock(async () => ({
|
|
815
815
|
ok: true,
|
|
816
816
|
json: async () => [
|
|
@@ -855,7 +855,7 @@ describe('DiscordTokenExtractor', () => {
|
|
|
855
855
|
expect(result).toBeNull()
|
|
856
856
|
})
|
|
857
857
|
|
|
858
|
-
|
|
858
|
+
it('returns null when returned value is not a valid token', async () => {
|
|
859
859
|
globalThis.fetch = mock(async () => ({
|
|
860
860
|
ok: true,
|
|
861
861
|
json: async () => [
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expect,
|
|
1
|
+
import { expect, it } from 'bun:test'
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
DiscordChannelSchema,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
DiscordUserSchema,
|
|
13
13
|
} from './types'
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
it('DiscordGuildSchema validates correct guild', () => {
|
|
16
16
|
const result = DiscordGuildSchema.safeParse({
|
|
17
17
|
id: '123456789012345678',
|
|
18
18
|
name: 'Test Guild',
|
|
@@ -20,21 +20,21 @@ test('DiscordGuildSchema validates correct guild', () => {
|
|
|
20
20
|
expect(result.success).toBe(true)
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
it('DiscordGuildSchema rejects missing id', () => {
|
|
24
24
|
const result = DiscordGuildSchema.safeParse({
|
|
25
25
|
name: 'Test Guild',
|
|
26
26
|
})
|
|
27
27
|
expect(result.success).toBe(false)
|
|
28
28
|
})
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
it('DiscordGuildSchema rejects missing name', () => {
|
|
31
31
|
const result = DiscordGuildSchema.safeParse({
|
|
32
32
|
id: '123456789012345678',
|
|
33
33
|
})
|
|
34
34
|
expect(result.success).toBe(false)
|
|
35
35
|
})
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
it('DiscordChannelSchema validates correct channel', () => {
|
|
38
38
|
const result = DiscordChannelSchema.safeParse({
|
|
39
39
|
id: '987654321098765432',
|
|
40
40
|
guild_id: '123456789012345678',
|
|
@@ -44,7 +44,7 @@ test('DiscordChannelSchema validates correct channel', () => {
|
|
|
44
44
|
expect(result.success).toBe(true)
|
|
45
45
|
})
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
it('DiscordChannelSchema validates channel with optional fields', () => {
|
|
48
48
|
const result = DiscordChannelSchema.safeParse({
|
|
49
49
|
id: '987654321098765432',
|
|
50
50
|
guild_id: '123456789012345678',
|
|
@@ -56,7 +56,7 @@ test('DiscordChannelSchema validates channel with optional fields', () => {
|
|
|
56
56
|
expect(result.success).toBe(true)
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
it('DiscordChannelSchema rejects missing required fields', () => {
|
|
60
60
|
const result = DiscordChannelSchema.safeParse({
|
|
61
61
|
id: '987654321098765432',
|
|
62
62
|
name: 'general',
|
|
@@ -64,7 +64,7 @@ test('DiscordChannelSchema rejects missing required fields', () => {
|
|
|
64
64
|
expect(result.success).toBe(false)
|
|
65
65
|
})
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
it('DiscordMessageSchema validates correct message', () => {
|
|
68
68
|
const result = DiscordMessageSchema.safeParse({
|
|
69
69
|
id: '111222333444555666',
|
|
70
70
|
channel_id: '987654321098765432',
|
|
@@ -78,7 +78,7 @@ test('DiscordMessageSchema validates correct message', () => {
|
|
|
78
78
|
expect(result.success).toBe(true)
|
|
79
79
|
})
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
it('DiscordMessageSchema validates message with optional fields', () => {
|
|
82
82
|
const result = DiscordMessageSchema.safeParse({
|
|
83
83
|
id: '111222333444555666',
|
|
84
84
|
channel_id: '987654321098765432',
|
|
@@ -94,7 +94,7 @@ test('DiscordMessageSchema validates message with optional fields', () => {
|
|
|
94
94
|
expect(result.success).toBe(true)
|
|
95
95
|
})
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
it('DiscordMessageSchema rejects missing required fields', () => {
|
|
98
98
|
const result = DiscordMessageSchema.safeParse({
|
|
99
99
|
id: '111222333444555666',
|
|
100
100
|
channel_id: '987654321098765432',
|
|
@@ -103,7 +103,7 @@ test('DiscordMessageSchema rejects missing required fields', () => {
|
|
|
103
103
|
expect(result.success).toBe(false)
|
|
104
104
|
})
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
it('DiscordUserSchema validates correct user', () => {
|
|
107
107
|
const result = DiscordUserSchema.safeParse({
|
|
108
108
|
id: '222333444555666777',
|
|
109
109
|
username: 'testuser',
|
|
@@ -111,7 +111,7 @@ test('DiscordUserSchema validates correct user', () => {
|
|
|
111
111
|
expect(result.success).toBe(true)
|
|
112
112
|
})
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
it('DiscordUserSchema validates user with optional fields', () => {
|
|
115
115
|
const result = DiscordUserSchema.safeParse({
|
|
116
116
|
id: '222333444555666777',
|
|
117
117
|
username: 'testuser',
|
|
@@ -122,14 +122,14 @@ test('DiscordUserSchema validates user with optional fields', () => {
|
|
|
122
122
|
expect(result.success).toBe(true)
|
|
123
123
|
})
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
it('DiscordUserSchema rejects missing required fields', () => {
|
|
126
126
|
const result = DiscordUserSchema.safeParse({
|
|
127
127
|
id: '222333444555666777',
|
|
128
128
|
})
|
|
129
129
|
expect(result.success).toBe(false)
|
|
130
130
|
})
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
it('DiscordReactionSchema validates correct reaction', () => {
|
|
133
133
|
const result = DiscordReactionSchema.safeParse({
|
|
134
134
|
emoji: {
|
|
135
135
|
name: 'thumbsup',
|
|
@@ -139,7 +139,7 @@ test('DiscordReactionSchema validates correct reaction', () => {
|
|
|
139
139
|
expect(result.success).toBe(true)
|
|
140
140
|
})
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
it('DiscordReactionSchema validates reaction with custom emoji', () => {
|
|
143
143
|
const result = DiscordReactionSchema.safeParse({
|
|
144
144
|
emoji: {
|
|
145
145
|
id: '123456789012345678',
|
|
@@ -150,7 +150,7 @@ test('DiscordReactionSchema validates reaction with custom emoji', () => {
|
|
|
150
150
|
expect(result.success).toBe(true)
|
|
151
151
|
})
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
it('DiscordReactionSchema rejects missing required fields', () => {
|
|
154
154
|
const result = DiscordReactionSchema.safeParse({
|
|
155
155
|
emoji: {
|
|
156
156
|
name: 'thumbsup',
|
|
@@ -159,7 +159,7 @@ test('DiscordReactionSchema rejects missing required fields', () => {
|
|
|
159
159
|
expect(result.success).toBe(false)
|
|
160
160
|
})
|
|
161
161
|
|
|
162
|
-
|
|
162
|
+
it('DiscordFileSchema validates correct file', () => {
|
|
163
163
|
const result = DiscordFileSchema.safeParse({
|
|
164
164
|
id: '444555666777888999',
|
|
165
165
|
filename: 'document.pdf',
|
|
@@ -169,7 +169,7 @@ test('DiscordFileSchema validates correct file', () => {
|
|
|
169
169
|
expect(result.success).toBe(true)
|
|
170
170
|
})
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
it('DiscordFileSchema validates file with optional fields', () => {
|
|
173
173
|
const result = DiscordFileSchema.safeParse({
|
|
174
174
|
id: '444555666777888999',
|
|
175
175
|
filename: 'document.pdf',
|
|
@@ -182,7 +182,7 @@ test('DiscordFileSchema validates file with optional fields', () => {
|
|
|
182
182
|
expect(result.success).toBe(true)
|
|
183
183
|
})
|
|
184
184
|
|
|
185
|
-
|
|
185
|
+
it('DiscordFileSchema rejects missing required fields', () => {
|
|
186
186
|
const result = DiscordFileSchema.safeParse({
|
|
187
187
|
id: '444555666777888999',
|
|
188
188
|
filename: 'document.pdf',
|
|
@@ -190,19 +190,19 @@ test('DiscordFileSchema rejects missing required fields', () => {
|
|
|
190
190
|
expect(result.success).toBe(false)
|
|
191
191
|
})
|
|
192
192
|
|
|
193
|
-
|
|
193
|
+
it('DiscordCredentialsSchema validates correct credentials', () => {
|
|
194
194
|
const result = DiscordCredentialsSchema.safeParse({
|
|
195
195
|
token: 'token_value',
|
|
196
196
|
})
|
|
197
197
|
expect(result.success).toBe(true)
|
|
198
198
|
})
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
it('DiscordCredentialsSchema rejects missing token', () => {
|
|
201
201
|
const result = DiscordCredentialsSchema.safeParse({})
|
|
202
202
|
expect(result.success).toBe(false)
|
|
203
203
|
})
|
|
204
204
|
|
|
205
|
-
|
|
205
|
+
it('DiscordConfigSchema validates correct config', () => {
|
|
206
206
|
const result = DiscordConfigSchema.safeParse({
|
|
207
207
|
current_server: null,
|
|
208
208
|
token: 'token_value',
|
|
@@ -211,7 +211,7 @@ test('DiscordConfigSchema validates correct config', () => {
|
|
|
211
211
|
expect(result.success).toBe(true)
|
|
212
212
|
})
|
|
213
213
|
|
|
214
|
-
|
|
214
|
+
it('DiscordConfigSchema validates config with servers', () => {
|
|
215
215
|
const result = DiscordConfigSchema.safeParse({
|
|
216
216
|
current_server: '123456789012345678',
|
|
217
217
|
token: 'token_value',
|
|
@@ -225,7 +225,7 @@ test('DiscordConfigSchema validates config with servers', () => {
|
|
|
225
225
|
expect(result.success).toBe(true)
|
|
226
226
|
})
|
|
227
227
|
|
|
228
|
-
|
|
228
|
+
it('DiscordConfigSchema rejects missing required fields', () => {
|
|
229
229
|
const result = DiscordConfigSchema.safeParse({
|
|
230
230
|
current_server: null,
|
|
231
231
|
token: 'token_value',
|
|
@@ -233,14 +233,14 @@ test('DiscordConfigSchema rejects missing required fields', () => {
|
|
|
233
233
|
expect(result.success).toBe(false)
|
|
234
234
|
})
|
|
235
235
|
|
|
236
|
-
|
|
236
|
+
it('DiscordError has correct name and code', () => {
|
|
237
237
|
const error = new DiscordError('Test error', 'TEST_CODE')
|
|
238
238
|
expect(error.name).toBe('DiscordError')
|
|
239
239
|
expect(error.message).toBe('Test error')
|
|
240
240
|
expect(error.code).toBe('TEST_CODE')
|
|
241
241
|
})
|
|
242
242
|
|
|
243
|
-
|
|
243
|
+
it('DiscordError is instance of Error', () => {
|
|
244
244
|
const error = new DiscordError('Test error', 'TEST_CODE')
|
|
245
245
|
expect(error instanceof Error).toBe(true)
|
|
246
246
|
})
|