wechaty-puppet-matrix 0.0.4

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 (352) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +14 -0
  3. package/dist/cjs/package.json +3 -0
  4. package/dist/cjs/src/cleanup.d.ts +4 -0
  5. package/dist/cjs/src/cleanup.d.ts.map +1 -0
  6. package/dist/cjs/src/cleanup.js +31 -0
  7. package/dist/cjs/src/config.d.ts +5 -0
  8. package/dist/cjs/src/config.d.ts.map +1 -0
  9. package/dist/cjs/src/config.js +10 -0
  10. package/dist/cjs/src/engine-schema.d.ts +76 -0
  11. package/dist/cjs/src/engine-schema.d.ts.map +1 -0
  12. package/dist/cjs/src/engine-schema.js +14 -0
  13. package/dist/cjs/src/matrix/cache-manager.d.ts +58 -0
  14. package/dist/cjs/src/matrix/cache-manager.d.ts.map +1 -0
  15. package/dist/cjs/src/matrix/cache-manager.js +286 -0
  16. package/dist/cjs/src/matrix/events/event-friendship.d.ts +6 -0
  17. package/dist/cjs/src/matrix/events/event-friendship.d.ts.map +1 -0
  18. package/dist/cjs/src/matrix/events/event-friendship.js +109 -0
  19. package/dist/cjs/src/matrix/events/event-message.d.ts +6 -0
  20. package/dist/cjs/src/matrix/events/event-message.d.ts.map +1 -0
  21. package/dist/cjs/src/matrix/events/event-message.js +5 -0
  22. package/dist/cjs/src/matrix/events/event-room-invite.d.ts +6 -0
  23. package/dist/cjs/src/matrix/events/event-room-invite.d.ts.map +1 -0
  24. package/dist/cjs/src/matrix/events/event-room-invite.js +55 -0
  25. package/dist/cjs/src/matrix/events/event-room-join.d.ts +6 -0
  26. package/dist/cjs/src/matrix/events/event-room-join.d.ts.map +1 -0
  27. package/dist/cjs/src/matrix/events/event-room-join.js +127 -0
  28. package/dist/cjs/src/matrix/events/event-room-leave.d.ts +8 -0
  29. package/dist/cjs/src/matrix/events/event-room-leave.d.ts.map +1 -0
  30. package/dist/cjs/src/matrix/events/event-room-leave.js +83 -0
  31. package/dist/cjs/src/matrix/events/event-room-topic.d.ts +6 -0
  32. package/dist/cjs/src/matrix/events/event-room-topic.d.ts.map +1 -0
  33. package/dist/cjs/src/matrix/events/event-room-topic.js +56 -0
  34. package/dist/cjs/src/matrix/events/event.d.ts +28 -0
  35. package/dist/cjs/src/matrix/events/event.d.ts.map +1 -0
  36. package/dist/cjs/src/matrix/events/event.js +42 -0
  37. package/dist/cjs/src/matrix/events/mod.d.ts +3 -0
  38. package/dist/cjs/src/matrix/events/mod.d.ts.map +1 -0
  39. package/dist/cjs/src/matrix/events/mod.js +21 -0
  40. package/dist/cjs/src/matrix/messages/message-appmsg.d.ts +57 -0
  41. package/dist/cjs/src/matrix/messages/message-appmsg.d.ts.map +1 -0
  42. package/dist/cjs/src/matrix/messages/message-appmsg.js +60 -0
  43. package/dist/cjs/src/matrix/messages/message-audio.d.ts +32 -0
  44. package/dist/cjs/src/matrix/messages/message-audio.d.ts.map +1 -0
  45. package/dist/cjs/src/matrix/messages/message-audio.js +17 -0
  46. package/dist/cjs/src/matrix/messages/message-emotion.d.ts +13 -0
  47. package/dist/cjs/src/matrix/messages/message-emotion.d.ts.map +1 -0
  48. package/dist/cjs/src/matrix/messages/message-emotion.js +32 -0
  49. package/dist/cjs/src/matrix/messages/message-image.d.ts +33 -0
  50. package/dist/cjs/src/matrix/messages/message-image.d.ts.map +1 -0
  51. package/dist/cjs/src/matrix/messages/message-image.js +14 -0
  52. package/dist/cjs/src/matrix/messages/message-miniprogram.d.ts +4 -0
  53. package/dist/cjs/src/matrix/messages/message-miniprogram.d.ts.map +1 -0
  54. package/dist/cjs/src/matrix/messages/message-miniprogram.js +21 -0
  55. package/dist/cjs/src/matrix/messages/message-sysmsg.d.ts +18 -0
  56. package/dist/cjs/src/matrix/messages/message-sysmsg.d.ts.map +1 -0
  57. package/dist/cjs/src/matrix/messages/message-sysmsg.js +76 -0
  58. package/dist/cjs/src/matrix/messages/message-video.d.ts +43 -0
  59. package/dist/cjs/src/matrix/messages/message-video.d.ts.map +1 -0
  60. package/dist/cjs/src/matrix/messages/message-video.js +20 -0
  61. package/dist/cjs/src/matrix/messages/sysmsg/message-pat.d.ts +14 -0
  62. package/dist/cjs/src/matrix/messages/sysmsg/message-pat.d.ts.map +1 -0
  63. package/dist/cjs/src/matrix/messages/sysmsg/message-pat.js +11 -0
  64. package/dist/cjs/src/matrix/messages/sysmsg/message-revokemsg.d.ts +19 -0
  65. package/dist/cjs/src/matrix/messages/sysmsg/message-revokemsg.d.ts.map +1 -0
  66. package/dist/cjs/src/matrix/messages/sysmsg/message-revokemsg.js +48 -0
  67. package/dist/cjs/src/matrix/messages/sysmsg/message-sysmsgtemplate.d.ts +59 -0
  68. package/dist/cjs/src/matrix/messages/sysmsg/message-sysmsgtemplate.d.ts.map +1 -0
  69. package/dist/cjs/src/matrix/messages/sysmsg/message-sysmsgtemplate.js +61 -0
  70. package/dist/cjs/src/matrix/messages/sysmsg/message-todo.d.ts +31 -0
  71. package/dist/cjs/src/matrix/messages/sysmsg/message-todo.d.ts.map +1 -0
  72. package/dist/cjs/src/matrix/messages/sysmsg/message-todo.js +16 -0
  73. package/dist/cjs/src/matrix/schema-mapper/contact.d.ts +4 -0
  74. package/dist/cjs/src/matrix/schema-mapper/contact.d.ts.map +1 -0
  75. package/dist/cjs/src/matrix/schema-mapper/contact.js +62 -0
  76. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-appmsg.d.ts +3 -0
  77. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-appmsg.d.ts.map +1 -0
  78. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-appmsg.js +100 -0
  79. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-refermsg.d.ts +3 -0
  80. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-refermsg.d.ts.map +1 -0
  81. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-refermsg.js +67 -0
  82. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-room.d.ts +3 -0
  83. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-room.d.ts.map +1 -0
  84. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-room.js +40 -0
  85. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-single-chat.d.ts +3 -0
  86. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-single-chat.d.ts.map +1 -0
  87. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-single-chat.js +11 -0
  88. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-sysmsg.d.ts +3 -0
  89. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-sysmsg.d.ts.map +1 -0
  90. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-sysmsg.js +41 -0
  91. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-type.d.ts +3 -0
  92. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-type.d.ts.map +1 -0
  93. package/dist/cjs/src/matrix/schema-mapper/message/message-parser-type.js +65 -0
  94. package/dist/cjs/src/matrix/schema-mapper/message/message-parser.d.ts +13 -0
  95. package/dist/cjs/src/matrix/schema-mapper/message/message-parser.d.ts.map +1 -0
  96. package/dist/cjs/src/matrix/schema-mapper/message/message-parser.js +20 -0
  97. package/dist/cjs/src/matrix/schema-mapper/message/mod.d.ts +3 -0
  98. package/dist/cjs/src/matrix/schema-mapper/message/mod.d.ts.map +1 -0
  99. package/dist/cjs/src/matrix/schema-mapper/message/mod.js +17 -0
  100. package/dist/cjs/src/matrix/schema-mapper/message.d.ts +6 -0
  101. package/dist/cjs/src/matrix/schema-mapper/message.d.ts.map +1 -0
  102. package/dist/cjs/src/matrix/schema-mapper/message.js +47 -0
  103. package/dist/cjs/src/matrix/schema-mapper/room.d.ts +6 -0
  104. package/dist/cjs/src/matrix/schema-mapper/room.d.ts.map +1 -0
  105. package/dist/cjs/src/matrix/schema-mapper/room.js +27 -0
  106. package/dist/cjs/src/matrix/service/request.d.ts +290 -0
  107. package/dist/cjs/src/matrix/service/request.d.ts.map +1 -0
  108. package/dist/cjs/src/matrix/service/request.js +1315 -0
  109. package/dist/cjs/src/matrix/types.d.ts +34 -0
  110. package/dist/cjs/src/matrix/types.d.ts.map +1 -0
  111. package/dist/cjs/src/matrix/types.js +30 -0
  112. package/dist/cjs/src/matrix/utils/cached-promise.d.ts +5 -0
  113. package/dist/cjs/src/matrix/utils/cached-promise.d.ts.map +1 -0
  114. package/dist/cjs/src/matrix/utils/cached-promise.js +22 -0
  115. package/dist/cjs/src/matrix/utils/image-decrypt.d.ts +7 -0
  116. package/dist/cjs/src/matrix/utils/image-decrypt.d.ts.map +1 -0
  117. package/dist/cjs/src/matrix/utils/image-decrypt.js +158 -0
  118. package/dist/cjs/src/matrix/utils/index.d.ts +4 -0
  119. package/dist/cjs/src/matrix/utils/index.d.ts.map +1 -0
  120. package/dist/cjs/src/matrix/utils/index.js +32 -0
  121. package/dist/cjs/src/matrix/utils/is-type.d.ts +9 -0
  122. package/dist/cjs/src/matrix/utils/is-type.d.ts.map +1 -0
  123. package/dist/cjs/src/matrix/utils/is-type.js +72 -0
  124. package/dist/cjs/src/matrix/utils/regex.d.ts +3 -0
  125. package/dist/cjs/src/matrix/utils/regex.d.ts.map +1 -0
  126. package/dist/cjs/src/matrix/utils/regex.js +14 -0
  127. package/dist/cjs/src/matrix/utils/runner.d.ts +3 -0
  128. package/dist/cjs/src/matrix/utils/runner.d.ts.map +1 -0
  129. package/dist/cjs/src/matrix/utils/runner.js +12 -0
  130. package/dist/cjs/src/matrix/utils/string.d.ts +2 -0
  131. package/dist/cjs/src/matrix/utils/string.d.ts.map +1 -0
  132. package/dist/cjs/src/matrix/utils/string.js +7 -0
  133. package/dist/cjs/src/matrix/utils/xml-to-json.d.ts +5 -0
  134. package/dist/cjs/src/matrix/utils/xml-to-json.d.ts.map +1 -0
  135. package/dist/cjs/src/matrix/utils/xml-to-json.js +51 -0
  136. package/dist/cjs/src/mod.d.ts +5 -0
  137. package/dist/cjs/src/mod.d.ts.map +1 -0
  138. package/dist/cjs/src/mod.js +9 -0
  139. package/dist/cjs/src/package-json.d.ts +3 -0
  140. package/dist/cjs/src/package-json.d.ts.map +1 -0
  141. package/dist/cjs/src/package-json.js +4 -0
  142. package/dist/cjs/src/package-json.spec.d.ts +3 -0
  143. package/dist/cjs/src/package-json.spec.d.ts.map +1 -0
  144. package/dist/cjs/src/package-json.spec.js +9 -0
  145. package/dist/cjs/src/puppet-matrix.d.ts +114 -0
  146. package/dist/cjs/src/puppet-matrix.d.ts.map +1 -0
  147. package/dist/cjs/src/puppet-matrix.js +1037 -0
  148. package/dist/cjs/tests/integration.spec.d.ts +3 -0
  149. package/dist/cjs/tests/integration.spec.d.ts.map +1 -0
  150. package/dist/cjs/tests/integration.spec.js +7 -0
  151. package/dist/cjs/tests/tap.spec.d.ts +3 -0
  152. package/dist/cjs/tests/tap.spec.d.ts.map +1 -0
  153. package/dist/cjs/tests/tap.spec.js +32 -0
  154. package/dist/esm/src/cleanup.d.ts +4 -0
  155. package/dist/esm/src/cleanup.d.ts.map +1 -0
  156. package/dist/esm/src/cleanup.js +24 -0
  157. package/dist/esm/src/config.d.ts +5 -0
  158. package/dist/esm/src/config.d.ts.map +1 -0
  159. package/dist/esm/src/config.js +5 -0
  160. package/dist/esm/src/engine-schema.d.ts +76 -0
  161. package/dist/esm/src/engine-schema.d.ts.map +1 -0
  162. package/dist/esm/src/engine-schema.js +11 -0
  163. package/dist/esm/src/matrix/cache-manager.d.ts +58 -0
  164. package/dist/esm/src/matrix/cache-manager.d.ts.map +1 -0
  165. package/dist/esm/src/matrix/cache-manager.js +279 -0
  166. package/dist/esm/src/matrix/events/event-friendship.d.ts +6 -0
  167. package/dist/esm/src/matrix/events/event-friendship.d.ts.map +1 -0
  168. package/dist/esm/src/matrix/events/event-friendship.js +84 -0
  169. package/dist/esm/src/matrix/events/event-message.d.ts +6 -0
  170. package/dist/esm/src/matrix/events/event-message.d.ts.map +1 -0
  171. package/dist/esm/src/matrix/events/event-message.js +3 -0
  172. package/dist/esm/src/matrix/events/event-room-invite.d.ts +6 -0
  173. package/dist/esm/src/matrix/events/event-room-invite.d.ts.map +1 -0
  174. package/dist/esm/src/matrix/events/event-room-invite.js +53 -0
  175. package/dist/esm/src/matrix/events/event-room-join.d.ts +6 -0
  176. package/dist/esm/src/matrix/events/event-room-join.d.ts.map +1 -0
  177. package/dist/esm/src/matrix/events/event-room-join.js +125 -0
  178. package/dist/esm/src/matrix/events/event-room-leave.d.ts +8 -0
  179. package/dist/esm/src/matrix/events/event-room-leave.d.ts.map +1 -0
  180. package/dist/esm/src/matrix/events/event-room-leave.js +79 -0
  181. package/dist/esm/src/matrix/events/event-room-topic.d.ts +6 -0
  182. package/dist/esm/src/matrix/events/event-room-topic.d.ts.map +1 -0
  183. package/dist/esm/src/matrix/events/event-room-topic.js +54 -0
  184. package/dist/esm/src/matrix/events/event.d.ts +28 -0
  185. package/dist/esm/src/matrix/events/event.d.ts.map +1 -0
  186. package/dist/esm/src/matrix/events/event.js +37 -0
  187. package/dist/esm/src/matrix/events/mod.d.ts +3 -0
  188. package/dist/esm/src/matrix/events/mod.d.ts.map +1 -0
  189. package/dist/esm/src/matrix/events/mod.js +14 -0
  190. package/dist/esm/src/matrix/messages/message-appmsg.d.ts +57 -0
  191. package/dist/esm/src/matrix/messages/message-appmsg.d.ts.map +1 -0
  192. package/dist/esm/src/matrix/messages/message-appmsg.js +56 -0
  193. package/dist/esm/src/matrix/messages/message-audio.d.ts +32 -0
  194. package/dist/esm/src/matrix/messages/message-audio.d.ts.map +1 -0
  195. package/dist/esm/src/matrix/messages/message-audio.js +14 -0
  196. package/dist/esm/src/matrix/messages/message-emotion.d.ts +13 -0
  197. package/dist/esm/src/matrix/messages/message-emotion.d.ts.map +1 -0
  198. package/dist/esm/src/matrix/messages/message-emotion.js +28 -0
  199. package/dist/esm/src/matrix/messages/message-image.d.ts +33 -0
  200. package/dist/esm/src/matrix/messages/message-image.d.ts.map +1 -0
  201. package/dist/esm/src/matrix/messages/message-image.js +11 -0
  202. package/dist/esm/src/matrix/messages/message-miniprogram.d.ts +4 -0
  203. package/dist/esm/src/matrix/messages/message-miniprogram.d.ts.map +1 -0
  204. package/dist/esm/src/matrix/messages/message-miniprogram.js +18 -0
  205. package/dist/esm/src/matrix/messages/message-sysmsg.d.ts +18 -0
  206. package/dist/esm/src/matrix/messages/message-sysmsg.d.ts.map +1 -0
  207. package/dist/esm/src/matrix/messages/message-sysmsg.js +69 -0
  208. package/dist/esm/src/matrix/messages/message-video.d.ts +43 -0
  209. package/dist/esm/src/matrix/messages/message-video.d.ts.map +1 -0
  210. package/dist/esm/src/matrix/messages/message-video.js +17 -0
  211. package/dist/esm/src/matrix/messages/sysmsg/message-pat.d.ts +14 -0
  212. package/dist/esm/src/matrix/messages/sysmsg/message-pat.d.ts.map +1 -0
  213. package/dist/esm/src/matrix/messages/sysmsg/message-pat.js +8 -0
  214. package/dist/esm/src/matrix/messages/sysmsg/message-revokemsg.d.ts +19 -0
  215. package/dist/esm/src/matrix/messages/sysmsg/message-revokemsg.d.ts.map +1 -0
  216. package/dist/esm/src/matrix/messages/sysmsg/message-revokemsg.js +43 -0
  217. package/dist/esm/src/matrix/messages/sysmsg/message-sysmsgtemplate.d.ts +59 -0
  218. package/dist/esm/src/matrix/messages/sysmsg/message-sysmsgtemplate.d.ts.map +1 -0
  219. package/dist/esm/src/matrix/messages/sysmsg/message-sysmsgtemplate.js +56 -0
  220. package/dist/esm/src/matrix/messages/sysmsg/message-todo.d.ts +31 -0
  221. package/dist/esm/src/matrix/messages/sysmsg/message-todo.d.ts.map +1 -0
  222. package/dist/esm/src/matrix/messages/sysmsg/message-todo.js +13 -0
  223. package/dist/esm/src/matrix/schema-mapper/contact.d.ts +4 -0
  224. package/dist/esm/src/matrix/schema-mapper/contact.d.ts.map +1 -0
  225. package/dist/esm/src/matrix/schema-mapper/contact.js +36 -0
  226. package/dist/esm/src/matrix/schema-mapper/message/message-parser-appmsg.d.ts +3 -0
  227. package/dist/esm/src/matrix/schema-mapper/message/message-parser-appmsg.d.ts.map +1 -0
  228. package/dist/esm/src/matrix/schema-mapper/message/message-parser-appmsg.js +73 -0
  229. package/dist/esm/src/matrix/schema-mapper/message/message-parser-refermsg.d.ts +3 -0
  230. package/dist/esm/src/matrix/schema-mapper/message/message-parser-refermsg.d.ts.map +1 -0
  231. package/dist/esm/src/matrix/schema-mapper/message/message-parser-refermsg.js +40 -0
  232. package/dist/esm/src/matrix/schema-mapper/message/message-parser-room.d.ts +3 -0
  233. package/dist/esm/src/matrix/schema-mapper/message/message-parser-room.d.ts.map +1 -0
  234. package/dist/esm/src/matrix/schema-mapper/message/message-parser-room.js +36 -0
  235. package/dist/esm/src/matrix/schema-mapper/message/message-parser-single-chat.d.ts +3 -0
  236. package/dist/esm/src/matrix/schema-mapper/message/message-parser-single-chat.d.ts.map +1 -0
  237. package/dist/esm/src/matrix/schema-mapper/message/message-parser-single-chat.js +7 -0
  238. package/dist/esm/src/matrix/schema-mapper/message/message-parser-sysmsg.d.ts +3 -0
  239. package/dist/esm/src/matrix/schema-mapper/message/message-parser-sysmsg.d.ts.map +1 -0
  240. package/dist/esm/src/matrix/schema-mapper/message/message-parser-sysmsg.js +37 -0
  241. package/dist/esm/src/matrix/schema-mapper/message/message-parser-type.d.ts +3 -0
  242. package/dist/esm/src/matrix/schema-mapper/message/message-parser-type.d.ts.map +1 -0
  243. package/dist/esm/src/matrix/schema-mapper/message/message-parser-type.js +38 -0
  244. package/dist/esm/src/matrix/schema-mapper/message/message-parser.d.ts +13 -0
  245. package/dist/esm/src/matrix/schema-mapper/message/message-parser.d.ts.map +1 -0
  246. package/dist/esm/src/matrix/schema-mapper/message/message-parser.js +15 -0
  247. package/dist/esm/src/matrix/schema-mapper/message/mod.d.ts +3 -0
  248. package/dist/esm/src/matrix/schema-mapper/message/mod.d.ts.map +1 -0
  249. package/dist/esm/src/matrix/schema-mapper/message/mod.js +14 -0
  250. package/dist/esm/src/matrix/schema-mapper/message.d.ts +6 -0
  251. package/dist/esm/src/matrix/schema-mapper/message.d.ts.map +1 -0
  252. package/dist/esm/src/matrix/schema-mapper/message.js +21 -0
  253. package/dist/esm/src/matrix/schema-mapper/room.d.ts +6 -0
  254. package/dist/esm/src/matrix/schema-mapper/room.d.ts.map +1 -0
  255. package/dist/esm/src/matrix/schema-mapper/room.js +22 -0
  256. package/dist/esm/src/matrix/service/request.d.ts +290 -0
  257. package/dist/esm/src/matrix/service/request.d.ts.map +1 -0
  258. package/dist/esm/src/matrix/service/request.js +1286 -0
  259. package/dist/esm/src/matrix/types.d.ts +34 -0
  260. package/dist/esm/src/matrix/types.d.ts.map +1 -0
  261. package/dist/esm/src/matrix/types.js +27 -0
  262. package/dist/esm/src/matrix/utils/cached-promise.d.ts +5 -0
  263. package/dist/esm/src/matrix/utils/cached-promise.d.ts.map +1 -0
  264. package/dist/esm/src/matrix/utils/cached-promise.js +18 -0
  265. package/dist/esm/src/matrix/utils/image-decrypt.d.ts +7 -0
  266. package/dist/esm/src/matrix/utils/image-decrypt.d.ts.map +1 -0
  267. package/dist/esm/src/matrix/utils/image-decrypt.js +153 -0
  268. package/dist/esm/src/matrix/utils/index.d.ts +4 -0
  269. package/dist/esm/src/matrix/utils/index.d.ts.map +1 -0
  270. package/dist/esm/src/matrix/utils/index.js +24 -0
  271. package/dist/esm/src/matrix/utils/is-type.d.ts +9 -0
  272. package/dist/esm/src/matrix/utils/is-type.d.ts.map +1 -0
  273. package/dist/esm/src/matrix/utils/is-type.js +62 -0
  274. package/dist/esm/src/matrix/utils/regex.d.ts +3 -0
  275. package/dist/esm/src/matrix/utils/regex.d.ts.map +1 -0
  276. package/dist/esm/src/matrix/utils/regex.js +11 -0
  277. package/dist/esm/src/matrix/utils/runner.d.ts +3 -0
  278. package/dist/esm/src/matrix/utils/runner.d.ts.map +1 -0
  279. package/dist/esm/src/matrix/utils/runner.js +9 -0
  280. package/dist/esm/src/matrix/utils/string.d.ts +2 -0
  281. package/dist/esm/src/matrix/utils/string.d.ts.map +1 -0
  282. package/dist/esm/src/matrix/utils/string.js +3 -0
  283. package/dist/esm/src/matrix/utils/xml-to-json.d.ts +5 -0
  284. package/dist/esm/src/matrix/utils/xml-to-json.d.ts.map +1 -0
  285. package/dist/esm/src/matrix/utils/xml-to-json.js +45 -0
  286. package/dist/esm/src/mod.d.ts +5 -0
  287. package/dist/esm/src/mod.d.ts.map +1 -0
  288. package/dist/esm/src/mod.js +4 -0
  289. package/dist/esm/src/package-json.d.ts +3 -0
  290. package/dist/esm/src/package-json.d.ts.map +1 -0
  291. package/dist/esm/src/package-json.js +1 -0
  292. package/dist/esm/src/package-json.spec.d.ts +3 -0
  293. package/dist/esm/src/package-json.spec.d.ts.map +1 -0
  294. package/dist/esm/src/package-json.spec.js +7 -0
  295. package/dist/esm/src/puppet-matrix.d.ts +114 -0
  296. package/dist/esm/src/puppet-matrix.d.ts.map +1 -0
  297. package/dist/esm/src/puppet-matrix.js +1007 -0
  298. package/dist/esm/tests/integration.spec.d.ts +3 -0
  299. package/dist/esm/tests/integration.spec.d.ts.map +1 -0
  300. package/dist/esm/tests/integration.spec.js +5 -0
  301. package/dist/esm/tests/tap.spec.d.ts +3 -0
  302. package/dist/esm/tests/tap.spec.d.ts.map +1 -0
  303. package/dist/esm/tests/tap.spec.js +7 -0
  304. package/package.json +98 -0
  305. package/src/cleanup.ts +36 -0
  306. package/src/config.ts +15 -0
  307. package/src/engine-schema.ts +171 -0
  308. package/src/matrix/cache-manager.ts +359 -0
  309. package/src/matrix/events/event-friendship.ts +116 -0
  310. package/src/matrix/events/event-message.ts +7 -0
  311. package/src/matrix/events/event-room-invite.ts +64 -0
  312. package/src/matrix/events/event-room-join.ts +200 -0
  313. package/src/matrix/events/event-room-leave.ts +111 -0
  314. package/src/matrix/events/event-room-topic.ts +73 -0
  315. package/src/matrix/events/event.ts +60 -0
  316. package/src/matrix/events/mod.ts +16 -0
  317. package/src/matrix/messages/message-appmsg.ts +131 -0
  318. package/src/matrix/messages/message-audio.ts +48 -0
  319. package/src/matrix/messages/message-emotion.ts +68 -0
  320. package/src/matrix/messages/message-image.ts +46 -0
  321. package/src/matrix/messages/message-miniprogram.ts +45 -0
  322. package/src/matrix/messages/message-sysmsg.ts +106 -0
  323. package/src/matrix/messages/message-video.ts +62 -0
  324. package/src/matrix/messages/sysmsg/message-pat.ts +22 -0
  325. package/src/matrix/messages/sysmsg/message-revokemsg.ts +70 -0
  326. package/src/matrix/messages/sysmsg/message-sysmsgtemplate.ts +133 -0
  327. package/src/matrix/messages/sysmsg/message-todo.ts +45 -0
  328. package/src/matrix/schema-mapper/contact.ts +37 -0
  329. package/src/matrix/schema-mapper/message/message-parser-appmsg.ts +78 -0
  330. package/src/matrix/schema-mapper/message/message-parser-refermsg.ts +53 -0
  331. package/src/matrix/schema-mapper/message/message-parser-room.ts +62 -0
  332. package/src/matrix/schema-mapper/message/message-parser-single-chat.ts +12 -0
  333. package/src/matrix/schema-mapper/message/message-parser-sysmsg.ts +62 -0
  334. package/src/matrix/schema-mapper/message/message-parser-type.ts +48 -0
  335. package/src/matrix/schema-mapper/message/message-parser.ts +35 -0
  336. package/src/matrix/schema-mapper/message/mod.ts +17 -0
  337. package/src/matrix/schema-mapper/message.ts +30 -0
  338. package/src/matrix/schema-mapper/room.ts +28 -0
  339. package/src/matrix/service/request.ts +1944 -0
  340. package/src/matrix/types.ts +37 -0
  341. package/src/matrix/utils/cached-promise.ts +25 -0
  342. package/src/matrix/utils/image-decrypt.ts +198 -0
  343. package/src/matrix/utils/index.ts +34 -0
  344. package/src/matrix/utils/is-type.ts +72 -0
  345. package/src/matrix/utils/regex.ts +15 -0
  346. package/src/matrix/utils/runner.ts +12 -0
  347. package/src/matrix/utils/string.ts +3 -0
  348. package/src/matrix/utils/xml-to-json.ts +59 -0
  349. package/src/mod.ts +10 -0
  350. package/src/package-json.spec.ts +10 -0
  351. package/src/package-json.ts +11 -0
  352. package/src/puppet-matrix.ts +1402 -0
@@ -0,0 +1,1944 @@
1
+ import axios from 'axios'
2
+ import { log } from '@juzi/wechaty-puppet'
3
+ import { EventEmitter } from 'events'
4
+ // @ts-ignore
5
+ import WebSocket from 'ws'
6
+ import * as PUPPET from '@juzi/wechaty-puppet'
7
+ import { format, getUnixTime } from 'date-fns'
8
+ import { xmlToJson } from '../utils/xml-to-json.js'
9
+ import { isRoomId } from '../utils/is-type.js'
10
+
11
+ const PRE = '[PuppetMatrix]'
12
+
13
+ /**
14
+ * 创建实例传过来的参数
15
+ */
16
+ export type PuppetMatrixOptions = {
17
+ httpServer?: string;
18
+ endpoint?: string;
19
+ token?: string;
20
+ };
21
+
22
+ export enum NotifyTypeEnum {
23
+ Ready = 1001,
24
+ LoginQRCodeChange = 1002, // set
25
+ UserLogin = 1003, // set
26
+ UserLogout = 1004, // set
27
+ InitFinish = 1005,
28
+ HeartBeatError = 1006,
29
+ SessionTimeout = 1007,
30
+ LoginFailed = 1008,
31
+ ContactSyncFinish = 1009,
32
+ NewMsg = 1010, // set
33
+ ContactInfoChange = 1039,
34
+ FriendAdd = 1040, // set
35
+ FriendDel = 1041,
36
+ RoomAdd = 1042,
37
+ RoomQuit = 1043,
38
+ RoomDelMe = 1044,
39
+ RoomDisband = 1045,
40
+ RoomMemberAdd = 1046, // set
41
+ RoomMemberUpdate = 1047,
42
+ RoomMemberDel = 1048, // set
43
+ }
44
+
45
+ /**
46
+ * 性别
47
+ */
48
+ enum ContactGender {
49
+ Unknown = 0, // 位置
50
+ Male = 1, // 男
51
+ Female = 2, // 女
52
+ }
53
+
54
+ /**
55
+ * 群成员
56
+ */
57
+ export interface ChatRoomMember {
58
+ wxid: string; // wxid
59
+ groupNick: string; // 群昵称
60
+ avatarMinUrl?: string;
61
+ avatarMaxUrl?: string;
62
+ avatar?: string; // 头像
63
+ inviterUserName?: string; // 邀请人
64
+ displayName?: string; // 群备注
65
+ sex?: number;
66
+ wxNum?: string; // 微信号
67
+ alias?: string; // 备注名
68
+ }
69
+
70
+ /**
71
+ * 好友 或 群 实例构造参数 务必按照此格式返回数据,否则可能报错,非必填值可以不传
72
+ */
73
+ export interface ContactPayload {
74
+ /**
75
+ * 头像,需在会话列表中
76
+ */
77
+ avatar: string;
78
+ /**
79
+ * 城市,需在会话列表中
80
+ */
81
+ city: string;
82
+ /**
83
+ * 国家,需在会话列表中
84
+ */
85
+ country: string;
86
+ /**
87
+ * 群成员数量,仅当对象是群聊时有效
88
+ */
89
+ memberNum?: number;
90
+ /**
91
+ * 朋友圈背景图,需在会话列表中 暂时无用
92
+ */
93
+ momentsBackgroudImgUrl?: string;
94
+ /**
95
+ * 昵称
96
+ */
97
+ name: string;
98
+ /**
99
+ * 备注
100
+ */
101
+ alias: string;
102
+ /**
103
+ * 省份,需在会话列表中
104
+ */
105
+ province: string;
106
+ /**
107
+ * 备注
108
+ */
109
+ remark?: string;
110
+ /**
111
+ * 性别,1=男,2=女
112
+ */
113
+ sex: ContactGender;
114
+ /**
115
+ * 签名,需在会话列表中
116
+ */
117
+ sign?: string;
118
+
119
+ /**
120
+ * 添加好友需要的ticket 票据 不同的客户端可能不同,自己构造好就行,会原样返回的 针对daen 是 v3 + '-' + v4
121
+ */
122
+ ticket?: string;
123
+ /**
124
+ * 微信ID
125
+ */
126
+ wxid: string;
127
+ /**
128
+ * 微信号
129
+ */
130
+ wxNum: string;
131
+ /**
132
+ * 群成员 id
133
+ */
134
+ chatroommemberList?: string[];
135
+ /**
136
+ * 群主
137
+ */
138
+ ownerId?: string;
139
+ /**
140
+ * 群管id
141
+ */
142
+ adminIdList?: string[];
143
+ /**
144
+ * 是否好友
145
+ */
146
+ isFriend?: number;
147
+ /**
148
+ * 加好友场景 来源,1=qq 3=微信号 6=单向添加 10和13=通讯录 14=群聊 15=手机号 17=名片 30=扫一扫
149
+ */
150
+ scene?: string;
151
+ device?: string;
152
+ qq?: string;
153
+ phone?: string;
154
+ email?: string;
155
+ description?: string;
156
+ labelIdlist?: string;
157
+ /**
158
+ * 朋友圈背景图
159
+ */
160
+ snsBgImg?: string;
161
+ /**
162
+ * 好友类型
163
+ * 1
164
+ */
165
+ contactType?: number;
166
+ /**
167
+ * 群公告
168
+ */
169
+ announcement?: string;
170
+ }
171
+
172
+ /**
173
+ * 微信登录状态
174
+ */
175
+ enum Status {
176
+ normal = 'normal',
177
+ offline = 'offline',
178
+ pending = 'pending',
179
+ fail = 'fail',
180
+ }
181
+
182
+ /**
183
+ * 登录状态
184
+ */
185
+ export interface StatsResult {
186
+ status: Status;
187
+ }
188
+
189
+ export type ClientEvent =
190
+ | 'kickout'
191
+ | 'contact'
192
+ | 'message'
193
+ | 'scan'
194
+ | 'verify-code';
195
+ /**
196
+ * 消息类型:1|文本 3|图片 34|语音 42|名片 43|视频 47|动态表情 48|地理位置 49|分享链接或附件 2001|红包 2002|小程序 2003|群邀请 10000|系统消息
197
+ */
198
+ export enum WechatMessageType {
199
+ Text = 1,
200
+ Image = 3,
201
+ Voice = 34,
202
+ VerifyMsg = 37,
203
+ PossibleFriendMsg = 40,
204
+ ShareCard = 42,
205
+ Video = 43,
206
+ Emoticon = 47,
207
+ Location = 48,
208
+ App = 49,
209
+ VoipMsg = 50,
210
+ StatusNotify = 51,
211
+ VoipNotify = 52,
212
+ VoipInvite = 53,
213
+ MicroVideo = 62,
214
+ VerifyMsgEnterprise = 65,
215
+ Transfer = 2000, // 转账
216
+ RedEnvelope = 2001, // 红包
217
+ MiniProgram = 2002, // 小程序
218
+ GroupInvite = 2003, // 群邀请
219
+ File = 2004, // 文件消息
220
+ SysNotice = 9999,
221
+ Sys = 10000,
222
+ SysTemplate = 10002, // NOTIFY 服务通知
223
+ }
224
+
225
+ /**
226
+ * 收到的消息格式
227
+ */
228
+ export interface MessagePayload {
229
+ id: string; // 消息id
230
+ timeStamp: number; // 10位时间戳
231
+ talkerId: string; // 发消息 人 或者 群
232
+ text: string; // 消息内容
233
+ msgType?: WechatMessageType;
234
+ fromWxid: string; // 群id
235
+ atWxidList?: string[]; // 消息中艾特人wxid列表
236
+ msg: string; // 消息内容
237
+ listenerId: string; //
238
+ }
239
+
240
+ export interface BaseEvent {
241
+ errorCode: number;
242
+ errorMessage: string;
243
+ wxid?: string;
244
+ name?: string;
245
+ robotInfo?: ContactPayload;
246
+ }
247
+
248
+ export interface ImageMessagePayload {
249
+ aes_key: string;
250
+ file_id: string;
251
+ file_size: string | number;
252
+ file_name?: string;
253
+ }
254
+
255
+ export interface AudioMessagePayload {
256
+ aesKey: string;
257
+ length: string;
258
+ voicelength: string;
259
+ voiceurl: string;
260
+ voicemd5: string;
261
+ clientmsgid: string;
262
+ fromusername: string;
263
+ }
264
+
265
+ export interface VoiceMessagePayload {
266
+ length: string;
267
+ }
268
+ export interface VideoMessagePayload {
269
+ aes_key: string;
270
+ file_id: string;
271
+ file_size: string;
272
+ play_length: string;
273
+ thumb_aes_key: string;
274
+ thumb_url: string;
275
+ thumb_size: string;
276
+ thumb_width: string;
277
+ thumb_height: string;
278
+ file_name: '';
279
+ }
280
+
281
+ export enum FriendshipType {
282
+ Unknown = 0,
283
+ Confirm,
284
+ Receive,
285
+ Verify,
286
+ Delete,
287
+ Removed,
288
+ }
289
+
290
+ export interface ContactEvent {
291
+ type: FriendshipType;
292
+ contactInfo: ContactPayload;
293
+ }
294
+
295
+ export interface QrStatus {
296
+ qrcode: string;
297
+ status: number;
298
+ }
299
+
300
+ export interface VerifyInfo {
301
+ uuid: string;
302
+ ticket: string;
303
+ }
304
+
305
+ export interface LogoutInfo {
306
+ contactId: string;
307
+ reason: string;
308
+ }
309
+ export interface QrInfo {
310
+ status: number;
311
+ url?: string;
312
+ }
313
+ export interface RoomJoinPayload {
314
+ roomId: string;
315
+ inviterId: string;
316
+ joinIds: string[];
317
+ }
318
+ export interface RoomLeavPayload {
319
+ roomId: string;
320
+ leaveIds: string[];
321
+ }
322
+
323
+ async function getAtWxidList (source: string): Promise<string[]> {
324
+ if (source) {
325
+ const json = await xmlToJson(source)
326
+ return (
327
+ json?.msgsource?.atuserlist?.split(',').filter((item: string) => item)
328
+ || []
329
+ )
330
+ }
331
+ return []
332
+ }
333
+ class Client extends EventEmitter {
334
+
335
+ private readonly options: PuppetMatrixOptions
336
+ socket: any
337
+ server: any
338
+ tokenInfo: any
339
+ hasEmitLogout: boolean
340
+
341
+ // @ts-ignore
342
+ override emit(event: 'hook', detail: BaseEvent): boolean;
343
+ override emit(event: 'login', detail: BaseEvent): boolean;
344
+ override emit(event: 'logout', message: string): boolean;
345
+ override emit(event: 'message', messageList: MessagePayload): boolean;
346
+ override emit(event: 'contact', detail: ContactEvent): boolean;
347
+ override emit(event: 'error', detail: ContactEvent): boolean;
348
+ override emit(event: 'scan', qrInfo: QrInfo): boolean;
349
+ override emit(event: 'verify-code', verifyInfo: VerifyInfo): boolean;
350
+ override emit(event: 'update-contacts', contacts: ContactPayload[]): boolean;
351
+ override emit(event: 'room-join', info: any): boolean;
352
+
353
+ override emit (event: ClientEvent, ...args: any[]): boolean {
354
+ return super.emit(event, ...args)
355
+ }
356
+
357
+ public static async create (options: PuppetMatrixOptions) {
358
+ const client = new Client(options)
359
+ await client.initServer()
360
+ return client
361
+ }
362
+
363
+ private constructor (options: PuppetMatrixOptions = {}) {
364
+ super()
365
+ this.options = options
366
+ this.tokenInfo = null
367
+ this.socket = null
368
+ this.hasEmitLogout = false
369
+ }
370
+
371
+ async getTokenInfo () {
372
+ try {
373
+ const res = await axios.get(`https://api-bot.aibotk.com/openapi/v1/token/info?secret=5be06b6f8d42a7&token=${this.options.token}`)
374
+ if (res.data.code === 0) {
375
+ this.tokenInfo = res.data.data
376
+ return true
377
+ } else {
378
+ log.error('Token auth failed, reason: %s', res.data.message)
379
+ return false
380
+ }
381
+ } catch (e) {
382
+ log.error('error info: %s', e)
383
+ return false
384
+ }
385
+ }
386
+
387
+ async initServer () {
388
+ await this.getTokenInfo()
389
+ if (!this.socket) {
390
+ const ws = new WebSocket(
391
+ `${this.tokenInfo.endpoint}?guid=${this.tokenInfo.guid}`,
392
+ { perMessageDeflate: true, maxPayload: 100 * 1024 * 1024 },
393
+ )
394
+
395
+ /**
396
+ * 1. Message
397
+ * 1.1. Deal with payload
398
+ */
399
+ ws.on('message', (data: string) => {
400
+ log.silly(PRE, 'initWebSocket() ws.on(message): %s', data)
401
+ try {
402
+ const payload: any = JSON.parse(data)
403
+ log.info(JSON.stringify(payload))
404
+ void this.eventParse(payload)
405
+ } catch (e: any) {
406
+ log.warn(PRE, 'initWebSocket() ws.on(message) exception: %s', e)
407
+ this.emit('error', e.message)
408
+ }
409
+ })
410
+
411
+ /**
412
+ * 1. Message
413
+ * 1.2. use websocket message as heartbeat source
414
+ */
415
+ ws.on('message', () => {
416
+ // if (!this.throttleQueue || !this.debounceQueue) {
417
+ // log.warn(PRE, 'initWebSocket() ws.on(message) throttleQueue or debounceQueue not exist')
418
+ // return
419
+ // }
420
+ // if (this.connectionStatus.status === CONNECTED) {
421
+ // this.debounceQueue.next('ws.on(message)')
422
+ // this.throttleQueue.next('ws.on(message)')
423
+ // }
424
+ })
425
+
426
+ /**
427
+ * 2. Error
428
+ */
429
+ ws.on('error', (e: any) => {
430
+ if (e.message.indexOf('ECONNREFUSED') !== -1) {
431
+ // Can not connect to remote server, if this is triggered when puppet-padchat is connected,
432
+ // an close event must be emitted, so ignore this error
433
+ // If this is triggered when puppet-padchat is trying to reconnect, also ignore this error
434
+ } else {
435
+ log.verbose(PRE, 'initWebSocket() ws.on(error) %s', e)
436
+ this.emit('error', e)
437
+ }
438
+ })
439
+
440
+ /**
441
+ * 3. Close
442
+ */
443
+ ws.on('close', (code: any, reason: any) => {
444
+ log.warn(
445
+ PRE,
446
+ 'initWebSocket() ws.on(close) code: %s, reason: %s',
447
+ code,
448
+ reason,
449
+ )
450
+
451
+ // if (!this.reconnectThrottleQueue) {
452
+ // log.warn(PRE, 'initWebSocket() ws.on(close) reconnectThrottleQueue not exist')
453
+ // return
454
+ // }
455
+ // if (this.connectionStatus.status === CONNECTED) {
456
+ // this.reconnectThrottleQueue.next('ws.on(close, ' + code + ')')
457
+ // }
458
+ })
459
+
460
+ /**
461
+ * 5. Wait the WebSocket to be connected
462
+ */
463
+ await new Promise((resolve, reject) => {
464
+ ws.once('open', () => {
465
+ log.silly(PRE, 'initWebSocket() Promise() ws.on(open)')
466
+ return resolve({})
467
+ })
468
+
469
+ ws.once('error', (e: any) => {
470
+ log.silly(PRE, 'initWebSocket() Promise() ws.on(error) %s', e)
471
+ return reject(e)
472
+ })
473
+ ws.once('close', (e: any) => {
474
+ log.silly(PRE, 'initWebSocket() Promise() ws.on(close)')
475
+ return reject(e)
476
+ })
477
+ })
478
+
479
+ this.socket = ws
480
+ return
481
+ }
482
+ if (this.socket) {
483
+ throw new Error('socket had already been opened!')
484
+ }
485
+ }
486
+
487
+ async eventParse (eventData: any) {
488
+ const notifyType = eventData.notify_type
489
+ const data = eventData.data
490
+ let robotInfo, msg: MessagePayload, contactInfo: ContactPayload, atWxidList
491
+ switch (notifyType) {
492
+ case NotifyTypeEnum.LoginQRCodeChange:
493
+ if (data.authUrl) {
494
+ // @ts-ignore
495
+ this.emit('verify-code', {
496
+ ticket: this.getQrcodeTicket(data.authUrl),
497
+ status: PUPPET.types.ScanStatus.Scanned,
498
+ })
499
+ } else {
500
+ void this.onQrCodeEvent(
501
+ data.status,
502
+ `http://weixin.qq.com/x/${data.uuid}`,
503
+ )
504
+ }
505
+ break
506
+ case NotifyTypeEnum.UserLogin:
507
+ robotInfo = {
508
+ wxNum: data?.alias,
509
+ wxid: data?.username || '',
510
+ name: data?.nickname || '',
511
+ sex: data?.sex,
512
+ alias: '',
513
+ province: data?.province || '',
514
+ city: data?.city || '',
515
+ country: data?.country || '',
516
+ avatar: data?.big_headimg_url || data?.small_headimg_url || '',
517
+ description: '',
518
+ labelIdlist: '',
519
+ }
520
+
521
+ this.emit('login', {
522
+ errorCode: 0,
523
+ errorMessage: 'success',
524
+ wxid: robotInfo.wxid,
525
+ robotInfo,
526
+ })
527
+ break
528
+ case NotifyTypeEnum.NewMsg:
529
+ if (data.is_chatroom_msg) {
530
+ atWxidList = await getAtWxidList(data.source)
531
+ }
532
+ msg = {
533
+ msg: data.content,
534
+ text: data.content,
535
+ id: data.msg_id,
536
+ atWxidList,
537
+ fromWxid: data.from_username,
538
+ msgType: data.msg_type,
539
+ timeStamp: data.create_time,
540
+ talkerId: !data.is_chatroom_msg
541
+ ? data.from_username
542
+ : data.chatroom_sender,
543
+ listenerId: data.to_username,
544
+ }
545
+ this.emit('message', msg)
546
+ break
547
+ case NotifyTypeEnum.FriendAdd:
548
+ contactInfo = {
549
+ wxNum: data?.alias,
550
+ wxid: data?.username || '',
551
+ name: data?.nickname || '',
552
+ sex: data?.sex,
553
+ alias: '',
554
+ province: data?.province || '',
555
+ city: data?.city || '',
556
+ country: data?.country || '',
557
+ avatar: data?.big_headimg_url || data?.small_headimg_url || '',
558
+ description: '',
559
+ labelIdlist: data?.labelid_list,
560
+ }
561
+ this.emit('contact', { type: FriendshipType.Confirm, contactInfo })
562
+ break
563
+ case NotifyTypeEnum.ContactInfoChange:
564
+ contactInfo = {
565
+ wxNum: data?.alias,
566
+ wxid: data?.username || '',
567
+ name: data?.nickname || '',
568
+ sex: data?.sex,
569
+ alias: '',
570
+ province: data?.province || '',
571
+ city: data?.city || '',
572
+ country: data?.country || '',
573
+ avatar: data?.big_headimg_url || data?.small_headimg_url || '',
574
+ description: '',
575
+ labelIdlist: data?.labelid_list,
576
+ }
577
+ this.emit('update-contacts', [ contactInfo ])
578
+ break
579
+ case NotifyTypeEnum.UserLogout:
580
+ this.emit('logout', data.errmsg)
581
+ break
582
+ case NotifyTypeEnum.RoomMemberAdd:
583
+ this.emit('room-join', {
584
+ roomId: data.room_username,
585
+ inviterId: data.member_list[0]?.invite_username,
586
+ joinIds: data.member_list.map((item: any) => item.username),
587
+ joinUsers: data.member_list.map((data: any) => ({
588
+ wxNum: data?.alias,
589
+ wxid: data?.username || '',
590
+ name: data?.nickname || '',
591
+ sex: data?.sex,
592
+ alias: '',
593
+ province: data?.province || '',
594
+ city: data?.city || '',
595
+ country: data?.country || '',
596
+ avatar: data?.big_headimg_url || data?.small_headimg_url || '',
597
+ description: '',
598
+ labelIdlist: data?.labelid_list,
599
+ })),
600
+ })
601
+ break
602
+ case NotifyTypeEnum.RoomMemberDel:
603
+ // @ts-ignore
604
+ this.emit('room-leave', {
605
+ roomId: data.room_username,
606
+ leaveIds: data.member_list.map((item: any) => item.username),
607
+ })
608
+ break
609
+ default:
610
+ log.info('other data', JSON.stringify(data))
611
+ }
612
+ }
613
+
614
+ getQrcodeTicket (authurl: string): string {
615
+ if (!authurl || !authurl.startsWith('http')) return ''
616
+ const url = new URL(authurl)
617
+ const searchParams = new URLSearchParams(url.search.slice(1))
618
+ return searchParams.get('ticket') || ''
619
+ }
620
+
621
+ async onQrCodeEvent (status: number, url?: string) {
622
+ const ScanStatusName = {
623
+ [PUPPET.types.ScanStatus.Unknown]: 'Unknown',
624
+ [PUPPET.types.ScanStatus.Cancel]: 'Cancel',
625
+ [PUPPET.types.ScanStatus.Waiting]: 'Waiting',
626
+ [PUPPET.types.ScanStatus.Scanned]: 'Scanned',
627
+ [PUPPET.types.ScanStatus.Confirmed]: 'Confirmed',
628
+ [PUPPET.types.ScanStatus.Timeout]: 'Timeout',
629
+ }
630
+ let scanStatus: PUPPET.types.ScanStatus = PUPPET.types.ScanStatus.Unknown
631
+ let qrUrl: string | undefined = ''
632
+ switch (status) {
633
+ case 0:
634
+ scanStatus = PUPPET.types.ScanStatus.Waiting
635
+ qrUrl = url
636
+ break
637
+ case 1:
638
+ scanStatus = PUPPET.types.ScanStatus.Scanned
639
+ break
640
+ case 2:
641
+ scanStatus = PUPPET.types.ScanStatus.Confirmed
642
+ break
643
+ case 3:
644
+ scanStatus = PUPPET.types.ScanStatus.Cancel
645
+ break
646
+ case 4:
647
+ scanStatus = PUPPET.types.ScanStatus.Timeout
648
+ break
649
+ }
650
+ log.silly(
651
+ PRE,
652
+ `scan event, status: ${ScanStatusName[scanStatus]}${
653
+ url ? ', with qrcode: ' + url : ''
654
+ }`,
655
+ )
656
+
657
+ // @ts-ignore
658
+ this.emit('scan', {
659
+ qrcode: qrUrl,
660
+ status: scanStatus,
661
+ })
662
+ }
663
+
664
+ setEmitLogout (val: boolean) {
665
+ this.hasEmitLogout = val
666
+ if (val) {
667
+ let time: any = setTimeout(() => {
668
+ this.hasEmitLogout = false
669
+ clearTimeout(time)
670
+ time = null
671
+ }, 10000)
672
+ }
673
+ }
674
+
675
+ async postData (data: any) {
676
+ const config: any = {
677
+ data: {
678
+ guid: this.tokenInfo.guid,
679
+ ...data.data,
680
+ },
681
+ headers: {
682
+ 'Content-Type': 'application/json',
683
+ },
684
+ method: 'POST',
685
+ url: this.tokenInfo.httpServer + data.path,
686
+ timeout: 600000,
687
+ }
688
+
689
+ const res = await axios(config)
690
+
691
+ if (res.data?.errcode === -102) {
692
+ log.warn('request error: %s', res.data?.errmsg)
693
+ if (!this.hasEmitLogout) {
694
+ this.setEmitLogout(true)
695
+ this.emit('logout', res.data?.errmsg)
696
+ }
697
+
698
+ return {}
699
+ }
700
+
701
+ return res.data
702
+ }
703
+
704
+ /**
705
+ * 获取微信运行状态
706
+ */
707
+ public async getStats (): Promise<StatsResult> {
708
+ const res = await this.postData({
709
+ path: '/client/get_client_status',
710
+ data: {},
711
+ })
712
+ // 0: stop, 1: running, 2: online
713
+ const { errcode, data } = res
714
+ if (!errcode) {
715
+ return {
716
+ status:
717
+ data.status === 1
718
+ ? Status.pending
719
+ : data.status === 2
720
+ ? Status.normal
721
+ : Status.offline,
722
+ }
723
+ } else {
724
+ return { status: Status.fail }
725
+ }
726
+ }
727
+
728
+ /**
729
+ * 获取登录二维码
730
+ */
731
+ public async getQrcode (): Promise<{
732
+ base64: string;
733
+ qrcodeUrl: string;
734
+ expiredTime: number;
735
+ uuid: string;
736
+ } | null> {
737
+ try {
738
+ const res = await this.postData({
739
+ path: '/login/get_login_qrcode',
740
+ data: {},
741
+ })
742
+
743
+ if (res?.qrcode) {
744
+ return {
745
+ base64: `data:image/jpeg;base64,${res?.qrcode?.buffer}`,
746
+ qrcodeUrl: `http://weixin.qq.com/x/${res?.uuid}`,
747
+ uuid: res?.uuid,
748
+ expiredTime: res?.expiredTime,
749
+ }
750
+ }
751
+ log.info(PRE, 'getQrcode error:', res?.errmsg)
752
+ return null
753
+ } catch (e) {
754
+ log.error(PRE, 'getQrcode(): %s', e)
755
+ return null
756
+ }
757
+ }
758
+
759
+ /**
760
+ * 获取登录二维码状态
761
+ * NEW: 0,
762
+ * SCANNED: 1,
763
+ * CONFIRMED: 2,
764
+ * CANCELLED: 3,
765
+ * EXPIRED: 4,
766
+ * UNKNOWN_ERROR: 5
767
+ */
768
+ public async getQrcodeStatus (): Promise<{
769
+ uuid?: string;
770
+ status: number;
771
+ pushLoginUrlexpiredTime?: number;
772
+ expiredTime?: number;
773
+ } | null> {
774
+ try {
775
+ const res = await this.postData({
776
+ path: '/login/check_login_qrcode',
777
+ data: {},
778
+ })
779
+ if (res?.uuid) {
780
+ return res
781
+ }
782
+ log.info(PRE, 'getQrcodeStatus error:', res?.errmsg)
783
+ return {
784
+ status: 4,
785
+ }
786
+ } catch (e) {
787
+ log.error(PRE, 'getQrcodeStatus(): %s', e)
788
+ return {
789
+ status: 4,
790
+ }
791
+ }
792
+ }
793
+
794
+ public async verifyLoginUrl (ticket: string, pin: string): Promise<void> {
795
+ try {
796
+ const res = await this.postData({
797
+ path: '/login/verify_login_url',
798
+ data: {
799
+ ticket,
800
+ pin,
801
+ },
802
+ })
803
+
804
+ log.info(PRE, 'verifyLoginUrl', res)
805
+ } catch (e) {
806
+ log.error(PRE, 'verifyLoginUrl(): %s', e)
807
+ }
808
+ }
809
+
810
+ /**
811
+ * 推送手机登录通知
812
+ */
813
+ public async pushLoginNotify (): Promise<any> {
814
+ await this.postData({
815
+ path: '/login/push_login_url',
816
+ data: {},
817
+ })
818
+ }
819
+
820
+ /**
821
+ * 获取当前bot信息
822
+ */
823
+ public async getSelfInfo (): Promise<ContactPayload | boolean> {
824
+ try {
825
+ const res = await this.postData({ path: '/user/get_profile', data: {} })
826
+ if (res.errcode === -102) {
827
+ log.info(PRE, 'offline login:', res?.errmsg)
828
+ return false
829
+ } else if (res.userInfo) {
830
+ const contact = res?.userInfo
831
+ const contactMore = res?.userInfoExt
832
+ return {
833
+ wxNum: contact.alias,
834
+ wxid: contact?.userName?.string || '',
835
+ name: contact?.nickName?.string || '',
836
+ sex: contact?.sex,
837
+ alias: contact?.remark?.string || '',
838
+ province: contact?.province || '',
839
+ city: contact?.city || '',
840
+ country: contact?.country || '',
841
+ avatar:
842
+ contactMore?.bigHeadImgUrl || contactMore?.smallHeadImgUrl || '',
843
+ description: contact?.description,
844
+ labelIdlist: contact?.labelIdlist,
845
+ }
846
+ }
847
+ log.info(PRE, 'get self info error:(%s)', res?.errmsg)
848
+ return false
849
+ } catch (e) {
850
+ log.error(PRE, 'getSelfInfo(): %s', e)
851
+ return false
852
+ }
853
+ }
854
+
855
+ /**
856
+ * 获取机器人二维码
857
+ */
858
+ public async getUserQrcode (): Promise<string> {
859
+ try {
860
+ const res = await this.postData({
861
+ path: '/user/get_qrcode',
862
+ data: {},
863
+ })
864
+ return res.qrcodeUrl
865
+ } catch (e) {
866
+ log.error(PRE, 'getUserQrcode(): %s', e)
867
+ return ''
868
+ }
869
+ }
870
+
871
+ /**
872
+ * 退出登录
873
+ */
874
+ public async logout (): Promise<void> {
875
+ try {
876
+ await this.postData({
877
+ path: '/user/logout',
878
+ data: {},
879
+ })
880
+ } catch (e) {
881
+ log.error(PRE, 'logout(): %s', e)
882
+ }
883
+ }
884
+
885
+ /**
886
+ * 查询对象简单信息
887
+ * @param contactId
888
+ */
889
+ public async searchContact (
890
+ contactIds: string[],
891
+ ): Promise<ContactPayload | ContactPayload[] | undefined> {
892
+ if (!contactIds.length) return
893
+
894
+ try {
895
+ const res = await this.postData({
896
+ path: '/contact/batch_get_contact_brief_info',
897
+ data: {
898
+ username_list: contactIds,
899
+ },
900
+ })
901
+ if (res.contactList?.length === 1) {
902
+ const contactInfo = res.contactList?.length
903
+ ? res.contactList[0]
904
+ : undefined
905
+ if (contactInfo) {
906
+ const contact = contactInfo.contact
907
+ return {
908
+ wxNum: contact.alias,
909
+ wxid: contact?.userName?.string || '',
910
+ name: contact?.nickName?.string || '',
911
+ sex: contact?.sex,
912
+ alias: contact?.remark?.string || '',
913
+ province: contact?.province || '',
914
+ city: contact?.city || '',
915
+ country: contact?.country || '',
916
+ avatar: contact?.bigHeadImgUrl || contact?.smallHeadImgUrl || '',
917
+ description: contact?.description,
918
+ labelIdlist: contact?.labelIdlist,
919
+ }
920
+ }
921
+ return undefined
922
+ } else {
923
+ const contacts: ContactPayload[]
924
+ = res.contactList?.map((contactInfo: any) => {
925
+ const contact = contactInfo.contact
926
+ return {
927
+ wxNum: contact.alias,
928
+ wxid: contact?.userName?.string || '',
929
+ name: contact?.nickName?.string || '',
930
+ sex: contact?.sex,
931
+ alias: contact?.remark?.string || '',
932
+ province: contact?.province || '',
933
+ city: contact?.city || '',
934
+ country: contact?.country || '',
935
+ avatar: contact?.bigHeadImgUrl || contact?.smallHeadImgUrl || '',
936
+ description: contact?.description,
937
+ labelIdlist: contact?.labelIdlist,
938
+ }
939
+ }) || []
940
+ return contacts
941
+ }
942
+ } catch (e) {
943
+ log.error(PRE, 'searchContact(%s): %s', contactIds, e)
944
+ return undefined
945
+ }
946
+ }
947
+
948
+ /**
949
+ * 查询对象详细信息
950
+ * @param contactId
951
+ */
952
+ public async searchContactDetail (
953
+ contactIds: string[],
954
+ roomId?: string,
955
+ ): Promise<ContactPayload | ContactPayload[] | undefined> {
956
+ if (!contactIds.length && !roomId) return undefined
957
+
958
+ try {
959
+ const data: any = {}
960
+ if (contactIds.length) {
961
+ data['username_list'] = contactIds
962
+ }
963
+ if (roomId) {
964
+ data['room_username'] = roomId
965
+ }
966
+ const res = await this.postData({
967
+ path: '/contact/get_contact',
968
+ data,
969
+ })
970
+ if (res.contactList?.length === 1) {
971
+ const contactInfo = res.contactList.length
972
+ ? res.contactList[0]
973
+ : undefined
974
+ if (contactInfo) {
975
+ const contact = contactInfo.contact || {}
976
+ return {
977
+ wxNum: contact?.alias,
978
+ wxid: contact?.userName?.string,
979
+ name: contact?.nickName?.string || '',
980
+ sex: contact?.sex || 0,
981
+ alias: contact?.remark?.string || '',
982
+ province: contact?.province || '',
983
+ city: contact?.city || '',
984
+ country: contact?.country || '',
985
+ avatar: contact?.bigHeadImgUrl || contact?.smallHeadImgUrl || '',
986
+ description: contact?.description,
987
+ labelIdlist: contact?.labelIdlist,
988
+ scene: contact?.addContactScene,
989
+ sign: contact?.signature,
990
+ snsBgImg: contact?.snsUserInfo?.snsBgimgId,
991
+ }
992
+ }
993
+ return undefined
994
+ } else {
995
+ return res.contactList?.map((contactInfo: any) => {
996
+ const contact = contactInfo.contact || {}
997
+ return {
998
+ wxNum: contact?.alias,
999
+ wxid: contact?.userName?.string,
1000
+ name: contact?.nickName?.string || '',
1001
+ sex: contact?.sex || 0,
1002
+ alias: contact?.remark?.string || '',
1003
+ province: contact?.province || '',
1004
+ city: contact?.city || '',
1005
+ country: contact?.country || '',
1006
+ avatar: contact?.bigHeadImgUrl || contact?.smallHeadImgUrl || '',
1007
+ description: contact?.description,
1008
+ labelIdlist: contact?.labelIdlist,
1009
+ scene: contact?.addContactScene,
1010
+ sign: contact?.signature,
1011
+ snsBgImg: contact?.snsUserInfo?.snsBgimgId,
1012
+ }
1013
+ })
1014
+ }
1015
+ } catch (e) {
1016
+ log.error(PRE, 'searchContactDetail(%s, %s): %s', contactIds, roomId, e)
1017
+ return undefined
1018
+ }
1019
+ }
1020
+
1021
+ /**
1022
+ * 同步联系人
1023
+ */
1024
+ public async syncContact (): Promise<void> {
1025
+ try {
1026
+ const res = await this.postData({
1027
+ path: '/contact/init_contact',
1028
+ data: {
1029
+ contact_seq: 0,
1030
+ room_seq: 0,
1031
+ },
1032
+ })
1033
+ const contactUsernameList = res.contactUsernameList || []
1034
+ const contactsInfo: ContactPayload[] = (await this.searchContact(
1035
+ contactUsernameList,
1036
+ )) as ContactPayload[]
1037
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1038
+ this.emit('update-contacts', contactsInfo || [])
1039
+ } catch (e) {
1040
+ log.error(PRE, 'syncContact(): %s', e)
1041
+ }
1042
+ }
1043
+
1044
+ /**
1045
+ * 获取好友列表 (本地存储)
1046
+ */
1047
+ public async getContactList (
1048
+ page: number = 1,
1049
+ pageSize: number = 100,
1050
+ ): Promise<void> {
1051
+ try {
1052
+ const res = await this.postData({
1053
+ path: '/contact/get_friends',
1054
+ data: {
1055
+ page_num: page,
1056
+ page_size: pageSize,
1057
+ },
1058
+ })
1059
+
1060
+ const totalPage = res.total_page || 1
1061
+ const contactList: ContactPayload[] = res.contact_list
1062
+ .filter((item: any) => item.username)
1063
+ .map((contact: any) => {
1064
+ return {
1065
+ isFriend: true,
1066
+ wxNum: contact?.alias,
1067
+ wxid: contact?.username,
1068
+ name: contact?.nickname || '',
1069
+ sex: contact?.sex,
1070
+ alias: contact?.remark || '',
1071
+ province: contact?.province || '',
1072
+ city: contact?.city || '',
1073
+ country: contact?.country || '',
1074
+ avatar:
1075
+ contact?.big_headimg_url || contact?.small_headimg_url || '',
1076
+ labelIdlist: contact?.labelIdlist,
1077
+ }
1078
+ })
1079
+ this.emit('update-contacts', contactList)
1080
+ if (page < totalPage) {
1081
+ await this.getContactList(page + 1, pageSize)
1082
+ }
1083
+ } catch (e) {
1084
+ log.error(PRE, 'getContactList(): %s', e)
1085
+ }
1086
+ }
1087
+
1088
+ /**
1089
+ * 获取群聊列表
1090
+ */
1091
+ public async getGroupList (
1092
+ page: number = 1,
1093
+ pageSize: number = 100,
1094
+ ): Promise<void> {
1095
+ try {
1096
+ const res = await this.postData({
1097
+ path: '/room/get_chatrooms',
1098
+ data: {
1099
+ page_num: page,
1100
+ page_size: pageSize,
1101
+ },
1102
+ })
1103
+ const totalPage = res.total_page || 1
1104
+ const groupList: ContactPayload[] = res.room_list
1105
+ .filter((item: any) => item.username)
1106
+ .map((item: any) => {
1107
+ return {
1108
+ wxid: item.username,
1109
+ announcement: item?.announcement,
1110
+ ownerId: item?.creator,
1111
+ name: item?.nickname,
1112
+ avatar: item?.headimg_url,
1113
+ memberNum: item?.total_member,
1114
+ chatroommemberList: [],
1115
+ }
1116
+ })
1117
+
1118
+ if (groupList.length > 0) {
1119
+ this.emit('update-contacts', groupList)
1120
+ }
1121
+
1122
+ if (parseInt(page.toString()) < parseInt(totalPage.toString())) {
1123
+ await this.getGroupList(parseInt(page.toString()) + 1, pageSize)
1124
+ }
1125
+ } catch (e) {
1126
+ log.error(PRE, 'getGroupList(): %s', e)
1127
+ }
1128
+ }
1129
+
1130
+ public async getGroupMembersDetail (roomId: string) {
1131
+ try {
1132
+ const res = await this.postData({
1133
+ path: '/room/get_chatroom_member_detail',
1134
+ data: {
1135
+ room_username: roomId,
1136
+ version: 0,
1137
+ },
1138
+ })
1139
+ const memeberIdList: string[]
1140
+ = res?.allMemberUserNameList.map((item: any) => item.string) || []
1141
+ const allMemberCount = res.allMemberCount
1142
+ const ownerId = res.chatRoomOwner
1143
+ const adminIdList: string[]
1144
+ = res?.adminUserNameList.map((item: any) => item.string) || []
1145
+ const memberList: ContactPayload[] = res?.newChatroomData?.chatRoomMember
1146
+ .filter((item: any) => item.username)
1147
+ .map((item: any) => ({
1148
+ wxid: item.username, // wxid
1149
+ groupNick: item?.nickname, // 群昵称
1150
+ avatarMinUrl: item?.smallHeadImgUrl,
1151
+ avatarMaxUrl: item?.bigHeadImgUrl,
1152
+ avatar: item?.bigHeadImgUrl || item?.smallHeadImgUrl, // 头像
1153
+ inviterUserName: item?.inviterUserName, // 邀请人
1154
+ }))
1155
+ return {
1156
+ memeberIdList,
1157
+ allMemberCount,
1158
+ ownerId,
1159
+ adminIdList,
1160
+ memberList,
1161
+ }
1162
+ } catch (e) {
1163
+ log.error(PRE, 'getGroupMembers(%s): %s', roomId, e)
1164
+ return []
1165
+ }
1166
+ }
1167
+
1168
+ /**
1169
+ * 获取群成员列表
1170
+ * @param roomId 群id
1171
+ * @param page
1172
+ * @param pageSize
1173
+ */
1174
+ public async getGroupMembers (
1175
+ roomId: string,
1176
+ page: number = 1,
1177
+ pageSize: number = 100,
1178
+ ): Promise<ContactPayload[]> {
1179
+ try {
1180
+ const res = await this.postData({
1181
+ path: '/room/get_chatroom_members',
1182
+ data: {
1183
+ room_username: roomId,
1184
+ page_num: page,
1185
+ page_size: pageSize,
1186
+ },
1187
+ })
1188
+
1189
+ const totalPage = res.total_page || 1
1190
+ const memberList = res.room_list
1191
+ .filter((item: any) => item.username)
1192
+ .map((item: any) => ({
1193
+ wxid: item.username, // wxid
1194
+ groupNick: item?.nickname, // 群昵称
1195
+ avatarMinUrl: item?.small_headimg_url,
1196
+ avatarMaxUrl: item?.big_headimg_url,
1197
+ avatar: item?.big_headimg_url || item?.small_headimg_url, // 头像
1198
+ inviterUserName: item?.invite_username, // 邀请人
1199
+ country: item?.country,
1200
+ province: item?.province,
1201
+ city: item?.city,
1202
+ displayName: item?.display_name, // 群备注
1203
+ sex: item?.sex,
1204
+ wxNum: item?.alias,
1205
+ alias: item?.remark,
1206
+ }))
1207
+
1208
+ if (page < totalPage) {
1209
+ const nextPageContacts = await this.getGroupMembers(roomId, page + 1, pageSize)
1210
+ return memberList.concat(nextPageContacts)
1211
+ } else {
1212
+ return memberList
1213
+ }
1214
+ } catch (e) {
1215
+ log.error(PRE, 'getGroupMembers(%s): %s', roomId, e)
1216
+ return []
1217
+ }
1218
+ }
1219
+
1220
+ /**
1221
+ * 获公众号聊列表
1222
+ */
1223
+ public async getOfficeList (
1224
+ page: number = 1,
1225
+ pageSize: number = 100,
1226
+ ): Promise<void> {
1227
+ try {
1228
+ const res = await this.postData({
1229
+ path: '/contact/get_publics',
1230
+ data: {
1231
+ page_num: page,
1232
+ page_size: pageSize,
1233
+ },
1234
+ })
1235
+ const totalPage = res.total_page || 1
1236
+ const officeList = res.contact_list
1237
+ .filter((item: any) => item.username)
1238
+ .map((contact: any) => {
1239
+ return {
1240
+ wxNum: contact?.alias,
1241
+ wxid: contact?.username,
1242
+ name: contact?.nickname || '',
1243
+ sex: contact?.sex,
1244
+ alias: contact?.remark || '',
1245
+ province: contact?.province || '',
1246
+ city: contact?.city || '',
1247
+ country: contact?.country || '',
1248
+ avatar:
1249
+ contact?.big_headimg_url || contact?.small_headimg_url || '',
1250
+ labelIdlist: contact?.labelIdlist,
1251
+ }
1252
+ })
1253
+ this.emit('update-contacts', officeList)
1254
+ if (page < totalPage) {
1255
+ await this.getOfficeList(page + 1, pageSize)
1256
+ }
1257
+ } catch (e) {
1258
+ log.error(PRE, 'getOfficeList(): %s', e)
1259
+ }
1260
+ }
1261
+
1262
+ /**
1263
+ * 发送文本消息
1264
+ * @param contactId
1265
+ * @param msg
1266
+ */
1267
+ public async sendText (
1268
+ contactId: string,
1269
+ msg: string,
1270
+ selfId?: string | undefined,
1271
+ ): Promise<MessagePayload | void> {
1272
+ try {
1273
+ const res = await this.postData({
1274
+ path: '/msg/send_text',
1275
+ data: {
1276
+ to_username: contactId,
1277
+ content: msg,
1278
+ },
1279
+ })
1280
+
1281
+ return {
1282
+ id: res?.list?.[0].newMsgId || '',
1283
+ timeStamp: res?.list?.[0].createTime || '',
1284
+ msgType: res?.list?.[0].type || '',
1285
+ talkerId: selfId || '',
1286
+ text: msg,
1287
+ msg,
1288
+ fromWxid: isRoomId(contactId) ? contactId : '',
1289
+ listenerId: contactId,
1290
+ }
1291
+ } catch (e) {
1292
+ log.error(PRE, 'sendText(%s, %s, %s): %s', contactId, msg, e)
1293
+ }
1294
+ }
1295
+
1296
+ /**
1297
+ * 发送文本消息带@
1298
+ * @param contactId
1299
+ * @param msg
1300
+ * @param atList
1301
+ * @param selfId
1302
+ */
1303
+
1304
+ public async sendAtText (
1305
+ contactId: string,
1306
+ msg: string,
1307
+ atList: string[],
1308
+ selfId: string | undefined,
1309
+ ): Promise<MessagePayload | void> {
1310
+
1311
+ try {
1312
+ const res = await this.postData({
1313
+ path: '/msg/send_room_at',
1314
+ data: {
1315
+ to_username: contactId,
1316
+ content: msg,
1317
+ at_list: atList,
1318
+ },
1319
+ })
1320
+
1321
+ return {
1322
+ id: res?.list?.[0].newMsgId || '',
1323
+ timeStamp: res?.list?.[0].createTime || '',
1324
+ msgType: res?.list?.[0].type || '',
1325
+ talkerId: selfId || '',
1326
+ text: msg,
1327
+ msg,
1328
+ fromWxid: isRoomId(contactId) ? contactId : '',
1329
+ listenerId: contactId,
1330
+ }
1331
+ } catch (e) {
1332
+ log.error(PRE, 'sendText(%s, %s, %s): %s', contactId, msg, atList, e)
1333
+ }
1334
+ }
1335
+
1336
+ /**
1337
+ * 上传文件到cdn
1338
+ * @param url
1339
+ */
1340
+
1341
+ public async uploadFile (url: string, type: number): Promise<any> {
1342
+ return await this.postData({
1343
+ path: '/cloud/cdn_upload',
1344
+ data: {
1345
+ file_type: type,
1346
+ url,
1347
+ },
1348
+ })
1349
+ }
1350
+
1351
+ public async downloadImage (imageInfo: ImageMessagePayload): Promise<any> {
1352
+ const params = {
1353
+ file_type: 2,
1354
+ file_id: imageInfo.file_id,
1355
+ aes_key: imageInfo.aes_key,
1356
+ file_size: imageInfo.file_size,
1357
+ file_name: `/微信图片_${format(new Date(), 'yyyyMMddHHmmss')}.png`,
1358
+ }
1359
+ const res = await this.postData({
1360
+ path: '/cloud/cdn_download',
1361
+ data: params,
1362
+ })
1363
+ return encodeURI(res.url) || ''
1364
+ }
1365
+
1366
+ /**
1367
+ * 下载文件
1368
+ * @param imageInfo
1369
+ */
1370
+ public async downloadFile (imageInfo: ImageMessagePayload): Promise<any> {
1371
+ const params = {
1372
+ file_type: 5,
1373
+ file_id: imageInfo.file_id.replace('@cdn_', ''),
1374
+ aes_key: imageInfo.aes_key,
1375
+ file_size: imageInfo.file_size,
1376
+ file_name: '/' + imageInfo.file_name,
1377
+ }
1378
+ const res = await this.postData({
1379
+ path: '/cloud/cdn_download',
1380
+ data: params,
1381
+ })
1382
+
1383
+ return encodeURI(res.url) || ''
1384
+ }
1385
+
1386
+ /**
1387
+ * 下载语音
1388
+ * @param imageInfo
1389
+ */
1390
+ public async downloadAudio (
1391
+ msgId: string,
1392
+ voiceInfo: VoiceMessagePayload,
1393
+ roomId?: string,
1394
+ ): Promise<any> {
1395
+ const params = {
1396
+ msg_id: msgId,
1397
+ length: voiceInfo.length,
1398
+ room_username: roomId,
1399
+ file_name: '/voice.mp3',
1400
+ to_mp3: true,
1401
+ }
1402
+ const res = await this.postData({
1403
+ path: '/cloud/download_voice',
1404
+ data: params,
1405
+ })
1406
+
1407
+ return encodeURI(res.url) || ''
1408
+ }
1409
+
1410
+ /**
1411
+ * 下载视频
1412
+ * @param imageInfo
1413
+ */
1414
+ public async downloadVideo (videoInfo: VideoMessagePayload): Promise<any> {
1415
+ const params = {
1416
+ file_type: 4,
1417
+ file_id: videoInfo.file_id,
1418
+ aes_key: videoInfo.aes_key,
1419
+ file_size: videoInfo.file_size,
1420
+ file_name: `/微信视频_${format(new Date(), 'yyyyMMddHHmmss')}.mp4`,
1421
+ }
1422
+
1423
+ const res = await this.postData({
1424
+ path: '/cloud/cdn_download',
1425
+ data: params,
1426
+ })
1427
+
1428
+ return encodeURI(res.url) || ''
1429
+ }
1430
+
1431
+ /**
1432
+ * 发送图片
1433
+ * @param contactId 要给谁,支持好友、群聊、公众号等
1434
+ * @param url 远程图片路径
1435
+ */
1436
+ public async sendUrlImg (
1437
+ contactId: string,
1438
+ url: string,
1439
+ selfId: string | undefined,
1440
+ ): Promise<MessagePayload | void> {
1441
+ try {
1442
+ const fileInfo = await this.uploadFile(url, 2)
1443
+ const res = await this.postData({
1444
+ path: '/msg/send_image',
1445
+ data: {
1446
+ to_username: contactId,
1447
+ file_id: fileInfo.file_id,
1448
+ aes_key: fileInfo.aes_key,
1449
+ file_size: fileInfo.file_size,
1450
+ big_file_size: 0,
1451
+ thumb_file_size: fileInfo.thumb_file_size,
1452
+ file_md5: fileInfo.md5,
1453
+ thumb_width: fileInfo.thumb_width,
1454
+ thumb_height: fileInfo.thumb_height,
1455
+ file_crc: fileInfo.file_crc,
1456
+ },
1457
+ })
1458
+ return {
1459
+ id: res?.newMsgId || '',
1460
+ timeStamp: res?.createTime || '',
1461
+ msgType: WechatMessageType.Image,
1462
+ talkerId: selfId || '',
1463
+ text: url,
1464
+ msg: url,
1465
+ fromWxid: isRoomId(contactId) ? contactId : '',
1466
+ listenerId: contactId,
1467
+ }
1468
+ } catch (e) {
1469
+ log.error(PRE, 'sendUrlImg(%s, %s): %s', contactId, url, e)
1470
+ }
1471
+ }
1472
+
1473
+ /**
1474
+ * 发送视频
1475
+ * @param contactId 要给谁,支持好友、群聊、公众号等
1476
+ * @param url 远程路径
1477
+ */
1478
+ public async sendVideo (
1479
+ contactId: string,
1480
+ url: string,
1481
+ selfId: string | undefined,
1482
+ ): Promise<MessagePayload | void> {
1483
+ try {
1484
+ const fileInfo = await this.uploadFile(url, 4)
1485
+ const res = await this.postData({
1486
+ path: '/msg/send_video',
1487
+ data: {
1488
+ to_username: contactId,
1489
+ file_id: fileInfo.file_id,
1490
+ aes_key: fileInfo.aes_key,
1491
+ file_size: fileInfo.file_size,
1492
+ thumb_file_size: fileInfo.thumb_file_size,
1493
+ file_md5: fileInfo.md5,
1494
+ thumb_file_md5: fileInfo.thumb_file_md5,
1495
+ video_duration: fileInfo.video_duration,
1496
+ file_crc: fileInfo.file_crc,
1497
+ mp4_identify: fileInfo.mp4_identify,
1498
+ },
1499
+ })
1500
+
1501
+ return {
1502
+ id: res?.newMsgId || '',
1503
+ timeStamp: res?.createTime || getUnixTime(new Date()),
1504
+ msgType: WechatMessageType.Image,
1505
+ talkerId: selfId || '',
1506
+ text: url,
1507
+ msg: url,
1508
+ fromWxid: isRoomId(contactId) ? contactId : '',
1509
+ listenerId: contactId,
1510
+ }
1511
+ } catch (error) {
1512
+ log.error(PRE, 'sendVideo(%s, %s): %s', contactId, url, error)
1513
+ }
1514
+ }
1515
+
1516
+ /**
1517
+ * 发送文件
1518
+ * @param contactId 要给谁,支持好友、群聊、公众号等
1519
+ * @param url 远程路径
1520
+ */
1521
+ public async sendCloudFile (
1522
+ contactId: string,
1523
+ url: string,
1524
+ selfId: string | undefined,
1525
+ ): Promise<MessagePayload | void> {
1526
+ try {
1527
+ const fileInfo = await this.uploadFile(url, 5)
1528
+ const res = await this.postData({
1529
+ path: '/msg/send_file',
1530
+ data: {
1531
+ to_username: contactId,
1532
+ file_id: fileInfo.file_id,
1533
+ aes_key: fileInfo.aes_key,
1534
+ file_size: fileInfo.file_size,
1535
+ file_md5: fileInfo.md5,
1536
+ file_name: fileInfo.name,
1537
+ file_key: fileInfo.file_key,
1538
+ },
1539
+ })
1540
+ return {
1541
+ id: res?.newMsgId || '',
1542
+ timeStamp: res?.createTime || '',
1543
+ msgType: WechatMessageType.App,
1544
+ talkerId: selfId || '',
1545
+ text: url,
1546
+ msg: url,
1547
+ fromWxid: isRoomId(contactId) ? contactId : '',
1548
+ listenerId: contactId,
1549
+ }
1550
+ } catch (error) {
1551
+ log.error(PRE, 'sendCloudFile(%s, %s): %s', contactId, url, error)
1552
+ }
1553
+ }
1554
+
1555
+ /**
1556
+ * 发送分享链接
1557
+ * @param contactId
1558
+ * @param title
1559
+ * @param content
1560
+ * @param jumpUrl 点击跳转地址
1561
+ * @param imageUrl 缩略图地址
1562
+ */
1563
+ public async sendShareCard (
1564
+ {
1565
+ contactId,
1566
+ title,
1567
+ content,
1568
+ jumpUrl,
1569
+ imageUrl,
1570
+ }: {
1571
+ contactId: string;
1572
+ title: string;
1573
+ content: string | undefined;
1574
+ jumpUrl: string;
1575
+ imageUrl: string | undefined;
1576
+ },
1577
+ selfId: string | undefined,
1578
+ ): Promise<MessagePayload | void> {
1579
+ try {
1580
+ const res = await this.postData({
1581
+ path: '/msg/send_link_card',
1582
+ data: {
1583
+ to_username: contactId,
1584
+ title,
1585
+ desc: content,
1586
+ url: jumpUrl,
1587
+ image_url: imageUrl,
1588
+ },
1589
+ })
1590
+ return {
1591
+ id: res?.newMsgId || '',
1592
+ timeStamp: res?.createTime || '',
1593
+ msgType: WechatMessageType.Text,
1594
+ talkerId: selfId || '',
1595
+ text: jumpUrl,
1596
+ msg: jumpUrl,
1597
+ fromWxid: isRoomId(contactId) ? contactId : '',
1598
+ listenerId: contactId,
1599
+ }
1600
+ } catch (e) {
1601
+ log.error('error info', e)
1602
+ }
1603
+ }
1604
+
1605
+ /**
1606
+ * 发送小程序
1607
+ * @param contactId
1608
+ * @param title
1609
+ * @param content
1610
+ * @param jumpUrl 点击跳转地址 点击跳转地址,例如饿了么首页为:pages/index/index.html
1611
+ * @param gh 例如饿了么为:gh_6506303a12bb
1612
+ * @param path 本地图片路径
1613
+ */
1614
+ public async sendMiniProgram (
1615
+ {
1616
+ appid,
1617
+ contactId,
1618
+ title,
1619
+ content,
1620
+ pagePath,
1621
+ username,
1622
+ thumbUrl,
1623
+ iconUrl,
1624
+ }: any,
1625
+ selfId: string | undefined,
1626
+ ): Promise<MessagePayload | void> {
1627
+ try {
1628
+ const fileInfo = await this.uploadFile(thumbUrl, 2)
1629
+ const res = await this.postData({
1630
+ path: '/msg/send_mini_app',
1631
+ data: {
1632
+ to_username: contactId,
1633
+ appid,
1634
+ username:
1635
+ username && username.endsWith('@app')
1636
+ ? username
1637
+ : username + '@app',
1638
+ title: content,
1639
+ appname: title,
1640
+ page_path: pagePath,
1641
+ appicon: iconUrl,
1642
+ file_id: fileInfo.file_id,
1643
+ aes_key: fileInfo.aes_key,
1644
+ file_size: fileInfo.file_size,
1645
+ file_md5: fileInfo.md5,
1646
+ },
1647
+ })
1648
+
1649
+ return {
1650
+ id: res?.newMsgId || '',
1651
+ timeStamp: res?.createTime || '',
1652
+ msgType: WechatMessageType.MiniProgram,
1653
+ talkerId: selfId || '',
1654
+ text: appid + '_' + username,
1655
+ msg: appid + '_' + username,
1656
+ fromWxid: isRoomId(contactId) ? contactId : '',
1657
+ listenerId: contactId,
1658
+ }
1659
+ } catch (error) {
1660
+ log.error(PRE, 'sendMiniProgram(%s, %s): %s', contactId, username, error)
1661
+ }
1662
+ }
1663
+
1664
+ /**
1665
+ * 发送xml消息
1666
+ * XML里<fromusername>wxid_3sq4tklb6c3121</fromusername>必须为自己的wxid,切记
1667
+ * @param contactId
1668
+ * @param xml
1669
+ * 1.消息内支持文本代码,详情见文本代码章节
1670
+ * 2.微信最多支持4096个字符,相当于2048个汉字,请勿超出否则崩溃
1671
+ */
1672
+ public async sendXml (
1673
+ contactId: string,
1674
+ xml: string,
1675
+ selfId: string | undefined,
1676
+ ): Promise<MessagePayload | void> {
1677
+ try {
1678
+ const res = await this.postData({
1679
+ path: '/msg/send_app_msg',
1680
+ data: {
1681
+ to_username: contactId,
1682
+ app_type: 0,
1683
+ appid: '',
1684
+ xml,
1685
+ },
1686
+ })
1687
+
1688
+ return {
1689
+ id: res?.newMsgId || '',
1690
+ timeStamp: res?.createTime || '',
1691
+ msgType: WechatMessageType.App,
1692
+ talkerId: selfId || '',
1693
+ text: xml,
1694
+ msg: xml,
1695
+ fromWxid: isRoomId(contactId) ? contactId : '',
1696
+ listenerId: contactId,
1697
+ }
1698
+ } catch (error) {
1699
+ log.error(PRE, 'sendXml(%s, %s): %s', contactId, xml, error)
1700
+ }
1701
+ }
1702
+
1703
+ /**
1704
+ * 同意好友请求
1705
+ * @param contactId
1706
+ * @param scene 来源
1707
+ * @param ticket
1708
+ */
1709
+ public async confirmFriendship (
1710
+ contactId: string,
1711
+ scene: string | number | undefined,
1712
+ ticket: string,
1713
+ ): Promise<void> {
1714
+ const res = await this.postData({
1715
+ path: '/contact/verify_friend',
1716
+ data: {
1717
+ username: contactId,
1718
+ scene: (scene && scene.toString()) || 6,
1719
+ ticket,
1720
+ opcode: 3, // 检查好友状态=>1, 单向加好友=>2, 同意好友申请=>3
1721
+ },
1722
+ })
1723
+ return res
1724
+ }
1725
+
1726
+ /**
1727
+ * 添加好友_通过wxid
1728
+ * @param scene 来源 1=qq 3=微信号 6=单向添加 10和13=通讯录 14=群聊 15=手机号 17=名片 30=扫一扫
1729
+ * @param content 打招呼内容
1730
+ * @param wxid wxid
1731
+ */
1732
+ public async addFriendByWxid ({
1733
+ scene,
1734
+ wxid,
1735
+ content,
1736
+ ticket,
1737
+ }: {
1738
+ scene: string | undefined;
1739
+ content: string | undefined;
1740
+ wxid: string | undefined;
1741
+ ticket: string | undefined;
1742
+ }): Promise<void> {
1743
+ await this.postData({
1744
+ path: '/contact/add_friend',
1745
+ data: {
1746
+ scene,
1747
+ username: wxid,
1748
+ verify_content: content,
1749
+ ticket,
1750
+ },
1751
+ })
1752
+ }
1753
+
1754
+ /**
1755
+ * 查询陌生人信息
1756
+ * @param content 手机号或者QQ
1757
+ */
1758
+ public async searchStranger (content: string): Promise<ContactPayload> {
1759
+ const contact = await this.postData({
1760
+ path: '/contact/search_contact',
1761
+ data: {
1762
+ username: content,
1763
+ from_scene: 0,
1764
+ search_scene: 0,
1765
+ },
1766
+ })
1767
+
1768
+ return {
1769
+ wxNum: contact?.alias || '',
1770
+ wxid: contact?.userName?.string,
1771
+ isFriend:
1772
+ contact?.userName?.string.includes('@stranger')
1773
+ && contact?.userName?.string.includes('v3_')
1774
+ ? 0
1775
+ : 1,
1776
+ name: contact?.nickName?.string || '',
1777
+ sex: contact?.sex,
1778
+ alias: contact?.remark?.string || '',
1779
+ province: contact?.province || '',
1780
+ city: contact?.city || '',
1781
+ country: contact?.country || '',
1782
+ avatar: contact?.bigHeadImgUrl || contact?.smallHeadImgUrl || '',
1783
+ description: contact?.description,
1784
+ labelIdlist: contact?.labelIdlist,
1785
+ scene: contact?.addContactScene,
1786
+ sign: contact?.signature,
1787
+ snsBgImg: contact?.snsUserInfo?.snsBgimgId,
1788
+ ticket: contact?.antispamTicket,
1789
+ }
1790
+ }
1791
+
1792
+ /**
1793
+ * 邀请进群
1794
+ * @param groupId 群id
1795
+ * @param contactId 好友wxid
1796
+ * @param type 类型 1直接拉 2 发送邀请链接
1797
+ */
1798
+ public async inviteToGroup (
1799
+ groupId: string,
1800
+ contactId: string,
1801
+ type: number = 1,
1802
+ ): Promise<void> {
1803
+ if (type === 1) {
1804
+ await this.postData({
1805
+ path: '/room/add_chatroom_member',
1806
+ data: {
1807
+ room_username: groupId,
1808
+ username_list: [ contactId ],
1809
+ },
1810
+ })
1811
+ } else {
1812
+ await this.postData({
1813
+ path: '/room/invite_chatroom_member',
1814
+ data: {
1815
+ room_username: groupId,
1816
+ username_list: [ contactId ],
1817
+ },
1818
+ })
1819
+ }
1820
+ }
1821
+
1822
+ /**
1823
+ * 删除好友
1824
+ * @param contactId 好友wxid
1825
+ */
1826
+ public async removeContact (contactId: string): Promise<void> {
1827
+ await this.postData({
1828
+ path: '/contact/del_friend',
1829
+ data: {
1830
+ username: contactId,
1831
+ },
1832
+ })
1833
+ }
1834
+
1835
+ /**
1836
+ * 设置好友备注
1837
+ * @param contactId 好友wxid
1838
+ * @param remark 支持emoji、微信表情
1839
+ */
1840
+ public async setContactAlias (
1841
+ contactId: string,
1842
+ remark: string,
1843
+ ): Promise<void> {
1844
+ await this.postData({
1845
+ path: '/contact/modify_remark',
1846
+ data: {
1847
+ username: contactId,
1848
+ remark,
1849
+ },
1850
+ })
1851
+ }
1852
+
1853
+ /**
1854
+ * 修改群名
1855
+ * @param groupId 群id
1856
+ * @param name 群名
1857
+ */
1858
+ public async setGroupName (
1859
+ groupId: string,
1860
+ name: string | undefined,
1861
+ ): Promise<void> {
1862
+ await this.postData({
1863
+ path: '/room/modify_chatroom_name',
1864
+ data: {
1865
+ room_username: groupId,
1866
+ name,
1867
+ },
1868
+ })
1869
+ }
1870
+
1871
+ /**
1872
+ * 删除好友
1873
+ * @param contactId 好友wxid
1874
+ */
1875
+ public async roomQuit (roomId: string): Promise<void> {
1876
+ await this.postData({
1877
+ path: '/room/quit_chatroom',
1878
+ data: {
1879
+ room_username: roomId,
1880
+ },
1881
+ })
1882
+ }
1883
+
1884
+ /**
1885
+ * 发送名片
1886
+ * @param contactId 接收人id
1887
+ * @param xml 名片xml
1888
+ */
1889
+ public async sendContactCard (
1890
+ contactId: string,
1891
+ xml: string | any,
1892
+ selfId: string | undefined,
1893
+ ): Promise<MessagePayload | void> {
1894
+ try {
1895
+ const res = await this.postData({
1896
+ path: '/msg/send_share_card_raw',
1897
+ data: {
1898
+ to_username: contactId,
1899
+ xml,
1900
+ },
1901
+ })
1902
+ return {
1903
+ id: res?.newMsgId || '',
1904
+ timeStamp: res?.createTime || '',
1905
+ msgType: WechatMessageType.App,
1906
+ talkerId: selfId || '',
1907
+ text: xml,
1908
+ msg: xml,
1909
+ fromWxid: isRoomId(contactId) ? contactId : '',
1910
+ listenerId: contactId,
1911
+ }
1912
+ } catch (error) {
1913
+ log.error(PRE, 'sendContactCard(%s, %s): %s', contactId, xml, error)
1914
+ }
1915
+ }
1916
+
1917
+ /**
1918
+ * 发送群公告
1919
+ * @param roomId 群id
1920
+ * @param content 公告内容
1921
+ */
1922
+ public async sendAnnouncement (
1923
+ roomId: string,
1924
+ content: string,
1925
+ ): Promise<void> {
1926
+ try {
1927
+ const res = await this.postData({
1928
+ path: '/room/set_chatroom_announcement',
1929
+ data: {
1930
+ room_username: roomId,
1931
+ announcement: content,
1932
+ },
1933
+ })
1934
+ if (res.baseResponse.ret) {
1935
+ log.error('sendAnnouncement error: %s', JSON.stringify(res.baseResponse))
1936
+ }
1937
+ } catch (error) {
1938
+ log.error(PRE, 'sendAnnouncement(%s, %s): %s', roomId, content, error)
1939
+ }
1940
+ }
1941
+
1942
+ }
1943
+
1944
+ export default Client