mozi-bot 1.0.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 (259) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +467 -0
  3. package/dist/agents/agent.d.ts +118 -0
  4. package/dist/agents/agent.d.ts.map +1 -0
  5. package/dist/agents/agent.js +686 -0
  6. package/dist/agents/agent.js.map +1 -0
  7. package/dist/agents/compaction.d.ts +78 -0
  8. package/dist/agents/compaction.d.ts.map +1 -0
  9. package/dist/agents/compaction.js +350 -0
  10. package/dist/agents/compaction.js.map +1 -0
  11. package/dist/agents/failover-error.d.ts +42 -0
  12. package/dist/agents/failover-error.d.ts.map +1 -0
  13. package/dist/agents/failover-error.js +171 -0
  14. package/dist/agents/failover-error.js.map +1 -0
  15. package/dist/agents/index.d.ts +10 -0
  16. package/dist/agents/index.d.ts.map +1 -0
  17. package/dist/agents/index.js +10 -0
  18. package/dist/agents/index.js.map +1 -0
  19. package/dist/agents/model-fallback.d.ts +54 -0
  20. package/dist/agents/model-fallback.d.ts.map +1 -0
  21. package/dist/agents/model-fallback.js +227 -0
  22. package/dist/agents/model-fallback.js.map +1 -0
  23. package/dist/agents/session-store.d.ts +53 -0
  24. package/dist/agents/session-store.d.ts.map +1 -0
  25. package/dist/agents/session-store.js +217 -0
  26. package/dist/agents/session-store.js.map +1 -0
  27. package/dist/agents/system-prompt.d.ts +29 -0
  28. package/dist/agents/system-prompt.d.ts.map +1 -0
  29. package/dist/agents/system-prompt.js +299 -0
  30. package/dist/agents/system-prompt.js.map +1 -0
  31. package/dist/channels/common/base.d.ts +40 -0
  32. package/dist/channels/common/base.d.ts.map +1 -0
  33. package/dist/channels/common/base.js +23 -0
  34. package/dist/channels/common/base.js.map +1 -0
  35. package/dist/channels/common/index.d.ts +21 -0
  36. package/dist/channels/common/index.d.ts.map +1 -0
  37. package/dist/channels/common/index.js +66 -0
  38. package/dist/channels/common/index.js.map +1 -0
  39. package/dist/channels/dingtalk/api.d.ts +30 -0
  40. package/dist/channels/dingtalk/api.d.ts.map +1 -0
  41. package/dist/channels/dingtalk/api.js +149 -0
  42. package/dist/channels/dingtalk/api.js.map +1 -0
  43. package/dist/channels/dingtalk/events.d.ts +80 -0
  44. package/dist/channels/dingtalk/events.d.ts.map +1 -0
  45. package/dist/channels/dingtalk/events.js +92 -0
  46. package/dist/channels/dingtalk/events.js.map +1 -0
  47. package/dist/channels/dingtalk/index.d.ts +51 -0
  48. package/dist/channels/dingtalk/index.d.ts.map +1 -0
  49. package/dist/channels/dingtalk/index.js +231 -0
  50. package/dist/channels/dingtalk/index.js.map +1 -0
  51. package/dist/channels/dingtalk/stream.d.ts +31 -0
  52. package/dist/channels/dingtalk/stream.d.ts.map +1 -0
  53. package/dist/channels/dingtalk/stream.js +116 -0
  54. package/dist/channels/dingtalk/stream.js.map +1 -0
  55. package/dist/channels/feishu/api.d.ts +33 -0
  56. package/dist/channels/feishu/api.d.ts.map +1 -0
  57. package/dist/channels/feishu/api.js +120 -0
  58. package/dist/channels/feishu/api.js.map +1 -0
  59. package/dist/channels/feishu/events.d.ts +87 -0
  60. package/dist/channels/feishu/events.d.ts.map +1 -0
  61. package/dist/channels/feishu/events.js +163 -0
  62. package/dist/channels/feishu/events.js.map +1 -0
  63. package/dist/channels/feishu/index.d.ts +46 -0
  64. package/dist/channels/feishu/index.d.ts.map +1 -0
  65. package/dist/channels/feishu/index.js +207 -0
  66. package/dist/channels/feishu/index.js.map +1 -0
  67. package/dist/channels/feishu/websocket.d.ts +32 -0
  68. package/dist/channels/feishu/websocket.d.ts.map +1 -0
  69. package/dist/channels/feishu/websocket.js +121 -0
  70. package/dist/channels/feishu/websocket.js.map +1 -0
  71. package/dist/channels/index.d.ts +9 -0
  72. package/dist/channels/index.d.ts.map +1 -0
  73. package/dist/channels/index.js +9 -0
  74. package/dist/channels/index.js.map +1 -0
  75. package/dist/cli/index.d.ts +6 -0
  76. package/dist/cli/index.d.ts.map +1 -0
  77. package/dist/cli/index.js +468 -0
  78. package/dist/cli/index.js.map +1 -0
  79. package/dist/commands/index.d.ts +54 -0
  80. package/dist/commands/index.d.ts.map +1 -0
  81. package/dist/commands/index.js +171 -0
  82. package/dist/commands/index.js.map +1 -0
  83. package/dist/config/index.d.ts +201 -0
  84. package/dist/config/index.d.ts.map +1 -0
  85. package/dist/config/index.js +261 -0
  86. package/dist/config/index.js.map +1 -0
  87. package/dist/gateway/index.d.ts +5 -0
  88. package/dist/gateway/index.d.ts.map +1 -0
  89. package/dist/gateway/index.js +5 -0
  90. package/dist/gateway/index.js.map +1 -0
  91. package/dist/gateway/server.d.ts +42 -0
  92. package/dist/gateway/server.d.ts.map +1 -0
  93. package/dist/gateway/server.js +235 -0
  94. package/dist/gateway/server.js.map +1 -0
  95. package/dist/hooks/index.d.ts +168 -0
  96. package/dist/hooks/index.d.ts.map +1 -0
  97. package/dist/hooks/index.js +148 -0
  98. package/dist/hooks/index.js.map +1 -0
  99. package/dist/index.d.ts +18 -0
  100. package/dist/index.d.ts.map +1 -0
  101. package/dist/index.js +29 -0
  102. package/dist/index.js.map +1 -0
  103. package/dist/memory/index.d.ts +94 -0
  104. package/dist/memory/index.d.ts.map +1 -0
  105. package/dist/memory/index.js +282 -0
  106. package/dist/memory/index.js.map +1 -0
  107. package/dist/plugins/index.d.ts +57 -0
  108. package/dist/plugins/index.d.ts.map +1 -0
  109. package/dist/plugins/index.js +103 -0
  110. package/dist/plugins/index.js.map +1 -0
  111. package/dist/providers/anthropic-compatible.d.ts +48 -0
  112. package/dist/providers/anthropic-compatible.d.ts.map +1 -0
  113. package/dist/providers/anthropic-compatible.js +380 -0
  114. package/dist/providers/anthropic-compatible.js.map +1 -0
  115. package/dist/providers/base.d.ts +26 -0
  116. package/dist/providers/base.d.ts.map +1 -0
  117. package/dist/providers/base.js +58 -0
  118. package/dist/providers/base.js.map +1 -0
  119. package/dist/providers/custom-openai.d.ts +66 -0
  120. package/dist/providers/custom-openai.d.ts.map +1 -0
  121. package/dist/providers/custom-openai.js +255 -0
  122. package/dist/providers/custom-openai.js.map +1 -0
  123. package/dist/providers/dashscope.d.ts +15 -0
  124. package/dist/providers/dashscope.d.ts.map +1 -0
  125. package/dist/providers/dashscope.js +237 -0
  126. package/dist/providers/dashscope.js.map +1 -0
  127. package/dist/providers/deepseek.d.ts +10 -0
  128. package/dist/providers/deepseek.d.ts.map +1 -0
  129. package/dist/providers/deepseek.js +57 -0
  130. package/dist/providers/deepseek.js.map +1 -0
  131. package/dist/providers/index.d.ts +33 -0
  132. package/dist/providers/index.d.ts.map +1 -0
  133. package/dist/providers/index.js +142 -0
  134. package/dist/providers/index.js.map +1 -0
  135. package/dist/providers/kimi.d.ts +10 -0
  136. package/dist/providers/kimi.d.ts.map +1 -0
  137. package/dist/providers/kimi.js +83 -0
  138. package/dist/providers/kimi.js.map +1 -0
  139. package/dist/providers/minimax.d.ts +20 -0
  140. package/dist/providers/minimax.d.ts.map +1 -0
  141. package/dist/providers/minimax.js +252 -0
  142. package/dist/providers/minimax.js.map +1 -0
  143. package/dist/providers/modelscope.d.ts +15 -0
  144. package/dist/providers/modelscope.d.ts.map +1 -0
  145. package/dist/providers/modelscope.js +237 -0
  146. package/dist/providers/modelscope.js.map +1 -0
  147. package/dist/providers/openai-compatible.d.ts +57 -0
  148. package/dist/providers/openai-compatible.d.ts.map +1 -0
  149. package/dist/providers/openai-compatible.js +193 -0
  150. package/dist/providers/openai-compatible.js.map +1 -0
  151. package/dist/providers/stepfun.d.ts +10 -0
  152. package/dist/providers/stepfun.d.ts.map +1 -0
  153. package/dist/providers/stepfun.js +125 -0
  154. package/dist/providers/stepfun.js.map +1 -0
  155. package/dist/providers/zhipu.d.ts +15 -0
  156. package/dist/providers/zhipu.d.ts.map +1 -0
  157. package/dist/providers/zhipu.js +247 -0
  158. package/dist/providers/zhipu.js.map +1 -0
  159. package/dist/sessions/index.d.ts +6 -0
  160. package/dist/sessions/index.d.ts.map +1 -0
  161. package/dist/sessions/index.js +6 -0
  162. package/dist/sessions/index.js.map +1 -0
  163. package/dist/sessions/store.d.ts +45 -0
  164. package/dist/sessions/store.d.ts.map +1 -0
  165. package/dist/sessions/store.js +268 -0
  166. package/dist/sessions/store.js.map +1 -0
  167. package/dist/sessions/types.d.ts +110 -0
  168. package/dist/sessions/types.d.ts.map +1 -0
  169. package/dist/sessions/types.js +6 -0
  170. package/dist/sessions/types.js.map +1 -0
  171. package/dist/tools/builtin/apply-patch.d.ts +8 -0
  172. package/dist/tools/builtin/apply-patch.d.ts.map +1 -0
  173. package/dist/tools/builtin/apply-patch.js +272 -0
  174. package/dist/tools/builtin/apply-patch.js.map +1 -0
  175. package/dist/tools/builtin/bash.d.ts +25 -0
  176. package/dist/tools/builtin/bash.d.ts.map +1 -0
  177. package/dist/tools/builtin/bash.js +212 -0
  178. package/dist/tools/builtin/bash.js.map +1 -0
  179. package/dist/tools/builtin/browser.d.ts +12 -0
  180. package/dist/tools/builtin/browser.d.ts.map +1 -0
  181. package/dist/tools/builtin/browser.js +693 -0
  182. package/dist/tools/builtin/browser.js.map +1 -0
  183. package/dist/tools/builtin/filesystem.d.ts +29 -0
  184. package/dist/tools/builtin/filesystem.d.ts.map +1 -0
  185. package/dist/tools/builtin/filesystem.js +484 -0
  186. package/dist/tools/builtin/filesystem.js.map +1 -0
  187. package/dist/tools/builtin/image.d.ts +13 -0
  188. package/dist/tools/builtin/image.d.ts.map +1 -0
  189. package/dist/tools/builtin/image.js +126 -0
  190. package/dist/tools/builtin/image.js.map +1 -0
  191. package/dist/tools/builtin/index.d.ts +30 -0
  192. package/dist/tools/builtin/index.d.ts.map +1 -0
  193. package/dist/tools/builtin/index.js +55 -0
  194. package/dist/tools/builtin/index.js.map +1 -0
  195. package/dist/tools/builtin/process-registry.d.ts +71 -0
  196. package/dist/tools/builtin/process-registry.d.ts.map +1 -0
  197. package/dist/tools/builtin/process-registry.js +172 -0
  198. package/dist/tools/builtin/process-registry.js.map +1 -0
  199. package/dist/tools/builtin/process-tool.d.ts +8 -0
  200. package/dist/tools/builtin/process-tool.d.ts.map +1 -0
  201. package/dist/tools/builtin/process-tool.js +279 -0
  202. package/dist/tools/builtin/process-tool.js.map +1 -0
  203. package/dist/tools/builtin/subagent.d.ts +33 -0
  204. package/dist/tools/builtin/subagent.d.ts.map +1 -0
  205. package/dist/tools/builtin/subagent.js +185 -0
  206. package/dist/tools/builtin/subagent.js.map +1 -0
  207. package/dist/tools/builtin/system.d.ts +11 -0
  208. package/dist/tools/builtin/system.d.ts.map +1 -0
  209. package/dist/tools/builtin/system.js +144 -0
  210. package/dist/tools/builtin/system.js.map +1 -0
  211. package/dist/tools/builtin/web.d.ts +9 -0
  212. package/dist/tools/builtin/web.d.ts.map +1 -0
  213. package/dist/tools/builtin/web.js +87 -0
  214. package/dist/tools/builtin/web.js.map +1 -0
  215. package/dist/tools/common.d.ts +45 -0
  216. package/dist/tools/common.d.ts.map +1 -0
  217. package/dist/tools/common.js +129 -0
  218. package/dist/tools/common.js.map +1 -0
  219. package/dist/tools/index.d.ts +8 -0
  220. package/dist/tools/index.d.ts.map +1 -0
  221. package/dist/tools/index.js +8 -0
  222. package/dist/tools/index.js.map +1 -0
  223. package/dist/tools/registry.d.ts +33 -0
  224. package/dist/tools/registry.d.ts.map +1 -0
  225. package/dist/tools/registry.js +174 -0
  226. package/dist/tools/registry.js.map +1 -0
  227. package/dist/tools/types.d.ts +58 -0
  228. package/dist/tools/types.d.ts.map +1 -0
  229. package/dist/tools/types.js +11 -0
  230. package/dist/tools/types.js.map +1 -0
  231. package/dist/types/index.d.ts +280 -0
  232. package/dist/types/index.d.ts.map +1 -0
  233. package/dist/types/index.js +34 -0
  234. package/dist/types/index.js.map +1 -0
  235. package/dist/utils/index.d.ts +35 -0
  236. package/dist/utils/index.d.ts.map +1 -0
  237. package/dist/utils/index.js +114 -0
  238. package/dist/utils/index.js.map +1 -0
  239. package/dist/utils/logger.d.ts +24 -0
  240. package/dist/utils/logger.d.ts.map +1 -0
  241. package/dist/utils/logger.js +94 -0
  242. package/dist/utils/logger.js.map +1 -0
  243. package/dist/web/index.d.ts +7 -0
  244. package/dist/web/index.d.ts.map +1 -0
  245. package/dist/web/index.js +7 -0
  246. package/dist/web/index.js.map +1 -0
  247. package/dist/web/static.d.ts +12 -0
  248. package/dist/web/static.d.ts.map +1 -0
  249. package/dist/web/static.js +1260 -0
  250. package/dist/web/static.js.map +1 -0
  251. package/dist/web/types.d.ts +95 -0
  252. package/dist/web/types.d.ts.map +1 -0
  253. package/dist/web/types.js +5 -0
  254. package/dist/web/types.js.map +1 -0
  255. package/dist/web/websocket.d.ts +58 -0
  256. package/dist/web/websocket.d.ts.map +1 -0
  257. package/dist/web/websocket.js +371 -0
  258. package/dist/web/websocket.js.map +1 -0
  259. package/package.json +89 -0
@@ -0,0 +1,66 @@
1
+ /**
2
+ * 通道注册表
3
+ */
4
+ import { getChildLogger } from "../../utils/logger.js";
5
+ export * from "./base.js";
6
+ const logger = getChildLogger("channels");
7
+ /** 通道注册表 */
8
+ const channels = new Map();
9
+ /** 全局消息处理器 */
10
+ let globalMessageHandler;
11
+ /** 注册通道 */
12
+ export function registerChannel(channel) {
13
+ channels.set(channel.id, channel);
14
+ // 如果有全局消息处理器,设置到通道
15
+ if (globalMessageHandler && "setMessageHandler" in channel) {
16
+ channel.setMessageHandler(globalMessageHandler);
17
+ }
18
+ logger.info({ channel: channel.id }, "Channel registered");
19
+ }
20
+ /** 获取通道 */
21
+ export function getChannel(id) {
22
+ return channels.get(id);
23
+ }
24
+ /** 获取所有通道 */
25
+ export function getAllChannels() {
26
+ return Array.from(channels.values());
27
+ }
28
+ /** 检查通道是否可用 */
29
+ export function hasChannel(id) {
30
+ return channels.has(id);
31
+ }
32
+ /** 设置全局消息处理器 */
33
+ export function setGlobalMessageHandler(handler) {
34
+ globalMessageHandler = handler;
35
+ // 更新所有已注册通道的处理器
36
+ for (const channel of channels.values()) {
37
+ if ("setMessageHandler" in channel) {
38
+ channel.setMessageHandler(handler);
39
+ }
40
+ }
41
+ }
42
+ /** 初始化所有通道 */
43
+ export async function initializeAllChannels() {
44
+ for (const channel of channels.values()) {
45
+ try {
46
+ await channel.initialize();
47
+ logger.info({ channel: channel.id }, "Channel initialized");
48
+ }
49
+ catch (error) {
50
+ logger.error({ channel: channel.id, error }, "Failed to initialize channel");
51
+ }
52
+ }
53
+ }
54
+ /** 关闭所有通道 */
55
+ export async function shutdownAllChannels() {
56
+ for (const channel of channels.values()) {
57
+ try {
58
+ await channel.shutdown();
59
+ logger.info({ channel: channel.id }, "Channel shut down");
60
+ }
61
+ catch (error) {
62
+ logger.error({ channel: channel.id, error }, "Failed to shut down channel");
63
+ }
64
+ }
65
+ }
66
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/channels/common/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,cAAc,WAAW,CAAC;AAE1B,MAAM,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;AAE1C,YAAY;AACZ,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAC;AAEtD,cAAc;AACd,IAAI,oBAAgD,CAAC;AAErD,WAAW;AACX,MAAM,UAAU,eAAe,CAAC,OAAuB;IACrD,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAElC,mBAAmB;IACnB,IAAI,oBAAoB,IAAI,mBAAmB,IAAI,OAAO,EAAE,CAAC;QAC1D,OAA8D,CAAC,iBAAiB,CAC/E,oBAAoB,CACrB,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,oBAAoB,CAAC,CAAC;AAC7D,CAAC;AAED,WAAW;AACX,MAAM,UAAU,UAAU,CAAC,EAAa;IACtC,OAAO,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAC1B,CAAC;AAED,aAAa;AACb,MAAM,UAAU,cAAc;IAC5B,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;AACvC,CAAC;AAED,eAAe;AACf,MAAM,UAAU,UAAU,CAAC,EAAa;IACtC,OAAO,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAC1B,CAAC;AAED,gBAAgB;AAChB,MAAM,UAAU,uBAAuB,CAAC,OAAuB;IAC7D,oBAAoB,GAAG,OAAO,CAAC;IAE/B,gBAAgB;IAChB,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACxC,IAAI,mBAAmB,IAAI,OAAO,EAAE,CAAC;YAClC,OAA8D,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC7F,CAAC;IACH,CAAC;AACH,CAAC;AAED,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,qBAAqB,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,8BAA8B,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;AACH,CAAC;AAED,aAAa;AACb,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,mBAAmB,CAAC,CAAC;QAC5D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,6BAA6B,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * 钉钉 API 客户端
3
+ */
4
+ import type { DingtalkConfig } from "../../types/index.js";
5
+ /** 钉钉 API 客户端 */
6
+ export declare class DingtalkApiClient {
7
+ private config;
8
+ constructor(config: DingtalkConfig);
9
+ /** 获取 Access Token */
10
+ getAccessToken(): Promise<string>;
11
+ /** 发送请求 (新版 API) */
12
+ private request;
13
+ /** 发送工作通知消息 */
14
+ sendWorkNotification(userId: string, content: unknown): Promise<void>;
15
+ /** 机器人发送单聊消息 */
16
+ sendRobotMessage(userId: string, content: string): Promise<void>;
17
+ /** 机器人发送群消息 */
18
+ sendGroupMessage(openConversationId: string, content: string): Promise<void>;
19
+ /** 回复 Webhook 消息 */
20
+ replyWebhookMessage(sessionWebhook: string, content: string): Promise<void>;
21
+ /** 发送 Markdown 消息 */
22
+ sendMarkdownMessage(sessionWebhook: string, title: string, text: string): Promise<void>;
23
+ /** 获取用户信息 */
24
+ getUserInfo(userId: string): Promise<unknown>;
25
+ /** 获取群信息 */
26
+ getChatInfo(openConversationId: string): Promise<unknown>;
27
+ }
28
+ /** 验证钉钉回调签名 */
29
+ export declare function verifyDingtalkSignature(timestamp: string, sign: string, appSecret: string): boolean;
30
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/channels/dingtalk/api.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA8B3D,iBAAiB;AACjB,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAiB;gBAEnB,MAAM,EAAE,cAAc;IAIlC,sBAAsB;IAChB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAiCvC,oBAAoB;YACN,OAAO;IAqDrB,eAAe;IACT,oBAAoB,CACxB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC;IAehB,gBAAgB;IACV,gBAAgB,CACpB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC;IAehB,eAAe;IACT,gBAAgB,CACpB,kBAAkB,EAAE,MAAM,EAC1B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC;IAehB,oBAAoB;IACd,mBAAmB,CACvB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC;IAiBhB,qBAAqB;IACf,mBAAmB,CACvB,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC;IAehB,aAAa;IACP,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASnD,YAAY;IACN,WAAW,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAMhE;AAED,eAAe;AACf,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,OAAO,CAIT"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * 钉钉 API 客户端
3
+ */
4
+ import { getChildLogger } from "../../utils/logger.js";
5
+ import { retry, computeHmacSha256 } from "../../utils/index.js";
6
+ import NodeCache from "node-cache";
7
+ const logger = getChildLogger("dingtalk-api");
8
+ const DINGTALK_API_BASE = "https://api.dingtalk.com";
9
+ const DINGTALK_OLD_API_BASE = "https://oapi.dingtalk.com";
10
+ /** Token 缓存 */
11
+ const tokenCache = new NodeCache({ stdTTL: 7000 }); // token 有效期 2 小时
12
+ /** 钉钉 API 客户端 */
13
+ export class DingtalkApiClient {
14
+ config;
15
+ constructor(config) {
16
+ this.config = config;
17
+ }
18
+ /** 获取 Access Token */
19
+ async getAccessToken() {
20
+ const cacheKey = `dingtalk_token_${this.config.appKey}`;
21
+ const cached = tokenCache.get(cacheKey);
22
+ if (cached) {
23
+ return cached;
24
+ }
25
+ logger.debug("Fetching new access token");
26
+ const response = await fetch(`${DINGTALK_OLD_API_BASE}/gettoken?appkey=${this.config.appKey}&appsecret=${this.config.appSecret}`);
27
+ if (!response.ok) {
28
+ throw new Error(`Failed to get access token: ${response.status}`);
29
+ }
30
+ const data = (await response.json());
31
+ if (data.errcode !== 0) {
32
+ throw new Error(`DingTalk API Error [${data.errcode}]: ${data.errmsg}`);
33
+ }
34
+ if (!data.access_token) {
35
+ throw new Error("No access token in response");
36
+ }
37
+ // 缓存 token
38
+ tokenCache.set(cacheKey, data.access_token);
39
+ return data.access_token;
40
+ }
41
+ /** 发送请求 (新版 API) */
42
+ async request(method, path, body, useOldApi = false) {
43
+ const token = await this.getAccessToken();
44
+ const baseUrl = useOldApi ? DINGTALK_OLD_API_BASE : DINGTALK_API_BASE;
45
+ const response = await retry(async () => {
46
+ const url = useOldApi
47
+ ? `${baseUrl}${path}?access_token=${token}`
48
+ : `${baseUrl}${path}`;
49
+ const headers = {
50
+ "Content-Type": "application/json",
51
+ };
52
+ if (!useOldApi) {
53
+ headers["x-acs-dingtalk-access-token"] = token;
54
+ }
55
+ const res = await fetch(url, {
56
+ method,
57
+ headers,
58
+ body: body ? JSON.stringify(body) : undefined,
59
+ });
60
+ if (!res.ok) {
61
+ throw new Error(`HTTP ${res.status}: ${await res.text()}`);
62
+ }
63
+ return res;
64
+ }, { maxRetries: 3, delayMs: 1000 });
65
+ const data = (await response.json());
66
+ // 旧版 API 错误处理
67
+ if (useOldApi && data.errcode !== undefined && data.errcode !== 0) {
68
+ throw new Error(`DingTalk API Error [${data.errcode}]: ${data.errmsg}`);
69
+ }
70
+ // 新版 API 错误处理
71
+ if (!useOldApi && data.success === false) {
72
+ throw new Error(`DingTalk API Error: ${data.errmsg || "Unknown error"}`);
73
+ }
74
+ return (data.result ?? data);
75
+ }
76
+ /** 发送工作通知消息 */
77
+ async sendWorkNotification(userId, content) {
78
+ logger.debug({ userId }, "Sending work notification");
79
+ await this.request("POST", "/topapi/message/corpconversation/asyncsend_v2", {
80
+ agent_id: this.config.robotCode,
81
+ userid_list: userId,
82
+ msg: content,
83
+ }, true);
84
+ }
85
+ /** 机器人发送单聊消息 */
86
+ async sendRobotMessage(userId, content) {
87
+ logger.debug({ userId }, "Sending robot message");
88
+ await this.request("POST", `/v1.0/robot/oToMessages/batchSend`, {
89
+ robotCode: this.config.robotCode,
90
+ userIds: [userId],
91
+ msgKey: "sampleText",
92
+ msgParam: JSON.stringify({ content }),
93
+ });
94
+ }
95
+ /** 机器人发送群消息 */
96
+ async sendGroupMessage(openConversationId, content) {
97
+ logger.debug({ openConversationId }, "Sending group message");
98
+ await this.request("POST", `/v1.0/robot/groupMessages/send`, {
99
+ robotCode: this.config.robotCode,
100
+ openConversationId,
101
+ msgKey: "sampleText",
102
+ msgParam: JSON.stringify({ content }),
103
+ });
104
+ }
105
+ /** 回复 Webhook 消息 */
106
+ async replyWebhookMessage(sessionWebhook, content) {
107
+ logger.debug({ sessionWebhook }, "Replying via webhook");
108
+ const response = await fetch(sessionWebhook, {
109
+ method: "POST",
110
+ headers: { "Content-Type": "application/json" },
111
+ body: JSON.stringify({
112
+ msgtype: "text",
113
+ text: { content },
114
+ }),
115
+ });
116
+ if (!response.ok) {
117
+ throw new Error(`Failed to reply: ${response.status}`);
118
+ }
119
+ }
120
+ /** 发送 Markdown 消息 */
121
+ async sendMarkdownMessage(sessionWebhook, title, text) {
122
+ const response = await fetch(sessionWebhook, {
123
+ method: "POST",
124
+ headers: { "Content-Type": "application/json" },
125
+ body: JSON.stringify({
126
+ msgtype: "markdown",
127
+ markdown: { title, text },
128
+ }),
129
+ });
130
+ if (!response.ok) {
131
+ throw new Error(`Failed to send markdown: ${response.status}`);
132
+ }
133
+ }
134
+ /** 获取用户信息 */
135
+ async getUserInfo(userId) {
136
+ return this.request("POST", "/topapi/v2/user/get", { userid: userId }, true);
137
+ }
138
+ /** 获取群信息 */
139
+ async getChatInfo(openConversationId) {
140
+ return this.request("GET", `/v1.0/im/conversations/${openConversationId}`);
141
+ }
142
+ }
143
+ /** 验证钉钉回调签名 */
144
+ export function verifyDingtalkSignature(timestamp, sign, appSecret) {
145
+ const stringToSign = timestamp + "\n" + appSecret;
146
+ const expectedSign = computeHmacSha256(appSecret, stringToSign);
147
+ return sign === expectedSign;
148
+ }
149
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/channels/dingtalk/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * 钉钉事件处理
3
+ */
4
+ import type { DingtalkConfig, InboundMessageContext } from "../../types/index.js";
5
+ /** 钉钉消息类型 */
6
+ export type DingtalkMsgType = "text" | "richText" | "picture" | "video" | "file" | "audio";
7
+ /** 钉钉回调消息 */
8
+ export interface DingtalkCallbackMessage {
9
+ /** 加密的消息ID */
10
+ msgId: string;
11
+ /** 消息类型 */
12
+ msgtype: DingtalkMsgType;
13
+ /** 文本内容 */
14
+ text?: {
15
+ content: string;
16
+ };
17
+ /** 富文本内容 */
18
+ richText?: Array<{
19
+ text?: string;
20
+ pictureDownloadCode?: string;
21
+ }>;
22
+ /** 发送者ID */
23
+ senderStaffId?: string;
24
+ /** 发送者昵称 */
25
+ senderNick?: string;
26
+ /** 发送者企业ID */
27
+ senderCorpId?: string;
28
+ /** 会话ID */
29
+ sessionWebhook?: string;
30
+ /** 会话过期时间 */
31
+ sessionWebhookExpiredTime?: number;
32
+ /** 会话类型 1:单聊 2:群聊 */
33
+ conversationType?: "1" | "2";
34
+ /** 群聊 ID */
35
+ openConversationId?: string;
36
+ /** @机器人信息 */
37
+ atUsers?: Array<{
38
+ dingtalkId: string;
39
+ staffId?: string;
40
+ }>;
41
+ /** 是否被 @全员 */
42
+ isAtAll?: boolean;
43
+ /** 机器人编码 */
44
+ robotCode?: string;
45
+ /** 创建时间 */
46
+ createAt?: number;
47
+ /** 是否在 @列表中 */
48
+ isInAtList?: boolean;
49
+ }
50
+ /** 钉钉 Stream 消息 */
51
+ export interface DingtalkStreamMessage {
52
+ specVersion: string;
53
+ type: string;
54
+ headers: {
55
+ appId: string;
56
+ connectionId: string;
57
+ contentType: string;
58
+ messageId: string;
59
+ time: string;
60
+ topic: string;
61
+ };
62
+ data: string;
63
+ }
64
+ /** 钉钉事件处理器 */
65
+ export declare class DingtalkEventHandler {
66
+ private config;
67
+ private processedMessages;
68
+ constructor(config: DingtalkConfig);
69
+ /** 验证回调签名 */
70
+ verifySignature(timestamp: string, sign: string): boolean;
71
+ /** 检查消息是否已处理 (去重) */
72
+ isMessageProcessed(msgId: string): boolean;
73
+ /** 解析消息内容 */
74
+ parseMessageContent(message: DingtalkCallbackMessage): string;
75
+ /** 将钉钉消息转换为通用消息上下文 */
76
+ convertToMessageContext(message: DingtalkCallbackMessage): InboundMessageContext | null;
77
+ /** 解析 Stream 消息 */
78
+ parseStreamMessage(streamMessage: DingtalkStreamMessage): DingtalkCallbackMessage;
79
+ }
80
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/channels/dingtalk/events.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAY,MAAM,sBAAsB,CAAC;AAM5F,aAAa;AACb,MAAM,MAAM,eAAe,GACvB,MAAM,GACN,UAAU,GACV,SAAS,GACT,OAAO,GACP,MAAM,GACN,OAAO,CAAC;AAEZ,aAAa;AACb,MAAM,WAAW,uBAAuB;IACtC,cAAc;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW;IACX,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW;IACX,IAAI,CAAC,EAAE;QACL,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,YAAY;IACZ,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC9B,CAAC,CAAC;IACH,YAAY;IACZ,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW;IACX,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa;IACb,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,qBAAqB;IACrB,gBAAgB,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC;IAC7B,YAAY;IACZ,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa;IACb,OAAO,CAAC,EAAE,KAAK,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,cAAc;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,mBAAmB;AACnB,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;CACd;AAED,cAAc;AACd,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,iBAAiB,CAAqB;gBAElC,MAAM,EAAE,cAAc;IAIlC,aAAa;IACb,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IAYzD,qBAAqB;IACrB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAc1C,aAAa;IACb,mBAAmB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM;IA6B7D,sBAAsB;IACtB,uBAAuB,CAAC,OAAO,EAAE,uBAAuB,GAAG,qBAAqB,GAAG,IAAI;IAkCvF,mBAAmB;IACnB,kBAAkB,CAAC,aAAa,EAAE,qBAAqB,GAAG,uBAAuB;CAGlF"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * 钉钉事件处理
3
+ */
4
+ import { getChildLogger } from "../../utils/logger.js";
5
+ import { computeHmacSha256 } from "../../utils/index.js";
6
+ const logger = getChildLogger("dingtalk-events");
7
+ /** 钉钉事件处理器 */
8
+ export class DingtalkEventHandler {
9
+ config;
10
+ processedMessages = new Set();
11
+ constructor(config) {
12
+ this.config = config;
13
+ }
14
+ /** 验证回调签名 */
15
+ verifySignature(timestamp, sign) {
16
+ if (!this.config.appSecret) {
17
+ logger.warn("No app secret configured, skipping signature verification");
18
+ return true;
19
+ }
20
+ const stringToSign = timestamp + "\n" + this.config.appSecret;
21
+ const expectedSign = computeHmacSha256(this.config.appSecret, stringToSign);
22
+ return sign === expectedSign;
23
+ }
24
+ /** 检查消息是否已处理 (去重) */
25
+ isMessageProcessed(msgId) {
26
+ if (this.processedMessages.has(msgId)) {
27
+ return true;
28
+ }
29
+ this.processedMessages.add(msgId);
30
+ if (this.processedMessages.size > 10000) {
31
+ const messages = Array.from(this.processedMessages);
32
+ this.processedMessages = new Set(messages.slice(5000));
33
+ }
34
+ return false;
35
+ }
36
+ /** 解析消息内容 */
37
+ parseMessageContent(message) {
38
+ switch (message.msgtype) {
39
+ case "text":
40
+ return message.text?.content || "";
41
+ case "richText":
42
+ return (message.richText
43
+ ?.map((item) => item.text || "[图片]")
44
+ .join("") || "");
45
+ case "picture":
46
+ return "[图片]";
47
+ case "video":
48
+ return "[视频]";
49
+ case "file":
50
+ return "[文件]";
51
+ case "audio":
52
+ return "[语音]";
53
+ default:
54
+ return `[${message.msgtype}]`;
55
+ }
56
+ }
57
+ /** 将钉钉消息转换为通用消息上下文 */
58
+ convertToMessageContext(message) {
59
+ // 检查消息去重
60
+ if (this.isMessageProcessed(message.msgId)) {
61
+ logger.debug({ msgId: message.msgId }, "Message already processed");
62
+ return null;
63
+ }
64
+ const content = this.parseMessageContent(message);
65
+ // 移除 @机器人 的内容
66
+ let cleanContent = content;
67
+ if (message.atUsers) {
68
+ // 钉钉的 @ 格式通常是 @nickname
69
+ cleanContent = content.replace(/@\S+\s?/g, "").trim();
70
+ }
71
+ const chatType = message.conversationType === "2" ? "group" : "direct";
72
+ return {
73
+ channelId: "dingtalk",
74
+ messageId: message.msgId,
75
+ chatId: message.openConversationId || message.senderStaffId || "",
76
+ chatType,
77
+ senderId: message.senderStaffId || "",
78
+ senderName: message.senderNick,
79
+ content: cleanContent,
80
+ mediaUrls: undefined,
81
+ replyToId: undefined,
82
+ mentions: message.atUsers?.map((u) => u.staffId || u.dingtalkId),
83
+ timestamp: message.createAt || Date.now(),
84
+ raw: message,
85
+ };
86
+ }
87
+ /** 解析 Stream 消息 */
88
+ parseStreamMessage(streamMessage) {
89
+ return JSON.parse(streamMessage.data);
90
+ }
91
+ }
92
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/channels/dingtalk/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * 钉钉通道适配器
3
+ *
4
+ * 支持两种连接模式:
5
+ * - stream: Stream 长连接模式 (默认,无需公网部署)
6
+ * - webhook: 传统 HTTP 回调模式 (需要公网部署)
7
+ */
8
+ import { Router, type Request, type Response } from "express";
9
+ import type { DingtalkConfig, ChannelMeta, OutboundMessage, SendResult, InboundMessageContext } from "../../types/index.js";
10
+ import { BaseChannelAdapter } from "../common/base.js";
11
+ import { DingtalkApiClient } from "./api.js";
12
+ export declare class DingtalkChannel extends BaseChannelAdapter {
13
+ readonly id: "dingtalk";
14
+ readonly meta: ChannelMeta;
15
+ private config;
16
+ private apiClient;
17
+ private eventHandler;
18
+ private streamClient;
19
+ private initialized;
20
+ private sessionCache;
21
+ constructor(config: DingtalkConfig);
22
+ /** 初始化通道 */
23
+ initialize(): Promise<void>;
24
+ /** 启动 Stream 连接 */
25
+ private startStream;
26
+ /** 关闭通道 */
27
+ shutdown(): Promise<void>;
28
+ /** 发送消息 */
29
+ sendMessage(message: OutboundMessage): Promise<SendResult>;
30
+ /** 发送文本消息 */
31
+ sendText(chatId: string, text: string, replyToId?: string): Promise<SendResult>;
32
+ /** 检查通道状态 */
33
+ isHealthy(): Promise<boolean>;
34
+ /** 创建 Express 路由处理器 */
35
+ createRouter(): Router;
36
+ /** 处理 Webhook 请求 */
37
+ handleWebhook(req: Request, res: Response): Promise<void>;
38
+ /** 使用 Session Webhook 回复 */
39
+ replyWithSession(context: InboundMessageContext & {
40
+ sessionWebhook?: string;
41
+ }, text: string): Promise<SendResult>;
42
+ /** 获取 API 客户端 */
43
+ getApiClient(): DingtalkApiClient;
44
+ /** 获取连接模式 */
45
+ getMode(): "stream" | "webhook";
46
+ /** 检查是否使用长连接 */
47
+ isUsingStream(): boolean;
48
+ }
49
+ /** 创建钉钉通道 */
50
+ export declare function createDingtalkChannel(config: DingtalkConfig): DingtalkChannel;
51
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/channels/dingtalk/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,eAAe,EACf,UAAU,EACV,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AA8B7C,qBAAa,eAAgB,SAAQ,kBAAkB;IACrD,QAAQ,CAAC,EAAE,EAAG,UAAU,CAAU;IAClC,QAAQ,CAAC,IAAI,cAAiB;IAE9B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,YAAY,CAAqC;IACzD,OAAO,CAAC,WAAW,CAAS;IAG5B,OAAO,CAAC,YAAY,CAAqC;gBAE7C,MAAM,EAAE,cAAc;IAQlC,YAAY;IACN,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BjC,mBAAmB;YACL,WAAW;IAazB,WAAW;IACL,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAY/B,WAAW;IACL,WAAW,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC;IAyBhE,aAAa;IACP,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAIrF,aAAa;IACP,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAiBnC,uBAAuB;IACvB,YAAY,IAAI,MAAM;IActB,oBAAoB;IACd,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAwD/D,4BAA4B;IACtB,gBAAgB,CACpB,OAAO,EAAE,qBAAqB,GAAG;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,EAC5D,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,CAAC;IAgBtB,iBAAiB;IACjB,YAAY,IAAI,iBAAiB;IAIjC,aAAa;IACb,OAAO,IAAI,QAAQ,GAAG,SAAS;IAI/B,gBAAgB;IAChB,aAAa,IAAI,OAAO;CAIzB;AAED,aAAa;AACb,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAE7E"}