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.
Files changed (229) hide show
  1. package/.claude-plugin/README.md +16 -16
  2. package/.claude-plugin/marketplace.json +29 -29
  3. package/.claude-plugin/plugin.json +5 -5
  4. package/CONTRIBUTING.md +1 -1
  5. package/README.md +9 -6
  6. package/bun.lock +89 -105
  7. package/bunfig.toml +3 -0
  8. package/dist/package.json +13 -3
  9. package/dist/src/platforms/discordbot/client.js +2 -2
  10. package/dist/src/platforms/discordbot/client.js.map +1 -1
  11. package/dist/src/platforms/kakaotalk/cli.d.ts.map +1 -1
  12. package/dist/src/platforms/kakaotalk/cli.js +2 -1
  13. package/dist/src/platforms/kakaotalk/cli.js.map +1 -1
  14. package/dist/src/platforms/kakaotalk/client.d.ts +2 -1
  15. package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
  16. package/dist/src/platforms/kakaotalk/client.js +52 -2
  17. package/dist/src/platforms/kakaotalk/client.js.map +1 -1
  18. package/dist/src/platforms/kakaotalk/commands/index.d.ts +1 -0
  19. package/dist/src/platforms/kakaotalk/commands/index.d.ts.map +1 -1
  20. package/dist/src/platforms/kakaotalk/commands/index.js +1 -0
  21. package/dist/src/platforms/kakaotalk/commands/index.js.map +1 -1
  22. package/dist/src/platforms/kakaotalk/commands/profile.d.ts +3 -0
  23. package/dist/src/platforms/kakaotalk/commands/profile.d.ts.map +1 -0
  24. package/dist/src/platforms/kakaotalk/commands/profile.js +19 -0
  25. package/dist/src/platforms/kakaotalk/commands/profile.js.map +1 -0
  26. package/dist/src/platforms/kakaotalk/index.d.ts +2 -2
  27. package/dist/src/platforms/kakaotalk/index.d.ts.map +1 -1
  28. package/dist/src/platforms/kakaotalk/index.js +1 -1
  29. package/dist/src/platforms/kakaotalk/index.js.map +1 -1
  30. package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
  31. package/dist/src/platforms/kakaotalk/protocol/session.js +2 -1
  32. package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
  33. package/dist/src/platforms/kakaotalk/types.d.ts +16 -0
  34. package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
  35. package/dist/src/platforms/kakaotalk/types.js +8 -0
  36. package/dist/src/platforms/kakaotalk/types.js.map +1 -1
  37. package/dist/src/platforms/line/commands/auth.d.ts.map +1 -1
  38. package/dist/src/platforms/line/commands/auth.js +32 -20
  39. package/dist/src/platforms/line/commands/auth.js.map +1 -1
  40. package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -1
  41. package/dist/src/platforms/teams/commands/reaction.js +2 -0
  42. package/dist/src/platforms/teams/commands/reaction.js.map +1 -1
  43. package/dist/src/platforms/webex/client.d.ts +2 -0
  44. package/dist/src/platforms/webex/client.d.ts.map +1 -1
  45. package/dist/src/platforms/webex/client.js +66 -23
  46. package/dist/src/platforms/webex/client.js.map +1 -1
  47. package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
  48. package/dist/src/platforms/webex/commands/auth.js +4 -0
  49. package/dist/src/platforms/webex/commands/auth.js.map +1 -1
  50. package/dist/src/platforms/webex/encryption.d.ts +10 -0
  51. package/dist/src/platforms/webex/encryption.d.ts.map +1 -0
  52. package/dist/src/platforms/webex/encryption.js +49 -0
  53. package/dist/src/platforms/webex/encryption.js.map +1 -0
  54. package/dist/src/platforms/webex/ensure-auth.d.ts.map +1 -1
  55. package/dist/src/platforms/webex/ensure-auth.js +4 -0
  56. package/dist/src/platforms/webex/ensure-auth.js.map +1 -1
  57. package/dist/src/platforms/webex/token-extractor.d.ts +6 -5
  58. package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
  59. package/dist/src/platforms/webex/token-extractor.js +92 -43
  60. package/dist/src/platforms/webex/token-extractor.js.map +1 -1
  61. package/dist/src/platforms/webex/types.d.ts +4 -0
  62. package/dist/src/platforms/webex/types.d.ts.map +1 -1
  63. package/dist/src/platforms/webex/types.js +2 -0
  64. package/dist/src/platforms/webex/types.js.map +1 -1
  65. package/dist/src/platforms/wechatbot/cli.d.ts +5 -0
  66. package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -0
  67. package/dist/src/platforms/wechatbot/cli.js +18 -0
  68. package/dist/src/platforms/wechatbot/cli.js.map +1 -0
  69. package/dist/src/platforms/wechatbot/client.d.ts +36 -0
  70. package/dist/src/platforms/wechatbot/client.d.ts.map +1 -0
  71. package/dist/src/platforms/wechatbot/client.js +208 -0
  72. package/dist/src/platforms/wechatbot/client.js.map +1 -0
  73. package/dist/src/platforms/wechatbot/commands/auth.d.ts +28 -0
  74. package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -0
  75. package/dist/src/platforms/wechatbot/commands/auth.js +164 -0
  76. package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -0
  77. package/dist/src/platforms/wechatbot/commands/index.d.ts +5 -0
  78. package/dist/src/platforms/wechatbot/commands/index.d.ts.map +1 -0
  79. package/dist/src/platforms/wechatbot/commands/index.js +5 -0
  80. package/dist/src/platforms/wechatbot/commands/index.js.map +1 -0
  81. package/dist/src/platforms/wechatbot/commands/message.d.ts +18 -0
  82. package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -0
  83. package/dist/src/platforms/wechatbot/commands/message.js +80 -0
  84. package/dist/src/platforms/wechatbot/commands/message.js.map +1 -0
  85. package/dist/src/platforms/wechatbot/commands/shared.d.ts +9 -0
  86. package/dist/src/platforms/wechatbot/commands/shared.d.ts.map +1 -0
  87. package/dist/src/platforms/wechatbot/commands/shared.js +13 -0
  88. package/dist/src/platforms/wechatbot/commands/shared.js.map +1 -0
  89. package/dist/src/platforms/wechatbot/commands/template.d.ts +19 -0
  90. package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -0
  91. package/dist/src/platforms/wechatbot/commands/template.js +76 -0
  92. package/dist/src/platforms/wechatbot/commands/template.js.map +1 -0
  93. package/dist/src/platforms/wechatbot/commands/user.d.ts +20 -0
  94. package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -0
  95. package/dist/src/platforms/wechatbot/commands/user.js +53 -0
  96. package/dist/src/platforms/wechatbot/commands/user.js.map +1 -0
  97. package/dist/src/platforms/wechatbot/credential-manager.d.ts +17 -0
  98. package/dist/src/platforms/wechatbot/credential-manager.d.ts.map +1 -0
  99. package/dist/src/platforms/wechatbot/credential-manager.js +121 -0
  100. package/dist/src/platforms/wechatbot/credential-manager.js.map +1 -0
  101. package/dist/src/platforms/wechatbot/index.d.ts +5 -0
  102. package/dist/src/platforms/wechatbot/index.d.ts.map +1 -0
  103. package/dist/src/platforms/wechatbot/index.js +4 -0
  104. package/dist/src/platforms/wechatbot/index.js.map +1 -0
  105. package/dist/src/platforms/wechatbot/types.d.ts +94 -0
  106. package/dist/src/platforms/wechatbot/types.d.ts.map +1 -0
  107. package/dist/src/platforms/wechatbot/types.js +54 -0
  108. package/dist/src/platforms/wechatbot/types.js.map +1 -0
  109. package/dist/src/platforms/whatsapp/client.d.ts +1 -0
  110. package/dist/src/platforms/whatsapp/client.d.ts.map +1 -1
  111. package/dist/src/platforms/whatsapp/client.js +27 -13
  112. package/dist/src/platforms/whatsapp/client.js.map +1 -1
  113. package/dist/src/platforms/whatsapp/commands/auth.d.ts.map +1 -1
  114. package/dist/src/platforms/whatsapp/commands/auth.js +21 -18
  115. package/dist/src/platforms/whatsapp/commands/auth.js.map +1 -1
  116. package/dist/src/platforms/whatsapp/credential-manager.d.ts.map +1 -1
  117. package/dist/src/platforms/whatsapp/credential-manager.js +14 -8
  118. package/dist/src/platforms/whatsapp/credential-manager.js.map +1 -1
  119. package/docs/content/docs/agent-skills.mdx +4 -4
  120. package/docs/content/docs/cli/channeltalk.mdx +1 -1
  121. package/docs/content/docs/cli/channeltalkbot.mdx +1 -1
  122. package/docs/content/docs/cli/discord.mdx +1 -1
  123. package/docs/content/docs/cli/discordbot.mdx +1 -1
  124. package/docs/content/docs/cli/instagram.mdx +1 -1
  125. package/docs/content/docs/cli/kakaotalk.mdx +1 -1
  126. package/docs/content/docs/cli/line.mdx +1 -1
  127. package/docs/content/docs/cli/meta.json +1 -0
  128. package/docs/content/docs/cli/slack.mdx +1 -1
  129. package/docs/content/docs/cli/slackbot.mdx +1 -1
  130. package/docs/content/docs/cli/teams.mdx +1 -1
  131. package/docs/content/docs/cli/webex.mdx +5 -3
  132. package/docs/content/docs/cli/wechatbot.mdx +179 -0
  133. package/docs/content/docs/cli/whatsapp.mdx +1 -1
  134. package/docs/content/docs/cli/whatsappbot.mdx +1 -1
  135. package/docs/content/docs/sdk/meta.json +1 -1
  136. package/docs/content/docs/sdk/wechatbot.mdx +282 -0
  137. package/docs/content/docs/tui.mdx +1 -1
  138. package/docs/src/app/page.tsx +5 -5
  139. package/package.json +13 -3
  140. package/skills/agent-channeltalk/SKILL.md +1 -1
  141. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  142. package/skills/agent-discord/SKILL.md +1 -1
  143. package/skills/agent-discordbot/SKILL.md +1 -1
  144. package/skills/agent-instagram/SKILL.md +1 -1
  145. package/skills/agent-kakaotalk/SKILL.md +24 -1
  146. package/skills/agent-line/SKILL.md +7 -11
  147. package/skills/agent-line/references/authentication.md +13 -4
  148. package/skills/agent-slack/SKILL.md +1 -1
  149. package/skills/agent-slackbot/SKILL.md +1 -1
  150. package/skills/agent-teams/SKILL.md +1 -1
  151. package/skills/agent-telegram/SKILL.md +1 -1
  152. package/skills/agent-webex/SKILL.md +1 -1
  153. package/skills/agent-webex/references/authentication.md +4 -3
  154. package/skills/agent-webex/references/common-patterns.md +1 -1
  155. package/skills/agent-wechatbot/SKILL.md +385 -0
  156. package/skills/agent-whatsapp/SKILL.md +12 -1
  157. package/skills/agent-whatsappbot/SKILL.md +1 -1
  158. package/src/platforms/discord/credential-manager.test.ts +18 -1
  159. package/src/platforms/discordbot/client.ts +2 -2
  160. package/src/platforms/instagram/commands/auth.test.ts +216 -0
  161. package/src/platforms/instagram/commands/chat.test.ts +127 -0
  162. package/src/platforms/instagram/commands/message.test.ts +178 -0
  163. package/src/platforms/kakaotalk/cli.ts +2 -1
  164. package/src/platforms/kakaotalk/client.test.ts +157 -0
  165. package/src/platforms/kakaotalk/client.ts +57 -3
  166. package/src/platforms/kakaotalk/commands/auth.test.ts +299 -0
  167. package/src/platforms/kakaotalk/commands/chat.test.ts +97 -0
  168. package/src/platforms/kakaotalk/commands/index.ts +1 -0
  169. package/src/platforms/kakaotalk/commands/message.test.ts +113 -0
  170. package/src/platforms/kakaotalk/commands/profile.test.ts +84 -0
  171. package/src/platforms/kakaotalk/commands/profile.ts +21 -0
  172. package/src/platforms/kakaotalk/index.test.ts +5 -0
  173. package/src/platforms/kakaotalk/index.ts +2 -0
  174. package/src/platforms/kakaotalk/protocol/session.ts +2 -0
  175. package/src/platforms/kakaotalk/types.ts +18 -0
  176. package/src/platforms/line/commands/auth.test.ts +141 -0
  177. package/src/platforms/line/commands/auth.ts +28 -19
  178. package/src/platforms/line/commands/chat.test.ts +110 -0
  179. package/src/platforms/line/commands/friend.test.ts +98 -0
  180. package/src/platforms/line/commands/message.test.ts +119 -0
  181. package/src/platforms/line/commands/profile.test.ts +85 -0
  182. package/src/platforms/slackbot/commands/channel.test.ts +139 -0
  183. package/src/platforms/slackbot/commands/message.test.ts +226 -0
  184. package/src/platforms/slackbot/commands/reaction.test.ts +90 -0
  185. package/src/platforms/slackbot/commands/user.test.ts +143 -0
  186. package/src/platforms/teams/commands/reaction.test.ts +45 -61
  187. package/src/platforms/teams/commands/reaction.ts +2 -0
  188. package/src/platforms/telegram/commands/chat.test.ts +125 -0
  189. package/src/platforms/telegram/commands/message.test.ts +92 -0
  190. package/src/platforms/webex/client.ts +98 -26
  191. package/src/platforms/webex/commands/auth.ts +4 -0
  192. package/src/platforms/webex/commands/member.test.ts +65 -58
  193. package/src/platforms/webex/commands/message.test.ts +78 -121
  194. package/src/platforms/webex/commands/snapshot.test.ts +59 -46
  195. package/src/platforms/webex/commands/space.test.ts +49 -48
  196. package/src/platforms/webex/encryption.ts +53 -0
  197. package/src/platforms/webex/ensure-auth.ts +4 -0
  198. package/src/platforms/webex/token-extractor.ts +107 -40
  199. package/src/platforms/webex/types.ts +4 -0
  200. package/src/platforms/webex/typings/node-jose.d.ts +27 -0
  201. package/src/platforms/wechatbot/cli.ts +24 -0
  202. package/src/platforms/wechatbot/client.test.ts +497 -0
  203. package/src/platforms/wechatbot/client.ts +268 -0
  204. package/src/platforms/wechatbot/commands/auth.test.ts +211 -0
  205. package/src/platforms/wechatbot/commands/auth.ts +203 -0
  206. package/src/platforms/wechatbot/commands/index.ts +4 -0
  207. package/src/platforms/wechatbot/commands/message.test.ts +155 -0
  208. package/src/platforms/wechatbot/commands/message.ts +104 -0
  209. package/src/platforms/wechatbot/commands/shared.ts +22 -0
  210. package/src/platforms/wechatbot/commands/template.test.ts +199 -0
  211. package/src/platforms/wechatbot/commands/template.ts +102 -0
  212. package/src/platforms/wechatbot/commands/user.test.ts +165 -0
  213. package/src/platforms/wechatbot/commands/user.ts +75 -0
  214. package/src/platforms/wechatbot/credential-manager.test.ts +255 -0
  215. package/src/platforms/wechatbot/credential-manager.ts +148 -0
  216. package/src/platforms/wechatbot/index.test.ts +49 -0
  217. package/src/platforms/wechatbot/index.ts +19 -0
  218. package/src/platforms/wechatbot/types.test.ts +223 -0
  219. package/src/platforms/wechatbot/types.ts +107 -0
  220. package/src/platforms/whatsapp/client.ts +24 -13
  221. package/src/platforms/whatsapp/commands/auth.test.ts +311 -0
  222. package/src/platforms/whatsapp/commands/auth.ts +21 -17
  223. package/src/platforms/whatsapp/commands/chat.test.ts +198 -0
  224. package/src/platforms/whatsapp/commands/message.test.ts +231 -0
  225. package/src/platforms/whatsapp/credential-manager.test.ts +20 -0
  226. package/src/platforms/whatsapp/credential-manager.ts +17 -8
  227. package/src/platforms/whatsappbot/commands/auth.test.ts +217 -0
  228. package/src/platforms/whatsappbot/commands/message.test.ts +198 -0
  229. package/src/platforms/whatsappbot/commands/template.test.ts +112 -0
@@ -0,0 +1,19 @@
1
+ export { WeChatBotClient } from './client'
2
+ export { WeChatBotCredentialManager } from './credential-manager'
3
+ export type {
4
+ WeChatBotAccountEntry,
5
+ WeChatBotConfig,
6
+ WeChatBotCredentials,
7
+ WeChatBotNewsArticle,
8
+ WeChatBotTemplate,
9
+ WeChatBotUserInfo,
10
+ } from './types'
11
+ export {
12
+ WeChatBotAccountEntrySchema,
13
+ WeChatBotConfigSchema,
14
+ WeChatBotCredentialsSchema,
15
+ WeChatBotError,
16
+ WeChatBotNewsArticleSchema,
17
+ WeChatBotTemplateSchema,
18
+ WeChatBotUserInfoSchema,
19
+ } from './types'
@@ -0,0 +1,223 @@
1
+ import { expect, test } from 'bun:test'
2
+
3
+ import {
4
+ WeChatBotAccountEntrySchema,
5
+ WeChatBotConfigSchema,
6
+ WeChatBotCredentialsSchema,
7
+ WeChatBotError,
8
+ WeChatBotNewsArticleSchema,
9
+ WeChatBotTemplateSchema,
10
+ WeChatBotUserInfoSchema,
11
+ } from '@/platforms/wechatbot/types'
12
+
13
+ test('WeChatBotAccountEntrySchema validates correct data', () => {
14
+ const result = WeChatBotAccountEntrySchema.safeParse({
15
+ app_id: 'wx123',
16
+ app_secret: 'secret123',
17
+ account_name: 'My Account',
18
+ })
19
+ expect(result.success).toBe(true)
20
+ })
21
+
22
+ test('WeChatBotAccountEntrySchema rejects missing app_id', () => {
23
+ const result = WeChatBotAccountEntrySchema.safeParse({
24
+ app_secret: 'secret123',
25
+ account_name: 'My Account',
26
+ })
27
+ expect(result.success).toBe(false)
28
+ })
29
+
30
+ test('WeChatBotAccountEntrySchema rejects missing app_secret', () => {
31
+ const result = WeChatBotAccountEntrySchema.safeParse({
32
+ app_id: 'wx123',
33
+ account_name: 'My Account',
34
+ })
35
+ expect(result.success).toBe(false)
36
+ })
37
+
38
+ test('WeChatBotAccountEntrySchema rejects missing account_name', () => {
39
+ const result = WeChatBotAccountEntrySchema.safeParse({
40
+ app_id: 'wx123',
41
+ app_secret: 'secret123',
42
+ })
43
+ expect(result.success).toBe(false)
44
+ })
45
+
46
+ test('WeChatBotConfigSchema validates with current account', () => {
47
+ const result = WeChatBotConfigSchema.safeParse({
48
+ current: { account_id: 'wx123' },
49
+ accounts: {
50
+ wx123: { app_id: 'wx123', app_secret: 'secret123', account_name: 'My Account' },
51
+ },
52
+ })
53
+ expect(result.success).toBe(true)
54
+ })
55
+
56
+ test('WeChatBotConfigSchema validates with current null and empty accounts', () => {
57
+ const result = WeChatBotConfigSchema.safeParse({
58
+ current: null,
59
+ accounts: {},
60
+ })
61
+ expect(result.success).toBe(true)
62
+ })
63
+
64
+ test('WeChatBotConfigSchema validates with multiple accounts', () => {
65
+ const result = WeChatBotConfigSchema.safeParse({
66
+ current: { account_id: 'wx-a' },
67
+ accounts: {
68
+ 'wx-a': { app_id: 'wx-a', app_secret: 'secret-a', account_name: 'Account A' },
69
+ 'wx-b': { app_id: 'wx-b', app_secret: 'secret-b', account_name: 'Account B' },
70
+ },
71
+ })
72
+ expect(result.success).toBe(true)
73
+ })
74
+
75
+ test('WeChatBotConfigSchema rejects missing accounts field', () => {
76
+ const result = WeChatBotConfigSchema.safeParse({ current: null })
77
+ expect(result.success).toBe(false)
78
+ })
79
+
80
+ test('WeChatBotConfigSchema rejects missing current field', () => {
81
+ const result = WeChatBotConfigSchema.safeParse({ accounts: {} })
82
+ expect(result.success).toBe(false)
83
+ })
84
+
85
+ test('WeChatBotCredentialsSchema validates correct data', () => {
86
+ const result = WeChatBotCredentialsSchema.safeParse({
87
+ app_id: 'wx123',
88
+ app_secret: 'secret123',
89
+ account_name: 'My Account',
90
+ })
91
+ expect(result.success).toBe(true)
92
+ })
93
+
94
+ test('WeChatBotCredentialsSchema rejects missing app_id', () => {
95
+ const result = WeChatBotCredentialsSchema.safeParse({
96
+ app_secret: 'secret123',
97
+ account_name: 'My Account',
98
+ })
99
+ expect(result.success).toBe(false)
100
+ })
101
+
102
+ test('WeChatBotCredentialsSchema rejects missing app_secret', () => {
103
+ const result = WeChatBotCredentialsSchema.safeParse({
104
+ app_id: 'wx123',
105
+ account_name: 'My Account',
106
+ })
107
+ expect(result.success).toBe(false)
108
+ })
109
+
110
+ test('WeChatBotCredentialsSchema rejects missing account_name', () => {
111
+ const result = WeChatBotCredentialsSchema.safeParse({
112
+ app_id: 'wx123',
113
+ app_secret: 'secret123',
114
+ })
115
+ expect(result.success).toBe(false)
116
+ })
117
+
118
+ test('WeChatBotNewsArticleSchema validates correct data', () => {
119
+ const result = WeChatBotNewsArticleSchema.safeParse({
120
+ title: 'Test Article',
121
+ description: 'Test description',
122
+ url: 'https://example.com',
123
+ picurl: 'https://example.com/pic.jpg',
124
+ })
125
+ expect(result.success).toBe(true)
126
+ })
127
+
128
+ test('WeChatBotNewsArticleSchema rejects missing title', () => {
129
+ const result = WeChatBotNewsArticleSchema.safeParse({
130
+ description: 'Test description',
131
+ url: 'https://example.com',
132
+ picurl: 'https://example.com/pic.jpg',
133
+ })
134
+ expect(result.success).toBe(false)
135
+ })
136
+
137
+ test('WeChatBotTemplateSchema validates correct data', () => {
138
+ const result = WeChatBotTemplateSchema.safeParse({
139
+ template_id: 'tmpl-001',
140
+ title: 'Order Notification',
141
+ primary_industry: 'IT科技',
142
+ deputy_industry: '互联网|电子商务',
143
+ content: 'ORDER_STATUS {{status.DATA}}',
144
+ example: 'Order shipped',
145
+ })
146
+ expect(result.success).toBe(true)
147
+ })
148
+
149
+ test('WeChatBotTemplateSchema rejects missing template_id', () => {
150
+ const result = WeChatBotTemplateSchema.safeParse({
151
+ title: 'Order Notification',
152
+ primary_industry: 'IT科技',
153
+ deputy_industry: '互联网|电子商务',
154
+ content: 'ORDER_STATUS {{status.DATA}}',
155
+ example: 'Order shipped',
156
+ })
157
+ expect(result.success).toBe(false)
158
+ })
159
+
160
+ test('WeChatBotUserInfoSchema validates correct data', () => {
161
+ const result = WeChatBotUserInfoSchema.safeParse({
162
+ subscribe: 1,
163
+ openid: 'openid-123',
164
+ language: 'zh_CN',
165
+ subscribe_time: 1609459200,
166
+ remark: '',
167
+ tagid_list: [1, 2],
168
+ subscribe_scene: 'ADD_SCENE_QR_CODE',
169
+ qr_scene: 0,
170
+ qr_scene_str: '',
171
+ })
172
+ expect(result.success).toBe(true)
173
+ })
174
+
175
+ test('WeChatBotUserInfoSchema validates with optional unionid', () => {
176
+ const result = WeChatBotUserInfoSchema.safeParse({
177
+ subscribe: 1,
178
+ openid: 'openid-123',
179
+ language: 'zh_CN',
180
+ subscribe_time: 1609459200,
181
+ unionid: 'union-id-xyz',
182
+ remark: '',
183
+ tagid_list: [],
184
+ subscribe_scene: 'ADD_SCENE_SEARCH',
185
+ qr_scene: 0,
186
+ qr_scene_str: '',
187
+ })
188
+ expect(result.success).toBe(true)
189
+ })
190
+
191
+ test('WeChatBotUserInfoSchema rejects missing openid', () => {
192
+ const result = WeChatBotUserInfoSchema.safeParse({
193
+ subscribe: 1,
194
+ language: 'zh_CN',
195
+ subscribe_time: 1609459200,
196
+ remark: '',
197
+ tagid_list: [],
198
+ subscribe_scene: 'ADD_SCENE_QR_CODE',
199
+ qr_scene: 0,
200
+ qr_scene_str: '',
201
+ })
202
+ expect(result.success).toBe(false)
203
+ })
204
+
205
+ test('WeChatBotError has correct name', () => {
206
+ const error = new WeChatBotError('Test error', 'TEST_CODE')
207
+ expect(error.name).toBe('WeChatBotError')
208
+ })
209
+
210
+ test('WeChatBotError has correct message', () => {
211
+ const error = new WeChatBotError('Test error', 'TEST_CODE')
212
+ expect(error.message).toBe('Test error')
213
+ })
214
+
215
+ test('WeChatBotError has correct code', () => {
216
+ const error = new WeChatBotError('Test error', 'TEST_CODE')
217
+ expect(error.code).toBe('TEST_CODE')
218
+ })
219
+
220
+ test('WeChatBotError is instance of Error', () => {
221
+ const error = new WeChatBotError('Test error', 'TEST_CODE')
222
+ expect(error instanceof Error).toBe(true)
223
+ })
@@ -0,0 +1,107 @@
1
+ import { z } from 'zod'
2
+
3
+ export interface WeChatBotAccountEntry {
4
+ app_id: string
5
+ app_secret: string
6
+ account_name: string
7
+ }
8
+
9
+ export interface WeChatBotConfig {
10
+ current: { account_id: string } | null
11
+ accounts: Record<string, WeChatBotAccountEntry>
12
+ }
13
+
14
+ export interface WeChatBotCredentials {
15
+ app_id: string
16
+ app_secret: string
17
+ account_name: string
18
+ }
19
+
20
+ export interface WeChatBotNewsArticle {
21
+ title: string
22
+ description: string
23
+ url: string
24
+ picurl: string
25
+ }
26
+
27
+ export interface WeChatBotTemplate {
28
+ template_id: string
29
+ title: string
30
+ primary_industry: string
31
+ deputy_industry: string
32
+ content: string
33
+ example: string
34
+ }
35
+
36
+ export interface WeChatBotUserInfo {
37
+ subscribe: number
38
+ openid: string
39
+ language: string
40
+ subscribe_time: number
41
+ unionid?: string
42
+ remark: string
43
+ tagid_list: number[]
44
+ subscribe_scene: string
45
+ qr_scene: number
46
+ qr_scene_str: string
47
+ }
48
+
49
+ export class WeChatBotError extends Error {
50
+ code: string
51
+
52
+ constructor(message: string, code: string) {
53
+ super(message)
54
+ this.name = 'WeChatBotError'
55
+ this.code = code
56
+ }
57
+ }
58
+
59
+ export const WeChatBotAccountEntrySchema = z.object({
60
+ app_id: z.string(),
61
+ app_secret: z.string(),
62
+ account_name: z.string(),
63
+ })
64
+
65
+ export const WeChatBotConfigSchema = z.object({
66
+ current: z
67
+ .object({
68
+ account_id: z.string(),
69
+ })
70
+ .nullable(),
71
+ accounts: z.record(z.string(), WeChatBotAccountEntrySchema),
72
+ })
73
+
74
+ export const WeChatBotCredentialsSchema = z.object({
75
+ app_id: z.string(),
76
+ app_secret: z.string(),
77
+ account_name: z.string(),
78
+ })
79
+
80
+ export const WeChatBotNewsArticleSchema = z.object({
81
+ title: z.string(),
82
+ description: z.string(),
83
+ url: z.string(),
84
+ picurl: z.string(),
85
+ })
86
+
87
+ export const WeChatBotTemplateSchema = z.object({
88
+ template_id: z.string(),
89
+ title: z.string(),
90
+ primary_industry: z.string(),
91
+ deputy_industry: z.string(),
92
+ content: z.string(),
93
+ example: z.string(),
94
+ })
95
+
96
+ export const WeChatBotUserInfoSchema = z.object({
97
+ subscribe: z.number(),
98
+ openid: z.string(),
99
+ language: z.string(),
100
+ subscribe_time: z.number(),
101
+ unionid: z.string().optional(),
102
+ remark: z.string(),
103
+ tagid_list: z.array(z.number()),
104
+ subscribe_scene: z.string(),
105
+ qr_scene: z.number(),
106
+ qr_scene_str: z.string(),
107
+ })
@@ -86,6 +86,7 @@ export class WhatsAppClient {
86
86
  private pendingResolve: (() => void) | null = null
87
87
  private pendingPromise: Promise<void> | null = null
88
88
  private authCompleteResolve: (() => void) | null = null
89
+ private authCompleteReject: ((err: Error) => void) | null = null
89
90
 
90
91
  private storePath: string | null = null
91
92
 
@@ -248,8 +249,9 @@ export class WhatsAppClient {
248
249
  this.pendingResolve = resolve
249
250
  })
250
251
 
251
- const authCompletePromise = new Promise<void>((resolve) => {
252
+ const authCompletePromise = new Promise<void>((resolve, reject) => {
252
253
  this.authCompleteResolve = resolve
254
+ this.authCompleteReject = reject
253
255
  })
254
256
 
255
257
  const cleaned = phoneNumber.replace(/[^0-9]/g, '')
@@ -258,16 +260,24 @@ export class WhatsAppClient {
258
260
 
259
261
  return new Promise((outerResolve, outerReject) => {
260
262
  let codeReturned = false
261
- let postPairingRetries = 0
262
- const MAX_POST_PAIRING_RETRIES = 5
263
263
 
264
264
  const overallTimeout = setTimeout(() => {
265
- outerReject(new WhatsAppError('Pairing timed out', 'pairing_timeout'))
265
+ const err = new WhatsAppError('Pairing timed out', 'pairing_timeout')
266
+ if (codeReturned) {
267
+ this.authCompleteReject?.(err)
268
+ } else {
269
+ outerReject(err)
270
+ }
266
271
  }, 120_000)
267
272
 
268
273
  const onError = (err: unknown): void => {
269
274
  clearTimeout(overallTimeout)
270
- outerReject(err instanceof Error ? err : new WhatsAppError(String(err), 'pairing_error'))
275
+ const error = err instanceof Error ? err : new WhatsAppError(String(err), 'pairing_error')
276
+ if (codeReturned) {
277
+ this.authCompleteReject?.(error)
278
+ } else {
279
+ outerReject(error)
280
+ }
271
281
  }
272
282
 
273
283
  const attempt = async (): Promise<void> => {
@@ -294,20 +304,21 @@ export class WhatsAppClient {
294
304
 
295
305
  const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode
296
306
 
297
- // 401 is normal for fresh credentials — always reconnect during pairing
298
307
  if (statusCode === DisconnectReason.forbidden) {
299
308
  clearTimeout(overallTimeout)
300
- outerReject(new WhatsAppError('Account banned or restricted.', 'forbidden'))
309
+ const err = new WhatsAppError('Account banned or restricted.', 'forbidden')
310
+ if (codeReturned) {
311
+ this.authCompleteReject?.(err)
312
+ } else {
313
+ outerReject(err)
314
+ }
301
315
  return
302
316
  }
303
317
 
304
318
  if (codeReturned) {
305
- postPairingRetries++
306
- if (postPairingRetries > MAX_POST_PAIRING_RETRIES) {
307
- clearTimeout(overallTimeout)
308
- outerReject(new WhatsAppError('Post-pairing reconnection failed.', 'post_pairing_failed'))
309
- return
310
- }
319
+ // Post-pairing: rely on overallTimeout (120s) instead of retry cap.
320
+ // Baileys cycles the connection during pairing — keep reconnecting
321
+ // until the user enters the code and the connection opens.
311
322
  setTimeout(() => attempt().catch(onError), 2000)
312
323
  return
313
324
  }