agent-messenger 2.2.0 → 2.4.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/README.md +16 -16
- package/.claude-plugin/marketplace.json +29 -29
- package/.claude-plugin/plugin.json +5 -5
- package/CONTRIBUTING.md +1 -1
- package/README.md +9 -6
- package/bun.lock +89 -105
- package/bunfig.toml +3 -0
- package/dist/package.json +13 -3
- package/dist/src/platforms/discordbot/client.js +2 -2
- package/dist/src/platforms/discordbot/client.js.map +1 -1
- package/dist/src/platforms/kakaotalk/cli.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/cli.js +2 -1
- package/dist/src/platforms/kakaotalk/cli.js.map +1 -1
- package/dist/src/platforms/kakaotalk/client.d.ts +2 -1
- package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/client.js +52 -2
- package/dist/src/platforms/kakaotalk/client.js.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/index.d.ts +1 -0
- package/dist/src/platforms/kakaotalk/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/index.js +1 -0
- package/dist/src/platforms/kakaotalk/commands/index.js.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/profile.d.ts +3 -0
- package/dist/src/platforms/kakaotalk/commands/profile.d.ts.map +1 -0
- package/dist/src/platforms/kakaotalk/commands/profile.js +19 -0
- package/dist/src/platforms/kakaotalk/commands/profile.js.map +1 -0
- package/dist/src/platforms/kakaotalk/index.d.ts +2 -2
- package/dist/src/platforms/kakaotalk/index.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/index.js +1 -1
- package/dist/src/platforms/kakaotalk/index.js.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/session.js +2 -1
- package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
- package/dist/src/platforms/kakaotalk/types.d.ts +16 -0
- package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/types.js +8 -0
- package/dist/src/platforms/kakaotalk/types.js.map +1 -1
- package/dist/src/platforms/line/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/line/commands/auth.js +32 -20
- package/dist/src/platforms/line/commands/auth.js.map +1 -1
- package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/reaction.js +2 -0
- package/dist/src/platforms/teams/commands/reaction.js.map +1 -1
- package/dist/src/platforms/webex/client.d.ts +2 -0
- package/dist/src/platforms/webex/client.d.ts.map +1 -1
- package/dist/src/platforms/webex/client.js +66 -23
- package/dist/src/platforms/webex/client.js.map +1 -1
- package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/auth.js +4 -0
- package/dist/src/platforms/webex/commands/auth.js.map +1 -1
- package/dist/src/platforms/webex/encryption.d.ts +10 -0
- package/dist/src/platforms/webex/encryption.d.ts.map +1 -0
- package/dist/src/platforms/webex/encryption.js +49 -0
- package/dist/src/platforms/webex/encryption.js.map +1 -0
- package/dist/src/platforms/webex/ensure-auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/ensure-auth.js +4 -0
- package/dist/src/platforms/webex/ensure-auth.js.map +1 -1
- package/dist/src/platforms/webex/token-extractor.d.ts +6 -5
- package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/webex/token-extractor.js +92 -43
- package/dist/src/platforms/webex/token-extractor.js.map +1 -1
- package/dist/src/platforms/webex/types.d.ts +4 -0
- package/dist/src/platforms/webex/types.d.ts.map +1 -1
- package/dist/src/platforms/webex/types.js +2 -0
- package/dist/src/platforms/webex/types.js.map +1 -1
- package/dist/src/platforms/wechatbot/cli.d.ts +5 -0
- package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/cli.js +18 -0
- package/dist/src/platforms/wechatbot/cli.js.map +1 -0
- package/dist/src/platforms/wechatbot/client.d.ts +36 -0
- package/dist/src/platforms/wechatbot/client.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/client.js +208 -0
- package/dist/src/platforms/wechatbot/client.js.map +1 -0
- package/dist/src/platforms/wechatbot/commands/auth.d.ts +28 -0
- package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/auth.js +164 -0
- package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -0
- package/dist/src/platforms/wechatbot/commands/index.d.ts +5 -0
- package/dist/src/platforms/wechatbot/commands/index.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/index.js +5 -0
- package/dist/src/platforms/wechatbot/commands/index.js.map +1 -0
- package/dist/src/platforms/wechatbot/commands/message.d.ts +18 -0
- package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/message.js +80 -0
- package/dist/src/platforms/wechatbot/commands/message.js.map +1 -0
- package/dist/src/platforms/wechatbot/commands/shared.d.ts +9 -0
- package/dist/src/platforms/wechatbot/commands/shared.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/shared.js +13 -0
- package/dist/src/platforms/wechatbot/commands/shared.js.map +1 -0
- package/dist/src/platforms/wechatbot/commands/template.d.ts +19 -0
- package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/template.js +76 -0
- package/dist/src/platforms/wechatbot/commands/template.js.map +1 -0
- package/dist/src/platforms/wechatbot/commands/user.d.ts +20 -0
- package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/user.js +53 -0
- package/dist/src/platforms/wechatbot/commands/user.js.map +1 -0
- package/dist/src/platforms/wechatbot/credential-manager.d.ts +17 -0
- package/dist/src/platforms/wechatbot/credential-manager.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/credential-manager.js +121 -0
- package/dist/src/platforms/wechatbot/credential-manager.js.map +1 -0
- package/dist/src/platforms/wechatbot/index.d.ts +5 -0
- package/dist/src/platforms/wechatbot/index.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/index.js +4 -0
- package/dist/src/platforms/wechatbot/index.js.map +1 -0
- package/dist/src/platforms/wechatbot/types.d.ts +94 -0
- package/dist/src/platforms/wechatbot/types.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/types.js +54 -0
- package/dist/src/platforms/wechatbot/types.js.map +1 -0
- package/dist/src/platforms/whatsapp/client.d.ts +1 -0
- package/dist/src/platforms/whatsapp/client.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/client.js +27 -13
- package/dist/src/platforms/whatsapp/client.js.map +1 -1
- package/dist/src/platforms/whatsapp/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/commands/auth.js +21 -18
- package/dist/src/platforms/whatsapp/commands/auth.js.map +1 -1
- package/dist/src/platforms/whatsapp/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/credential-manager.js +14 -8
- package/dist/src/platforms/whatsapp/credential-manager.js.map +1 -1
- package/docs/content/docs/agent-skills.mdx +4 -4
- package/docs/content/docs/cli/channeltalk.mdx +1 -1
- package/docs/content/docs/cli/channeltalkbot.mdx +1 -1
- package/docs/content/docs/cli/discord.mdx +1 -1
- package/docs/content/docs/cli/discordbot.mdx +1 -1
- package/docs/content/docs/cli/instagram.mdx +1 -1
- package/docs/content/docs/cli/kakaotalk.mdx +1 -1
- package/docs/content/docs/cli/line.mdx +1 -1
- package/docs/content/docs/cli/meta.json +1 -0
- package/docs/content/docs/cli/slack.mdx +1 -1
- package/docs/content/docs/cli/slackbot.mdx +1 -1
- package/docs/content/docs/cli/teams.mdx +1 -1
- package/docs/content/docs/cli/webex.mdx +5 -3
- package/docs/content/docs/cli/wechatbot.mdx +179 -0
- package/docs/content/docs/cli/whatsapp.mdx +1 -1
- package/docs/content/docs/cli/whatsappbot.mdx +1 -1
- package/docs/content/docs/sdk/meta.json +1 -1
- package/docs/content/docs/sdk/wechatbot.mdx +282 -0
- package/docs/content/docs/tui.mdx +1 -1
- package/docs/src/app/page.tsx +5 -5
- package/package.json +13 -3
- 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 +24 -1
- package/skills/agent-line/SKILL.md +7 -11
- package/skills/agent-line/references/authentication.md +13 -4
- 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-webex/references/authentication.md +4 -3
- package/skills/agent-webex/references/common-patterns.md +1 -1
- package/skills/agent-wechatbot/SKILL.md +385 -0
- package/skills/agent-whatsapp/SKILL.md +12 -1
- package/skills/agent-whatsappbot/SKILL.md +1 -1
- package/src/platforms/discord/credential-manager.test.ts +18 -1
- package/src/platforms/discordbot/client.ts +2 -2
- package/src/platforms/instagram/commands/auth.test.ts +216 -0
- package/src/platforms/instagram/commands/chat.test.ts +127 -0
- package/src/platforms/instagram/commands/message.test.ts +178 -0
- package/src/platforms/kakaotalk/cli.ts +2 -1
- package/src/platforms/kakaotalk/client.test.ts +157 -0
- package/src/platforms/kakaotalk/client.ts +57 -3
- package/src/platforms/kakaotalk/commands/auth.test.ts +299 -0
- package/src/platforms/kakaotalk/commands/chat.test.ts +97 -0
- package/src/platforms/kakaotalk/commands/index.ts +1 -0
- package/src/platforms/kakaotalk/commands/message.test.ts +113 -0
- package/src/platforms/kakaotalk/commands/profile.test.ts +84 -0
- package/src/platforms/kakaotalk/commands/profile.ts +21 -0
- package/src/platforms/kakaotalk/index.test.ts +5 -0
- package/src/platforms/kakaotalk/index.ts +2 -0
- package/src/platforms/kakaotalk/protocol/session.ts +2 -0
- package/src/platforms/kakaotalk/types.ts +18 -0
- package/src/platforms/line/commands/auth.test.ts +141 -0
- package/src/platforms/line/commands/auth.ts +28 -19
- package/src/platforms/line/commands/chat.test.ts +110 -0
- package/src/platforms/line/commands/friend.test.ts +98 -0
- package/src/platforms/line/commands/message.test.ts +119 -0
- package/src/platforms/line/commands/profile.test.ts +85 -0
- package/src/platforms/slackbot/commands/channel.test.ts +139 -0
- package/src/platforms/slackbot/commands/message.test.ts +226 -0
- package/src/platforms/slackbot/commands/reaction.test.ts +90 -0
- package/src/platforms/slackbot/commands/user.test.ts +143 -0
- package/src/platforms/teams/commands/reaction.test.ts +45 -61
- package/src/platforms/teams/commands/reaction.ts +2 -0
- package/src/platforms/telegram/commands/chat.test.ts +125 -0
- package/src/platforms/telegram/commands/message.test.ts +92 -0
- package/src/platforms/webex/client.ts +98 -26
- package/src/platforms/webex/commands/auth.ts +4 -0
- package/src/platforms/webex/commands/member.test.ts +65 -58
- package/src/platforms/webex/commands/message.test.ts +78 -121
- package/src/platforms/webex/commands/snapshot.test.ts +59 -46
- package/src/platforms/webex/commands/space.test.ts +49 -48
- package/src/platforms/webex/encryption.ts +53 -0
- package/src/platforms/webex/ensure-auth.ts +4 -0
- package/src/platforms/webex/token-extractor.ts +107 -40
- package/src/platforms/webex/types.ts +4 -0
- package/src/platforms/webex/typings/node-jose.d.ts +27 -0
- package/src/platforms/wechatbot/cli.ts +24 -0
- package/src/platforms/wechatbot/client.test.ts +497 -0
- package/src/platforms/wechatbot/client.ts +268 -0
- package/src/platforms/wechatbot/commands/auth.test.ts +211 -0
- package/src/platforms/wechatbot/commands/auth.ts +203 -0
- package/src/platforms/wechatbot/commands/index.ts +4 -0
- package/src/platforms/wechatbot/commands/message.test.ts +155 -0
- package/src/platforms/wechatbot/commands/message.ts +104 -0
- package/src/platforms/wechatbot/commands/shared.ts +22 -0
- package/src/platforms/wechatbot/commands/template.test.ts +199 -0
- package/src/platforms/wechatbot/commands/template.ts +102 -0
- package/src/platforms/wechatbot/commands/user.test.ts +165 -0
- package/src/platforms/wechatbot/commands/user.ts +75 -0
- package/src/platforms/wechatbot/credential-manager.test.ts +255 -0
- package/src/platforms/wechatbot/credential-manager.ts +148 -0
- package/src/platforms/wechatbot/index.test.ts +49 -0
- package/src/platforms/wechatbot/index.ts +19 -0
- package/src/platforms/wechatbot/types.test.ts +223 -0
- package/src/platforms/wechatbot/types.ts +107 -0
- package/src/platforms/whatsapp/client.ts +24 -13
- package/src/platforms/whatsapp/commands/auth.test.ts +311 -0
- package/src/platforms/whatsapp/commands/auth.ts +21 -17
- package/src/platforms/whatsapp/commands/chat.test.ts +198 -0
- package/src/platforms/whatsapp/commands/message.test.ts +231 -0
- package/src/platforms/whatsapp/credential-manager.test.ts +20 -0
- package/src/platforms/whatsapp/credential-manager.ts +17 -8
- package/src/platforms/whatsappbot/commands/auth.test.ts +217 -0
- package/src/platforms/whatsappbot/commands/message.test.ts +198 -0
- package/src/platforms/whatsappbot/commands/template.test.ts +112 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { afterAll, describe, expect, mock, test } from 'bun:test'
|
|
2
|
+
import { rmSync } from 'node:fs'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { WeChatBotCredentialManager } from '@/platforms/wechatbot/credential-manager'
|
|
6
|
+
|
|
7
|
+
const mockFollowersResult = {
|
|
8
|
+
total: 2,
|
|
9
|
+
count: 2,
|
|
10
|
+
openids: ['openid-1', 'openid-2'],
|
|
11
|
+
next_openid: '',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const mockUserInfo = {
|
|
15
|
+
subscribe: 1,
|
|
16
|
+
openid: 'openid-123',
|
|
17
|
+
language: 'zh_CN',
|
|
18
|
+
subscribe_time: 1609459200,
|
|
19
|
+
remark: '',
|
|
20
|
+
tagid_list: [],
|
|
21
|
+
subscribe_scene: 'ADD_SCENE_QR_CODE',
|
|
22
|
+
qr_scene: 0,
|
|
23
|
+
qr_scene_str: '',
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
mock.module('../client', () => ({
|
|
27
|
+
WeChatBotClient: class MockWeChatBotClient {
|
|
28
|
+
async login() {
|
|
29
|
+
return this
|
|
30
|
+
}
|
|
31
|
+
getFollowers = mock(() => Promise.resolve(mockFollowersResult))
|
|
32
|
+
getUserInfo = mock(() => Promise.resolve(mockUserInfo))
|
|
33
|
+
},
|
|
34
|
+
}))
|
|
35
|
+
|
|
36
|
+
const { listAction } = await import('@/platforms/wechatbot/commands/user')
|
|
37
|
+
|
|
38
|
+
const testDirs: string[] = []
|
|
39
|
+
|
|
40
|
+
function makeCredManager(): WeChatBotCredentialManager {
|
|
41
|
+
const dir = join(
|
|
42
|
+
import.meta.dir,
|
|
43
|
+
`.test-user-config-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
44
|
+
)
|
|
45
|
+
testDirs.push(dir)
|
|
46
|
+
return new WeChatBotCredentialManager(dir)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function makeCredManagerWithCreds(): Promise<WeChatBotCredentialManager> {
|
|
50
|
+
const manager = makeCredManager()
|
|
51
|
+
await manager.setCredentials({ app_id: 'wx123', app_secret: 'secret123', account_name: 'My Account' })
|
|
52
|
+
return manager
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
afterAll(() => {
|
|
56
|
+
for (const dir of testDirs) {
|
|
57
|
+
rmSync(dir, { recursive: true, force: true })
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe('listAction (user)', () => {
|
|
62
|
+
test('returns followers list with total, count, openids, next_openid', async () => {
|
|
63
|
+
const credManager = await makeCredManagerWithCreds()
|
|
64
|
+
const result = await listAction({ _credManager: credManager })
|
|
65
|
+
|
|
66
|
+
expect(result.total).toBe(2)
|
|
67
|
+
expect(result.count).toBe(2)
|
|
68
|
+
expect(result.openids).toEqual(['openid-1', 'openid-2'])
|
|
69
|
+
expect(result.next_openid).toBe('')
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
test('returns error when client throws', async () => {
|
|
73
|
+
mock.module('../client', () => ({
|
|
74
|
+
WeChatBotClient: class MockWeChatBotClient {
|
|
75
|
+
async login() {
|
|
76
|
+
return this
|
|
77
|
+
}
|
|
78
|
+
getFollowers = mock(() => Promise.reject(new Error('API error')))
|
|
79
|
+
},
|
|
80
|
+
}))
|
|
81
|
+
|
|
82
|
+
const { listAction: listActionFresh } = await import('@/platforms/wechatbot/commands/user')
|
|
83
|
+
const credManager = await makeCredManagerWithCreds()
|
|
84
|
+
const result = await listActionFresh({ _credManager: credManager })
|
|
85
|
+
|
|
86
|
+
expect(result.error).toBe('API error')
|
|
87
|
+
expect(result.openids).toBeUndefined()
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test('passes nextOpenid option to client', async () => {
|
|
91
|
+
const getFollowersMock = mock(() =>
|
|
92
|
+
Promise.resolve({ total: 1, count: 1, openids: ['openid-3'], next_openid: '' }),
|
|
93
|
+
)
|
|
94
|
+
mock.module('../client', () => ({
|
|
95
|
+
WeChatBotClient: class MockWeChatBotClient {
|
|
96
|
+
async login() {
|
|
97
|
+
return this
|
|
98
|
+
}
|
|
99
|
+
getFollowers = getFollowersMock
|
|
100
|
+
},
|
|
101
|
+
}))
|
|
102
|
+
|
|
103
|
+
const { listAction: listActionFresh } = await import('@/platforms/wechatbot/commands/user')
|
|
104
|
+
const credManager = await makeCredManagerWithCreds()
|
|
105
|
+
await listActionFresh({ nextOpenid: 'openid-2', _credManager: credManager })
|
|
106
|
+
|
|
107
|
+
expect(getFollowersMock).toHaveBeenCalledWith('openid-2')
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
describe('getAction', () => {
|
|
112
|
+
test('returns user info for given openId', async () => {
|
|
113
|
+
mock.module('../client', () => ({
|
|
114
|
+
WeChatBotClient: class MockWeChatBotClient {
|
|
115
|
+
async login() {
|
|
116
|
+
return this
|
|
117
|
+
}
|
|
118
|
+
getUserInfo = mock(() => Promise.resolve(mockUserInfo))
|
|
119
|
+
},
|
|
120
|
+
}))
|
|
121
|
+
|
|
122
|
+
const { getAction: getActionFresh } = await import('@/platforms/wechatbot/commands/user')
|
|
123
|
+
const credManager = await makeCredManagerWithCreds()
|
|
124
|
+
const result = await getActionFresh('openid-123', { _credManager: credManager })
|
|
125
|
+
|
|
126
|
+
expect(result.user).toEqual(mockUserInfo)
|
|
127
|
+
expect(result.user?.openid).toBe('openid-123')
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
test('returns error when client throws', async () => {
|
|
131
|
+
mock.module('../client', () => ({
|
|
132
|
+
WeChatBotClient: class MockWeChatBotClient {
|
|
133
|
+
async login() {
|
|
134
|
+
return this
|
|
135
|
+
}
|
|
136
|
+
getUserInfo = mock(() => Promise.reject(new Error('user not found')))
|
|
137
|
+
},
|
|
138
|
+
}))
|
|
139
|
+
|
|
140
|
+
const { getAction: getActionFresh } = await import('@/platforms/wechatbot/commands/user')
|
|
141
|
+
const credManager = await makeCredManagerWithCreds()
|
|
142
|
+
const result = await getActionFresh('nonexistent-openid', { _credManager: credManager })
|
|
143
|
+
|
|
144
|
+
expect(result.error).toBe('user not found')
|
|
145
|
+
expect(result.user).toBeUndefined()
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
test('passes lang option to client', async () => {
|
|
149
|
+
const getUserInfoMock = mock(() => Promise.resolve({ ...mockUserInfo, language: 'en' }))
|
|
150
|
+
mock.module('../client', () => ({
|
|
151
|
+
WeChatBotClient: class MockWeChatBotClient {
|
|
152
|
+
async login() {
|
|
153
|
+
return this
|
|
154
|
+
}
|
|
155
|
+
getUserInfo = getUserInfoMock
|
|
156
|
+
},
|
|
157
|
+
}))
|
|
158
|
+
|
|
159
|
+
const { getAction: getActionFresh } = await import('@/platforms/wechatbot/commands/user')
|
|
160
|
+
const credManager = await makeCredManagerWithCreds()
|
|
161
|
+
await getActionFresh('openid-123', { lang: 'en', _credManager: credManager })
|
|
162
|
+
|
|
163
|
+
expect(getUserInfoMock).toHaveBeenCalledWith('openid-123', 'en')
|
|
164
|
+
})
|
|
165
|
+
})
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
|
|
3
|
+
import { formatOutput } from '@/shared/utils/output'
|
|
4
|
+
|
|
5
|
+
import type { WeChatBotUserInfo } from '../types'
|
|
6
|
+
import type { AccountOption } from './shared'
|
|
7
|
+
import { getClient } from './shared'
|
|
8
|
+
|
|
9
|
+
interface UserResult {
|
|
10
|
+
total?: number
|
|
11
|
+
count?: number
|
|
12
|
+
openids?: string[]
|
|
13
|
+
next_openid?: string
|
|
14
|
+
user?: WeChatBotUserInfo
|
|
15
|
+
error?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type UserOptions = AccountOption & {
|
|
19
|
+
nextOpenid?: string
|
|
20
|
+
lang?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function listAction(options: UserOptions): Promise<UserResult> {
|
|
24
|
+
try {
|
|
25
|
+
const client = await getClient(options)
|
|
26
|
+
const result = await client.getFollowers(options.nextOpenid)
|
|
27
|
+
return {
|
|
28
|
+
total: result.total,
|
|
29
|
+
count: result.count,
|
|
30
|
+
openids: result.openids,
|
|
31
|
+
next_openid: result.next_openid,
|
|
32
|
+
}
|
|
33
|
+
} catch (error) {
|
|
34
|
+
return { error: (error as Error).message }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function getAction(openId: string, options: UserOptions): Promise<UserResult> {
|
|
39
|
+
try {
|
|
40
|
+
const client = await getClient(options)
|
|
41
|
+
const user = await client.getUserInfo(openId, options.lang)
|
|
42
|
+
return { user }
|
|
43
|
+
} catch (error) {
|
|
44
|
+
return { error: (error as Error).message }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function cliOutput(result: UserResult, pretty?: boolean): void {
|
|
49
|
+
console.log(formatOutput(result, pretty))
|
|
50
|
+
if (result.error) process.exit(1)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const userCommand = new Command('user')
|
|
54
|
+
.description('User management commands')
|
|
55
|
+
.addCommand(
|
|
56
|
+
new Command('list')
|
|
57
|
+
.description('List followers')
|
|
58
|
+
.option('--next-openid <cursor>', 'Cursor for pagination')
|
|
59
|
+
.option('--account <id>', 'Account ID')
|
|
60
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
61
|
+
.action(async (opts: UserOptions) => {
|
|
62
|
+
cliOutput(await listAction(opts), opts.pretty)
|
|
63
|
+
}),
|
|
64
|
+
)
|
|
65
|
+
.addCommand(
|
|
66
|
+
new Command('get')
|
|
67
|
+
.description('Get user info by OpenID')
|
|
68
|
+
.argument('<open-id>', 'User OpenID')
|
|
69
|
+
.option('--lang <lang>', 'Language (zh_CN, zh_TW, en)', 'zh_CN')
|
|
70
|
+
.option('--account <id>', 'Account ID')
|
|
71
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
72
|
+
.action(async (openId: string, opts: UserOptions) => {
|
|
73
|
+
cliOutput(await getAction(openId, opts), opts.pretty)
|
|
74
|
+
}),
|
|
75
|
+
)
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { afterAll, describe, expect, test } from 'bun:test'
|
|
2
|
+
import { existsSync, rmSync } from 'node:fs'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { WeChatBotCredentialManager } from '@/platforms/wechatbot/credential-manager'
|
|
6
|
+
|
|
7
|
+
const testDirs: string[] = []
|
|
8
|
+
|
|
9
|
+
function setup(): WeChatBotCredentialManager {
|
|
10
|
+
const testConfigDir = join(
|
|
11
|
+
import.meta.dir,
|
|
12
|
+
`.test-wechatbot-config-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
13
|
+
)
|
|
14
|
+
testDirs.push(testConfigDir)
|
|
15
|
+
return new WeChatBotCredentialManager(testConfigDir)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
afterAll(() => {
|
|
19
|
+
for (const dir of testDirs) {
|
|
20
|
+
rmSync(dir, { recursive: true, force: true })
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
describe('WeChatBotCredentialManager', () => {
|
|
25
|
+
test('load returns default config when file does not exist', async () => {
|
|
26
|
+
const manager = setup()
|
|
27
|
+
const config = await manager.load()
|
|
28
|
+
|
|
29
|
+
expect(config).toEqual({
|
|
30
|
+
current: null,
|
|
31
|
+
accounts: {},
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('save creates file with correct content', async () => {
|
|
36
|
+
const testConfigDir = join(
|
|
37
|
+
import.meta.dir,
|
|
38
|
+
`.test-wechatbot-config-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
39
|
+
)
|
|
40
|
+
testDirs.push(testConfigDir)
|
|
41
|
+
const manager = new WeChatBotCredentialManager(testConfigDir)
|
|
42
|
+
const config = {
|
|
43
|
+
current: { account_id: 'wx123' },
|
|
44
|
+
accounts: {
|
|
45
|
+
wx123: {
|
|
46
|
+
app_id: 'wx123',
|
|
47
|
+
app_secret: 'secret123',
|
|
48
|
+
account_name: 'Test Account',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
await manager.save(config)
|
|
54
|
+
|
|
55
|
+
const credentialsPath = join(testConfigDir, 'wechatbot-credentials.json')
|
|
56
|
+
expect(existsSync(credentialsPath)).toBe(true)
|
|
57
|
+
|
|
58
|
+
const file = Bun.file(credentialsPath)
|
|
59
|
+
const content = await file.text()
|
|
60
|
+
const loaded = JSON.parse(content)
|
|
61
|
+
expect(loaded).toEqual(config)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('getCredentials returns null when not configured', async () => {
|
|
65
|
+
const manager = setup()
|
|
66
|
+
const creds = await manager.getCredentials()
|
|
67
|
+
expect(creds).toBeNull()
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test('getCredentials returns credentials from env vars when E2E env vars are set', async () => {
|
|
71
|
+
const originalAppId = process.env.E2E_WECHATBOT_APP_ID
|
|
72
|
+
const originalAppSecret = process.env.E2E_WECHATBOT_APP_SECRET
|
|
73
|
+
|
|
74
|
+
process.env.E2E_WECHATBOT_APP_ID = 'env-app-id'
|
|
75
|
+
process.env.E2E_WECHATBOT_APP_SECRET = 'env-app-secret'
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const manager = setup()
|
|
79
|
+
const creds = await manager.getCredentials()
|
|
80
|
+
expect(creds).toEqual({
|
|
81
|
+
app_id: 'env-app-id',
|
|
82
|
+
app_secret: 'env-app-secret',
|
|
83
|
+
account_name: 'env',
|
|
84
|
+
})
|
|
85
|
+
} finally {
|
|
86
|
+
if (originalAppId === undefined) {
|
|
87
|
+
delete process.env.E2E_WECHATBOT_APP_ID
|
|
88
|
+
} else {
|
|
89
|
+
process.env.E2E_WECHATBOT_APP_ID = originalAppId
|
|
90
|
+
}
|
|
91
|
+
if (originalAppSecret === undefined) {
|
|
92
|
+
delete process.env.E2E_WECHATBOT_APP_SECRET
|
|
93
|
+
} else {
|
|
94
|
+
process.env.E2E_WECHATBOT_APP_SECRET = originalAppSecret
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test('getCredentials ignores env vars when accountId is provided', async () => {
|
|
100
|
+
const originalAppId = process.env.E2E_WECHATBOT_APP_ID
|
|
101
|
+
const originalAppSecret = process.env.E2E_WECHATBOT_APP_SECRET
|
|
102
|
+
|
|
103
|
+
process.env.E2E_WECHATBOT_APP_ID = 'env-app-id'
|
|
104
|
+
process.env.E2E_WECHATBOT_APP_SECRET = 'env-app-secret'
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const manager = setup()
|
|
108
|
+
const creds = await manager.getCredentials('nonexistent-id')
|
|
109
|
+
expect(creds).toBeNull()
|
|
110
|
+
} finally {
|
|
111
|
+
if (originalAppId === undefined) {
|
|
112
|
+
delete process.env.E2E_WECHATBOT_APP_ID
|
|
113
|
+
} else {
|
|
114
|
+
process.env.E2E_WECHATBOT_APP_ID = originalAppId
|
|
115
|
+
}
|
|
116
|
+
if (originalAppSecret === undefined) {
|
|
117
|
+
delete process.env.E2E_WECHATBOT_APP_SECRET
|
|
118
|
+
} else {
|
|
119
|
+
process.env.E2E_WECHATBOT_APP_SECRET = originalAppSecret
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
test('getCredentials returns specific account by accountId', async () => {
|
|
125
|
+
const manager = setup()
|
|
126
|
+
await manager.setCredentials({ app_id: 'wx-a', app_secret: 'secret-a', account_name: 'Account A' })
|
|
127
|
+
await manager.setCredentials({ app_id: 'wx-b', app_secret: 'secret-b', account_name: 'Account B' })
|
|
128
|
+
|
|
129
|
+
const creds = await manager.getCredentials('wx-a')
|
|
130
|
+
expect(creds).toEqual({
|
|
131
|
+
app_id: 'wx-a',
|
|
132
|
+
app_secret: 'secret-a',
|
|
133
|
+
account_name: 'Account A',
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
test('getCredentials returns null for nonexistent accountId', async () => {
|
|
138
|
+
const manager = setup()
|
|
139
|
+
const creds = await manager.getCredentials('nonexistent')
|
|
140
|
+
expect(creds).toBeNull()
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
test('setCredentials saves and sets as current', async () => {
|
|
144
|
+
const manager = setup()
|
|
145
|
+
await manager.setCredentials({ app_id: 'wx123', app_secret: 'secret123', account_name: 'My Account' })
|
|
146
|
+
|
|
147
|
+
const creds = await manager.getCredentials()
|
|
148
|
+
expect(creds).toEqual({
|
|
149
|
+
app_id: 'wx123',
|
|
150
|
+
app_secret: 'secret123',
|
|
151
|
+
account_name: 'My Account',
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
const config = await manager.load()
|
|
155
|
+
expect(config.current).toEqual({ account_id: 'wx123' })
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
test('removeAccount deletes account and adjusts current', async () => {
|
|
159
|
+
const manager = setup()
|
|
160
|
+
await manager.setCredentials({ app_id: 'wx123', app_secret: 'secret123', account_name: 'My Account' })
|
|
161
|
+
|
|
162
|
+
const removed = await manager.removeAccount('wx123')
|
|
163
|
+
expect(removed).toBe(true)
|
|
164
|
+
|
|
165
|
+
const creds = await manager.getCredentials()
|
|
166
|
+
expect(creds).toBeNull()
|
|
167
|
+
|
|
168
|
+
const config = await manager.load()
|
|
169
|
+
expect(config.current).toBeNull()
|
|
170
|
+
expect(config.accounts['wx123']).toBeUndefined()
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test('removeAccount returns false for non-existent account', async () => {
|
|
174
|
+
const manager = setup()
|
|
175
|
+
const removed = await manager.removeAccount('nonexistent')
|
|
176
|
+
expect(removed).toBe(false)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test('removeAccount does not clear current when a different account is removed', async () => {
|
|
180
|
+
const manager = setup()
|
|
181
|
+
await manager.setCredentials({ app_id: 'wx-a', app_secret: 'secret-a', account_name: 'Account A' })
|
|
182
|
+
await manager.setCredentials({ app_id: 'wx-b', app_secret: 'secret-b', account_name: 'Account B' })
|
|
183
|
+
|
|
184
|
+
const removed = await manager.removeAccount('wx-a')
|
|
185
|
+
expect(removed).toBe(true)
|
|
186
|
+
|
|
187
|
+
const config = await manager.load()
|
|
188
|
+
expect(config.current).toEqual({ account_id: 'wx-b' })
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
test('setCurrent switches active account', async () => {
|
|
192
|
+
const manager = setup()
|
|
193
|
+
await manager.setCredentials({ app_id: 'wx-a', app_secret: 'secret-a', account_name: 'Account A' })
|
|
194
|
+
await manager.setCredentials({ app_id: 'wx-b', app_secret: 'secret-b', account_name: 'Account B' })
|
|
195
|
+
|
|
196
|
+
const result = await manager.setCurrent('wx-a')
|
|
197
|
+
expect(result).toBe(true)
|
|
198
|
+
|
|
199
|
+
const config = await manager.load()
|
|
200
|
+
expect(config.current).toEqual({ account_id: 'wx-a' })
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
test('setCurrent returns false for non-existent account', async () => {
|
|
204
|
+
const manager = setup()
|
|
205
|
+
const result = await manager.setCurrent('nonexistent')
|
|
206
|
+
expect(result).toBe(false)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
test('listAll returns all accounts with is_current flag', async () => {
|
|
210
|
+
const manager = setup()
|
|
211
|
+
await manager.setCredentials({ app_id: 'wx-a', app_secret: 'secret-a', account_name: 'Account A' })
|
|
212
|
+
await manager.setCredentials({ app_id: 'wx-b', app_secret: 'secret-b', account_name: 'Account B' })
|
|
213
|
+
|
|
214
|
+
const accounts = await manager.listAll()
|
|
215
|
+
expect(accounts).toHaveLength(2)
|
|
216
|
+
|
|
217
|
+
const acctA = accounts.find((a) => a.app_id === 'wx-a')
|
|
218
|
+
const acctB = accounts.find((a) => a.app_id === 'wx-b')
|
|
219
|
+
|
|
220
|
+
expect(acctA?.is_current).toBe(false)
|
|
221
|
+
expect(acctB?.is_current).toBe(true)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
test('listAll returns empty array when no accounts', async () => {
|
|
225
|
+
const manager = setup()
|
|
226
|
+
const accounts = await manager.listAll()
|
|
227
|
+
expect(accounts).toHaveLength(0)
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
test('clearCredentials resets everything', async () => {
|
|
231
|
+
const manager = setup()
|
|
232
|
+
await manager.setCredentials({ app_id: 'wx123', app_secret: 'secret123', account_name: 'My Account' })
|
|
233
|
+
|
|
234
|
+
await manager.clearCredentials()
|
|
235
|
+
|
|
236
|
+
const config = await manager.load()
|
|
237
|
+
expect(config.current).toBeNull()
|
|
238
|
+
expect(config.accounts).toEqual({})
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
test('round-trip: set → get → remove → get null', async () => {
|
|
242
|
+
const manager = setup()
|
|
243
|
+
|
|
244
|
+
await manager.setCredentials({ app_id: 'wx123', app_secret: 'secret123', account_name: 'My Account' })
|
|
245
|
+
|
|
246
|
+
const creds = await manager.getCredentials()
|
|
247
|
+
expect(creds?.app_id).toBe('wx123')
|
|
248
|
+
expect(creds?.app_secret).toBe('secret123')
|
|
249
|
+
|
|
250
|
+
await manager.removeAccount('wx123')
|
|
251
|
+
|
|
252
|
+
const afterRemove = await manager.getCredentials()
|
|
253
|
+
expect(afterRemove).toBeNull()
|
|
254
|
+
})
|
|
255
|
+
})
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
|
|
6
|
+
import type { WeChatBotAccountEntry, WeChatBotConfig, WeChatBotCredentials } from './types'
|
|
7
|
+
import { WeChatBotConfigSchema } from './types'
|
|
8
|
+
|
|
9
|
+
export class WeChatBotCredentialManager {
|
|
10
|
+
private configDir: string
|
|
11
|
+
private credentialsPath: string
|
|
12
|
+
|
|
13
|
+
constructor(configDir?: string) {
|
|
14
|
+
this.configDir = configDir ?? join(homedir(), '.config', 'agent-messenger')
|
|
15
|
+
this.credentialsPath = join(this.configDir, 'wechatbot-credentials.json')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async load(): Promise<WeChatBotConfig> {
|
|
19
|
+
if (!existsSync(this.credentialsPath)) {
|
|
20
|
+
return { current: null, accounts: {} }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const content = await readFile(this.credentialsPath, 'utf-8')
|
|
24
|
+
let json: unknown
|
|
25
|
+
try {
|
|
26
|
+
json = JSON.parse(content)
|
|
27
|
+
} catch {
|
|
28
|
+
return { current: null, accounts: {} }
|
|
29
|
+
}
|
|
30
|
+
const parsed = WeChatBotConfigSchema.safeParse(json)
|
|
31
|
+
if (!parsed.success) {
|
|
32
|
+
return { current: null, accounts: {} }
|
|
33
|
+
}
|
|
34
|
+
return parsed.data
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async save(config: WeChatBotConfig): Promise<void> {
|
|
38
|
+
await mkdir(this.configDir, { recursive: true })
|
|
39
|
+
await writeFile(this.credentialsPath, JSON.stringify(config, null, 2), { mode: 0o600 })
|
|
40
|
+
await chmod(this.credentialsPath, 0o600)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async getCredentials(accountId?: string): Promise<WeChatBotCredentials | null> {
|
|
44
|
+
const envAppId = process.env.E2E_WECHATBOT_APP_ID
|
|
45
|
+
const envAppSecret = process.env.E2E_WECHATBOT_APP_SECRET
|
|
46
|
+
|
|
47
|
+
if (envAppId && envAppSecret && !accountId) {
|
|
48
|
+
return {
|
|
49
|
+
app_id: envAppId,
|
|
50
|
+
app_secret: envAppSecret,
|
|
51
|
+
account_name: 'env',
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const config = await this.load()
|
|
56
|
+
|
|
57
|
+
if (accountId) {
|
|
58
|
+
const account = config.accounts[accountId]
|
|
59
|
+
if (!account) return null
|
|
60
|
+
return {
|
|
61
|
+
app_id: account.app_id,
|
|
62
|
+
app_secret: account.app_secret,
|
|
63
|
+
account_name: account.account_name,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!config.current) {
|
|
68
|
+
return null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const account = config.accounts[config.current.account_id]
|
|
72
|
+
if (!account) return null
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
app_id: account.app_id,
|
|
76
|
+
app_secret: account.app_secret,
|
|
77
|
+
account_name: account.account_name,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async setCredentials(entry: WeChatBotAccountEntry): Promise<void> {
|
|
82
|
+
const config = await this.load()
|
|
83
|
+
|
|
84
|
+
config.accounts[entry.app_id] = {
|
|
85
|
+
app_id: entry.app_id,
|
|
86
|
+
app_secret: entry.app_secret,
|
|
87
|
+
account_name: entry.account_name,
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
config.current = {
|
|
91
|
+
account_id: entry.app_id,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
await this.save(config)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async removeAccount(accountId: string): Promise<boolean> {
|
|
98
|
+
const config = await this.load()
|
|
99
|
+
|
|
100
|
+
if (!config.accounts[accountId]) {
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
delete config.accounts[accountId]
|
|
105
|
+
|
|
106
|
+
if (config.current?.account_id === accountId) {
|
|
107
|
+
config.current = null
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
await this.save(config)
|
|
111
|
+
return true
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async setCurrent(accountId: string): Promise<boolean> {
|
|
115
|
+
const config = await this.load()
|
|
116
|
+
|
|
117
|
+
if (!config.accounts[accountId]) {
|
|
118
|
+
return false
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
config.current = {
|
|
122
|
+
account_id: accountId,
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
await this.save(config)
|
|
126
|
+
return true
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async listAll(): Promise<Array<WeChatBotAccountEntry & { is_current: boolean }>> {
|
|
130
|
+
const config = await this.load()
|
|
131
|
+
const results: Array<WeChatBotAccountEntry & { is_current: boolean }> = []
|
|
132
|
+
|
|
133
|
+
for (const account of Object.values(config.accounts)) {
|
|
134
|
+
results.push({
|
|
135
|
+
app_id: account.app_id,
|
|
136
|
+
app_secret: account.app_secret,
|
|
137
|
+
account_name: account.account_name,
|
|
138
|
+
is_current: config.current?.account_id === account.app_id,
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return results
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async clearCredentials(): Promise<void> {
|
|
146
|
+
await this.save({ current: null, accounts: {} })
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
WeChatBotAccountEntrySchema,
|
|
5
|
+
WeChatBotClient,
|
|
6
|
+
WeChatBotConfigSchema,
|
|
7
|
+
WeChatBotCredentialManager,
|
|
8
|
+
WeChatBotCredentialsSchema,
|
|
9
|
+
WeChatBotError,
|
|
10
|
+
WeChatBotNewsArticleSchema,
|
|
11
|
+
WeChatBotTemplateSchema,
|
|
12
|
+
WeChatBotUserInfoSchema,
|
|
13
|
+
} from '@/platforms/wechatbot/index'
|
|
14
|
+
|
|
15
|
+
test('WeChatBotClient is exported from barrel', () => {
|
|
16
|
+
expect(typeof WeChatBotClient).toBe('function')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('WeChatBotCredentialManager is exported from barrel', () => {
|
|
20
|
+
expect(typeof WeChatBotCredentialManager).toBe('function')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('WeChatBotError is exported from barrel', () => {
|
|
24
|
+
expect(typeof WeChatBotError).toBe('function')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('WeChatBotAccountEntrySchema is exported from barrel', () => {
|
|
28
|
+
expect(typeof WeChatBotAccountEntrySchema.parse).toBe('function')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('WeChatBotConfigSchema is exported from barrel', () => {
|
|
32
|
+
expect(typeof WeChatBotConfigSchema.parse).toBe('function')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('WeChatBotCredentialsSchema is exported from barrel', () => {
|
|
36
|
+
expect(typeof WeChatBotCredentialsSchema.parse).toBe('function')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('WeChatBotNewsArticleSchema is exported from barrel', () => {
|
|
40
|
+
expect(typeof WeChatBotNewsArticleSchema.parse).toBe('function')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('WeChatBotTemplateSchema is exported from barrel', () => {
|
|
44
|
+
expect(typeof WeChatBotTemplateSchema.parse).toBe('function')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('WeChatBotUserInfoSchema is exported from barrel', () => {
|
|
48
|
+
expect(typeof WeChatBotUserInfoSchema.parse).toBe('function')
|
|
49
|
+
})
|