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,1402 @@
1
+ import { log } from '@juzi/wechaty-puppet'
2
+ import * as PUPPET from '@juzi/wechaty-puppet'
3
+ import type { FileBoxInterface } from 'file-box'
4
+ import { FileBox } from 'file-box'
5
+ import type { ContactPayload, MessagePayload } from './engine-schema.js'
6
+ import type { FileBoxMetadataMessage } from './matrix/types.js'
7
+ import Client from './matrix/service/request.js'
8
+ import { getUnixTime } from 'date-fns'
9
+
10
+ import { delay } from './matrix/utils/index.js'
11
+ import path from 'path'
12
+ // 参考
13
+ import { CacheManager, RoomMemberMap } from './matrix/cache-manager.js'
14
+ import { isIMContactId, isRoomId } from './matrix/utils/is-type.js'
15
+ import { AppMessagePayload, parseAppmsgMessagePayload } from './matrix/messages/message-appmsg.js'
16
+ import { parseMiniProgramMessagePayload } from './matrix/messages/message-miniprogram.js'
17
+ import { parseEmotionMessagePayload } from './matrix/messages/message-emotion.js'
18
+ import { ImageMessagePayload, parseImageMessagePayload } from './matrix/messages/message-image.js'
19
+ import { parseAudioMessagePayload, AudioMessagePayload } from './matrix/messages/message-audio.js'
20
+ import { parseVideoMessagePayload, VideoMessagePayload } from './matrix/messages/message-video.js'
21
+ import { CachedPromiseFunc } from './matrix/utils/cached-promise.js'
22
+ import { engineMessageToWechaty } from './matrix/schema-mapper/message.js'
23
+ import { engineContactToWechaty } from './matrix/schema-mapper/contact.js'
24
+ import {
25
+ chatRoomMemberToContact,
26
+ engineRoomMemberToWechaty,
27
+ engineRoomToWechaty,
28
+ } from './matrix/schema-mapper/room.js'
29
+ import { parseEvent, EventType } from './matrix/events/mod.js'
30
+ import { addRunningPuppet, removeRunningPuppet } from './cleanup.js'
31
+ import { packageJson } from './package-json.js'
32
+ import { JsonToXml } from './matrix/utils/xml-to-json.js'
33
+
34
+ const VERSION = packageJson.version || '0.0.0'
35
+ const PRE = '[PuppetMatrix]'
36
+ const SEARCH_CONTACT_PREFIX = '$search$-'
37
+ const STRANGER_SUFFIX = '@stranger'
38
+
39
+ export type PuppetEngineOptions = PUPPET.PuppetOptions & {
40
+ token?: string,
41
+ engine?: any
42
+ }
43
+
44
+ class PuppetMatrix extends PUPPET.Puppet {
45
+
46
+ private _cacheMgr?: CacheManager
47
+ private _client?: Client
48
+ private _self?: ContactPayload | undefined
49
+ private _qrcodeTicket: string | null | undefined
50
+ private _printVersion: boolean = true
51
+ private _heartBeatTimer?: ReturnType<typeof setTimeout>
52
+ private _qrcodeInterval?: ReturnType<typeof setInterval> | null
53
+ private _qrcodeStatuasInterval?: ReturnType<typeof setInterval> | null
54
+ public static override readonly VERSION = VERSION
55
+
56
+ constructor (public override options: PuppetEngineOptions = {} as PuppetEngineOptions) {
57
+ super(options)
58
+
59
+ this.options.engine = Client
60
+
61
+ if (!this.options.token) {
62
+ const token = process.env['WECHATY_PUPPET_MATRIX_TOKEN'] || ''
63
+ if (token) {
64
+ this.options.token = token
65
+ }
66
+ }
67
+ }
68
+
69
+ public get client () {
70
+ return this._client
71
+ }
72
+
73
+ override async onStart (): Promise<void> {
74
+ log.verbose(PRE, 'onStart()')
75
+ await this._startClient()
76
+ }
77
+
78
+ /**
79
+ * 启动监听
80
+ * @private
81
+ */
82
+ private async _startClient () {
83
+ if (!this._client) {
84
+ this._client = await this.options.engine.create(this.options)
85
+ }
86
+
87
+ await this._startPuppetHeart(true)
88
+ if (this._client) {
89
+ this._client.on('login', this.wrapAsync(async ({ robotInfo } : { robotInfo: ContactPayload }) => {
90
+ log.info(PRE, `login success: ${robotInfo.name}`)
91
+ await this.onLogin(robotInfo)
92
+ }))
93
+ this._client.on('message', this.wrapAsync(async (message:MessagePayload) => {
94
+ await this._onPushMessage(message)
95
+ }))
96
+ this._client.on('contact', this.wrapAsync(async ({ contactInfo }:{ friendShip:PUPPET.payloads.FriendshipReceive, contactInfo: ContactPayload, type: PUPPET.types.Friendship }) => {
97
+ await this._cacheMgr!.setContact(contactInfo.wxid, contactInfo)
98
+ await this._cacheMgr?.setFriendshipRawPayload(contactInfo.wxid, {
99
+ id: contactInfo.wxid,
100
+ contactId: contactInfo.wxid,
101
+ timestamp: getUnixTime(Date.now()),
102
+ type: PUPPET.types.Friendship.Confirm,
103
+ })
104
+
105
+ this.emit('friendship', {
106
+ friendshipId: contactInfo.wxid,
107
+ type: PUPPET.types.Friendship.Confirm,
108
+ })
109
+ }))
110
+
111
+ this._client.on('update-contacts', this.wrapAsync(async (contactList: ContactPayload[]) => {
112
+ for (const contact of contactList) {
113
+ await this._onPushContact(contact)
114
+ }
115
+ }))
116
+ this._client.on('room-leave', this.wrapAsync(async ({ roomId, leaveIds }: { roomId: string, leaveIds: string[] }) => {
117
+ const payload = {
118
+ roomId,
119
+ removeeIdList: leaveIds,
120
+ removerId: this._self?.wxid,
121
+ timestamp: getUnixTime(Date.now()),
122
+ }
123
+ for (const leaveId of leaveIds) {
124
+ await this._cacheMgr?.deleteSingleRoomMember(roomId, leaveId)
125
+ const roomInfo = await this._cacheMgr?.getRoom(roomId)
126
+ if (roomInfo && roomInfo.chatroommemberList) {
127
+ roomInfo.chatroommemberList = roomInfo.chatroommemberList.filter(member => member !== leaveId)
128
+ await this._cacheMgr?.setRoom(roomId, roomInfo)
129
+ }
130
+ }
131
+
132
+ this.emit('room-leave', payload)
133
+ }))
134
+ this._client.on('room-join', this.wrapAsync(async ({ roomId, inviterId, joinIds, joinUsers }: { roomId: string, inviterId: string, joinIds: string[], joinUsers: ContactPayload[] }) => {
135
+ const payload = {
136
+ inviteeIdList : joinIds,
137
+ inviterId,
138
+ roomId,
139
+ timestamp : getUnixTime(Date.now()),
140
+ }
141
+ for (const joinUser of joinUsers) {
142
+ await this._cacheMgr?.updateSingleRoomMember(roomId, joinUser)
143
+ const roomInfo = await this._cacheMgr?.getRoom(roomId)
144
+ if (roomInfo && roomInfo.chatroommemberList) {
145
+ roomInfo.chatroommemberList.push(joinUser.wxid)
146
+ await this._cacheMgr?.setRoom(roomId, roomInfo)
147
+ }
148
+ }
149
+ log.info(PRE, 'room-join-----: %s', JSON.stringify(payload))
150
+ this.emit('room-join', payload)
151
+ }))
152
+ this._client.on('logout', this.wrapAsync(async (message: string) => {
153
+ log.info(PRE, 'Logout event: %s', message)
154
+ await this.logout(message)
155
+ }))
156
+ }
157
+ addRunningPuppet(this)
158
+ void this.checkIsLogin()
159
+
160
+ if (this._printVersion) {
161
+ // only print once
162
+ this._printVersion = false
163
+ log.info(`
164
+ ============================================================
165
+ Welcome to Wechaty Matrix puppet!
166
+
167
+ - puppet-Matrix version: ${VERSION}
168
+ ============================================================
169
+ `)
170
+ }
171
+ }
172
+
173
+ private async checkIsLogin () {
174
+ const info = await this._client?.getSelfInfo() as ContactPayload
175
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
176
+ if (info) {
177
+ log.info(PRE, `login success: ${info.name}`)
178
+ await this.onLogin(info)
179
+ } else {
180
+ if (this._qrcodeInterval) {
181
+ clearInterval(this._qrcodeInterval)
182
+ this._qrcodeInterval = null
183
+ }
184
+ await this._getQrcode()
185
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
186
+ this._qrcodeInterval = setInterval(async () => {
187
+ await this._getQrcode()
188
+ }, 200000)
189
+ }
190
+ }
191
+
192
+ private getQrcodeTicket (authurl: string):string {
193
+ if (!authurl || !authurl.startsWith('http')) return ''
194
+ const url = new URL(authurl)
195
+ const searchParams = new URLSearchParams(url.search.slice(1))
196
+ return searchParams.get('ticket') || ''
197
+ }
198
+
199
+ private async _getQrcode () {
200
+ const qrcode = await this._client?.getQrcode()
201
+ if (qrcode) {
202
+ if (this._qrcodeStatuasInterval) {
203
+ clearInterval(this._qrcodeStatuasInterval)
204
+ this._qrcodeStatuasInterval = null
205
+ }
206
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
207
+ this._qrcodeStatuasInterval = setInterval(async () => {
208
+ const scanStatus = await this._client?.getQrcodeStatus() as { status: number, uuid: string, authUrl?: string }
209
+ if (scanStatus.uuid === qrcode.uuid) {
210
+
211
+ if (scanStatus.authUrl) {
212
+ this._qrcodeTicket = this.getQrcodeTicket(scanStatus.authUrl)
213
+
214
+ this.emit('verify-code', scanStatus.uuid, '', 1, 1)
215
+ }
216
+ await this.onQrCodeEvent(scanStatus.status, qrcode.qrcodeUrl)
217
+ }
218
+
219
+ }, 8000)
220
+ }
221
+ }
222
+
223
+ override async enterVerifyCode (id: string, code: string): Promise<void> {
224
+ log.verbose(PRE, 'enterVerifyCode(%s, %s)', id, code)
225
+ if (this._qrcodeTicket) {
226
+ await this._client?.verifyLoginUrl(this._qrcodeTicket, code)
227
+ return
228
+ }
229
+ log.error(PRE, 'enterVerifyCode(%s, %s) error, no qrcodeTicket', id, code)
230
+ }
231
+
232
+ private async onQrCodeEvent (status: number, url: string) {
233
+ const ScanStatusName = {
234
+ [PUPPET.types.ScanStatus.Unknown]: 'Unknown',
235
+ [PUPPET.types.ScanStatus.Cancel]: 'Cancel',
236
+ [PUPPET.types.ScanStatus.Waiting]: 'Waiting',
237
+ [PUPPET.types.ScanStatus.Scanned]: 'Scanned',
238
+ [PUPPET.types.ScanStatus.Confirmed]: 'Confirmed',
239
+ [PUPPET.types.ScanStatus.Timeout]: 'Timeout',
240
+ }
241
+ let scanStatus: PUPPET.types.ScanStatus = PUPPET.types.ScanStatus.Unknown
242
+
243
+ switch (status) {
244
+ case 0:
245
+ scanStatus = PUPPET.types.ScanStatus.Waiting
246
+ break
247
+ case 1:
248
+ scanStatus = PUPPET.types.ScanStatus.Scanned
249
+ break
250
+ case 2:
251
+ scanStatus = PUPPET.types.ScanStatus.Confirmed
252
+ break
253
+ case 3:
254
+ scanStatus = PUPPET.types.ScanStatus.Cancel
255
+ break
256
+ case 4:
257
+ scanStatus = PUPPET.types.ScanStatus.Timeout
258
+ break
259
+ }
260
+ log.silly(
261
+ PRE,
262
+ `scan event, status: ${ScanStatusName[scanStatus]}${url ? ', with qrcode: ' + url : ''}`,
263
+ )
264
+
265
+ this.emit('scan', {
266
+ qrcode: url,
267
+ status: scanStatus,
268
+ })
269
+ // 如果被取消 或者 超时 重新拉取二维码
270
+ if (status === 4 || status === 3) {
271
+ await this.checkIsLogin()
272
+ }
273
+ }
274
+
275
+ // 登录
276
+ private async onLogin (user: ContactPayload):Promise<void> {
277
+ try {
278
+ // create cache manager firstly
279
+ if (!this._client) {
280
+ this._client = await this.options.engine.create(this.options)
281
+ }
282
+ if (!this._cacheMgr) {
283
+ this._cacheMgr = new CacheManager(user.wxid)
284
+ await this._cacheMgr.init()
285
+ await this._cacheMgr!.setContact(user.wxid, user)
286
+ }
287
+ if (this._qrcodeInterval) {
288
+ clearInterval(this._qrcodeInterval)
289
+ this._qrcodeInterval = null
290
+ }
291
+ if (this._qrcodeStatuasInterval) {
292
+ clearInterval(this._qrcodeStatuasInterval)
293
+ this._qrcodeStatuasInterval = null
294
+ }
295
+ this._self = user
296
+
297
+ await super.login(user.wxid)
298
+ void this._client?.pushLoginNotify()
299
+ await this.ready()
300
+ } catch (e) {
301
+ log.error('error login', e)
302
+ }
303
+ }
304
+
305
+ public async ready (): Promise<void> {
306
+ try {
307
+ await this._client?.getContactList(1, 100)
308
+ await delay(2000)
309
+ await this._client?.getGroupList(1, 100)
310
+ await delay(2000)
311
+ await this._client?.getOfficeList(1, 100)
312
+
313
+ log.silly(PRE, 'on ready')
314
+
315
+ setTimeout(() => {
316
+ this.emit('ready', {
317
+ data: 'ready',
318
+ })
319
+ }, 10000)
320
+ } catch (e) {
321
+ log.error('ready error', e)
322
+ }
323
+ }
324
+
325
+ public async onStop (): Promise<void> {
326
+ await this._stopClient()
327
+ }
328
+
329
+ private async _stopClient (): Promise<void> {
330
+ this.__currentUserId = undefined
331
+ this.__currentUserId = undefined
332
+ if (this._cacheMgr) {
333
+ log.info(PRE, 'colse cache')
334
+ await this._cacheMgr.close()
335
+ this._cacheMgr = undefined
336
+ }
337
+ removeRunningPuppet(this)
338
+ this._stopPuppetHeart()
339
+ }
340
+
341
+ // 登出
342
+ override async logout (reason?: string): Promise<void> {
343
+ if (!this.isLoggedIn) {
344
+ return
345
+ }
346
+ await this._client?.logout()
347
+
348
+ await super.logout(reason)
349
+ void this.checkIsLogin()
350
+ }
351
+
352
+ override ding (data?: string): void {
353
+ const eventDongPayload = {
354
+ data: data ? data! : 'ding-dong',
355
+ }
356
+ this.emit('dong', eventDongPayload)
357
+ }
358
+
359
+ /****************************************************************************
360
+ * contact
361
+ ***************************************************************************/
362
+
363
+ /**
364
+ *
365
+ * ContactSelf
366
+ *
367
+ *
368
+ */
369
+ // 设置自己的昵称 暂不支持
370
+ override async contactSelfName (name: string): Promise<void> {
371
+ return PUPPET.throwUnsupportedError(name)
372
+ }
373
+
374
+ // 获取自己的二维码
375
+ override async contactSelfQRCode (): Promise<string> {
376
+ return this._client?.getUserQrcode() || ''
377
+ }
378
+
379
+ // 设置自己的签名 暂不支持
380
+ override async contactSelfSignature (signature: string): Promise<void> {
381
+ return PUPPET.throwUnsupportedError(signature)
382
+ }
383
+
384
+ // 获取用户的手机号 暂不支持
385
+ override async contactPhone (contactId: string, phoneList: string[]): Promise<void> {
386
+ return PUPPET.throwUnsupportedError(contactId, phoneList)
387
+ }
388
+
389
+ // 查询或设置用户备注
390
+ override contactAlias (contactId: string) : Promise<string>
391
+ override contactAlias (contactId: string, alias: string | null): Promise<void>
392
+
393
+ override async contactAlias (contactId : string, alias? : string | null): Promise<string | void> {
394
+ const contact = await this.contactRawPayload(contactId)
395
+ if (alias) {
396
+ // contact is stranger, set alias in cache, to update after user is added
397
+ if (contact) {
398
+ if (contact.wxid.indexOf(STRANGER_SUFFIX) !== -1) {
399
+ await this._cacheMgr!.setContactStrangerAlias(contact.wxid, alias)
400
+
401
+ // to suppress warning: 15:31:06 WARN Contact alias(asd3) sync with server fail: set(asd3) is not equal to get()
402
+ if (contactId.startsWith(SEARCH_CONTACT_PREFIX)) {
403
+ const searchContact = await this._cacheMgr?.getContactSearch(contactId)
404
+ if (searchContact) {
405
+ searchContact.remark = alias
406
+ await this._cacheMgr!.setContactSearch(contactId, searchContact)
407
+ }
408
+ }
409
+ } else {
410
+ await this._client?.setContactAlias(contactId, alias)
411
+ contact.remark = alias
412
+ await this._updateContactCache(contact)
413
+ }
414
+ }
415
+ } else {
416
+ return contact && contact.remark
417
+ }
418
+ }
419
+
420
+ // 获取用户头像
421
+ override async contactAvatar (contactId: string) : Promise<FileBoxInterface>
422
+ override async contactAvatar (contactId: string, file: FileBoxInterface) : Promise<void>
423
+
424
+ override async contactAvatar (contactId: string, file?: FileBoxInterface) : Promise<void | FileBoxInterface> {
425
+ if (file) {
426
+ return PUPPET.throwUnsupportedError('set avatar is not unsupported')
427
+ }
428
+ const contact = await this.contactRawPayload(contactId)
429
+ if (contact && contact.avatar) {
430
+ return FileBox.fromUrl(contact.avatar, { name: `avatar-${contactId}.jpg` })
431
+ }
432
+ }
433
+
434
+ // 获取用户列表
435
+ override async contactList (): Promise<string[]> {
436
+ return this._cacheMgr!.getContactIds()
437
+ }
438
+
439
+ // 公司备注 暂不支持
440
+ override async contactCorporationRemark (contactId: string, corporationRemark: string | null) {
441
+ return PUPPET.throwUnsupportedError(contactId, corporationRemark)
442
+ }
443
+
444
+ // 其他备注 暂不支持
445
+ override async contactDescription (contactId: string, description: string | null) {
446
+ return PUPPET.throwUnsupportedError(contactId, description)
447
+ }
448
+
449
+ // 删除联系人
450
+ override async contactDelete (contactId: string): Promise<void> {
451
+ const contact = await this._refreshContact(contactId)
452
+ if (contact && contact.isFriend === 2) {
453
+ log.warn(`can not delete contact which is not a friend:: ${contactId}`)
454
+ return
455
+ }
456
+ await this._client?.removeContact(contactId)
457
+ await this._refreshContact(contactId, 2)
458
+ }
459
+
460
+ // 添加标签 暂不支持
461
+ override async tagContactTagAdd (tagIds: string[], contactIds: string[]): Promise<void> {
462
+ return PUPPET.throwUnsupportedError(tagIds, contactIds)
463
+ }
464
+
465
+ // 删除用户标签 暂不支持
466
+ override async tagContactTagRemove (tagIds: string[], contactIds: string[]): Promise<void> {
467
+ return PUPPET.throwUnsupportedError(tagIds, contactIds)
468
+ }
469
+
470
+ // 删除标签
471
+ override async tagTagDelete (tagIdList: string[]) : Promise<void> {
472
+ return PUPPET.throwUnsupportedError(tagIdList)
473
+ }
474
+
475
+ // 获取用户标签
476
+ override async tagTagContactList (contactId?: string) : Promise<string[]> {
477
+ return PUPPET.throwUnsupportedError(contactId)
478
+ }
479
+
480
+ /****************************************************************************
481
+ * friendship
482
+ ***************************************************************************/
483
+ /**
484
+ * 通过好友请求
485
+ * @param friendshipId
486
+ */
487
+ override async friendshipAccept (friendshipId : string): Promise<void> {
488
+ const friendship: PUPPET.payloads.FriendshipReceive = (await this.friendshipRawPayload(
489
+ friendshipId,
490
+ )) as PUPPET.payloads.FriendshipReceive
491
+ const userName = friendship.contactId
492
+
493
+ // FIXME: workaround to make accept enterprise account work. can be done in a better way
494
+ if (isIMContactId(userName)) {
495
+ await this._refreshContact(userName)
496
+ }
497
+ await this._client?.confirmFriendship(userName, friendship.scene, friendship.ticket)
498
+ }
499
+
500
+ /**
501
+ * 主动添加好友
502
+ * @param contactId
503
+ * @param option
504
+ */
505
+ override async friendshipAdd (contactId: string, option?: PUPPET.types.FriendshipAddOptions): Promise<void> {
506
+ let stranger: number | undefined
507
+ let ticket: string
508
+ let addContactScene
509
+ const cachedContactSearch = await this._cacheMgr!.getContactSearch(contactId)
510
+ // 通过陌生人查找用户 手机或者qq
511
+ if (cachedContactSearch) {
512
+ stranger = cachedContactSearch.isFriend || undefined
513
+ ticket = cachedContactSearch.ticket || ''
514
+ addContactScene = cachedContactSearch.scene
515
+ } else {
516
+ // 通过wxid 查找
517
+ const contactPayload = await this.contactRawPayload(contactId)
518
+ const contactAlias = contactPayload?.remark
519
+ if (!contactAlias) {
520
+ // add contact from room,
521
+ const roomIds = await this._findRoomIdForWxid(contactId)
522
+ if (!roomIds.length) {
523
+ throw new Error(`Can not find room for contact while adding friendship: ${contactId}`)
524
+ }
525
+ const res = await this._client?.searchContact([ contactId ]) as ContactPayload | undefined
526
+ if (res) {
527
+ await this._updateContactCache(res)
528
+ }
529
+ addContactScene = '14' // 1=qq 3=微信号 6=单向添加 10和13=通讯录 14=群聊 15=手机号 17=名片 30=扫一扫
530
+ }
531
+ const res = await this.contactRawPayload(contactId)
532
+ if (res?.isFriend === 1) {
533
+ throw new Error(`contact:${contactId} is already a friend`)
534
+ }
535
+ // 通过wxid加好友
536
+ ticket = ''
537
+ addContactScene = '6' // 1=qq 3=微信号 6=单向添加 10和13=通讯录 14=群聊 15=手机号 17=名片 30=扫一扫
538
+ }
539
+ let hello: string | undefined
540
+ if (stranger === 1) {
541
+ throw new Error(`contact:${contactId} is already a friend`)
542
+ }
543
+ if (option) {
544
+ if (typeof option === 'string') {
545
+ hello = option
546
+ } else {
547
+ hello = (option as any).hello
548
+ }
549
+ }
550
+ await this._client?.addFriendByWxid({ content: hello, ticket, scene: addContactScene, wxid: contactId })
551
+ }
552
+
553
+ /**
554
+ * 根据手机号查询好友
555
+ * @param phone
556
+ */
557
+ override async friendshipSearchPhone (phone: string): Promise<null | string> {
558
+ return this._friendshipSearch(phone, '15')
559
+ }
560
+
561
+ /**
562
+ * 根据qq号查询好友
563
+ * @param qq
564
+ */
565
+ override async friendshipSearchHandle (qq: string): Promise<null | string> {
566
+ return this._friendshipSearch(qq, '1')
567
+ }
568
+
569
+ /**
570
+ * 陌生人查询
571
+ * @param id
572
+ * @param scene 场景值 1=qq 3=微信号 6=单向添加 10和13=通讯录 14=群聊 15=手机号 17=名片 30=扫一扫
573
+ * @private
574
+ */
575
+ private async _friendshipSearch (id: string, scene?:string): Promise<null | string> {
576
+ const cachedContactSearch = await this._cacheMgr!.getContactSearch(id)
577
+ if (cachedContactSearch) {
578
+ return id
579
+ }
580
+
581
+ const res = await this._client?.searchStranger(id)
582
+ const searchId = `${SEARCH_CONTACT_PREFIX}${id}`
583
+ if (res) {
584
+ await this._cacheMgr!.setContactSearch(searchId, { ...res, scene })
585
+ }
586
+ return searchId
587
+ }
588
+
589
+ /**
590
+ * 根据wxid 查询群id
591
+ * @param wxid
592
+ * @private
593
+ */
594
+ private async _findRoomIdForWxid (wxid: string): Promise<string[]> {
595
+ const ret = []
596
+
597
+ const roomIds = (await this._cacheMgr?.getRoomIds()) || []
598
+ for (const roomId of roomIds) {
599
+ const roomMember = await this._cacheMgr?.getRoomMember(roomId)
600
+ if (!roomMember) {
601
+ continue
602
+ }
603
+
604
+ const roomMemberIds = Object.keys(roomMember)
605
+ if (roomMemberIds.indexOf(wxid) !== -1) {
606
+ ret.push(roomId)
607
+ }
608
+ }
609
+
610
+ return ret
611
+ }
612
+
613
+ /****************************************************************************
614
+ * get message payload
615
+ ***************************************************************************/
616
+ // 名片
617
+ override async messageContact (messageId: string): Promise<string> {
618
+ log.verbose('PuppetWeChat', 'messageContact(%s)', messageId)
619
+ return PUPPET.throwUnsupportedError(messageId)
620
+ }
621
+
622
+ // 文件消息
623
+ override async messageFile (messageId: string): Promise<FileBoxInterface> {
624
+ const messagePayload: MessagePayload = await this.messageRawPayload(messageId)
625
+ const message: PUPPET.payloads.Message = await this.messageRawPayloadParser(messagePayload)
626
+ switch (message.type) {
627
+ // 图片
628
+ case PUPPET.types.Message.Image:
629
+ return this._getMessageImageFileBox(messageId, messagePayload)
630
+ case PUPPET.types.Message.Audio:
631
+ return this._getMessageAudioFileBox(messageId, messagePayload)
632
+ case PUPPET.types.Message.Video: {
633
+ return this._getMessageVideoFileBox(messageId, messagePayload)
634
+ }
635
+ case PUPPET.types.Message.Attachment:
636
+ return this._getMessageFileFileBox(messageId, messagePayload)
637
+ case PUPPET.types.Message.Emoticon: {
638
+ const emotionPayload = await parseEmotionMessagePayload(messagePayload)
639
+ const emoticonBox = FileBox.fromUrl(emotionPayload.cdnurl, { name: `message-${messageId}-emoticon.jpg` })
640
+
641
+ emoticonBox.metadata = {
642
+ payload: emotionPayload,
643
+ type: 'emoticon',
644
+ }
645
+
646
+ return emoticonBox
647
+ }
648
+ case PUPPET.types.Message.MiniProgram:
649
+ return PUPPET.throwUnsupportedError(messageId)
650
+ case PUPPET.types.Message.Url:
651
+ return PUPPET.throwUnsupportedError(messageId)
652
+ default:
653
+ throw new Error(`Can not get file for message: ${messageId}`)
654
+ }
655
+ }
656
+
657
+ /**
658
+ * 解析图片消息
659
+ * @param messageId
660
+ */
661
+ override async messageImage (messageId: string): Promise<FileBoxInterface> {
662
+ const messagePayload: MessagePayload = await this.messageRawPayload(messageId)
663
+ return this._getMessageImageFileBox(messageId, messagePayload)
664
+ }
665
+
666
+ /**
667
+ * 解析小程序
668
+ * @param messageId
669
+ */
670
+ override async messageMiniProgram (messageId: string): Promise<PUPPET.payloads.MiniProgram> {
671
+ const messagePayload = await this.messageRawPayload(messageId)
672
+ const message = await this.messageRawPayloadParser(messagePayload)
673
+
674
+ if (message.type !== PUPPET.types.Message.MiniProgram) {
675
+ throw new Error('message is not mini program, can not get MiniProgramPayload')
676
+ }
677
+
678
+ return parseMiniProgramMessagePayload(messagePayload)
679
+ }
680
+
681
+ /**
682
+ * 解析h5链接
683
+ * @param messageId
684
+ */
685
+ override async messageUrl (messageId: string) : Promise<PUPPET.payloads.UrlLink> {
686
+ const rawPayload = await this.messageRawPayload(messageId)
687
+ const payload = await this.messageRawPayloadParser(rawPayload)
688
+
689
+ if (payload.type !== PUPPET.types.Message.Url) {
690
+ throw new Error('Can not get url from non url payload')
691
+ }
692
+
693
+ // FIXME: thumb may not in appPayload.thumburl, but in appPayload.appAttachPayload
694
+ const appPayload = await parseAppmsgMessagePayload(rawPayload.msg)
695
+ return {
696
+ description: appPayload.des,
697
+ thumbnailUrl: appPayload.thumburl,
698
+ title: appPayload.title,
699
+ url: appPayload.url,
700
+ }
701
+ }
702
+
703
+ /****************************************************************************
704
+ * send message
705
+ ***************************************************************************/
706
+ // 发送名片
707
+ override async messageSendContact (toUserId: string, contactId: string): Promise<void | string> {
708
+ log.verbose('PuppetWeChat', 'messageSend("%s", %s)', toUserId, contactId)
709
+ const contactPayload = await this.contactRawPayload(contactId)
710
+ const xmlObj = {
711
+ msg: {
712
+ antispamticket: '', // TODO 需要考虑怎么设置
713
+ bigheadimgurl: contactPayload?.avatar,
714
+ brandFlags: '0',
715
+ certflag: '0',
716
+ city: contactPayload?.city,
717
+ fullpy: contactPayload?.name,
718
+ imagestatus: '3',
719
+ nickname: contactPayload?.name,
720
+ province: contactPayload?.province,
721
+ regionCode: 'CN_Shanghai',
722
+ scene: '17',
723
+ sex: contactPayload?.sex,
724
+ smallheadimgurl: contactPayload?.avatar,
725
+ username: contactPayload?.ticket,
726
+ },
727
+ }
728
+ const xml = JsonToXml(xmlObj)
729
+ const res = await this._client?.sendContactCard(toUserId, xml, this._self?.wxid)
730
+ if (res) {
731
+ await this._cacheMgr?.setMessage(res.id, res)
732
+ return res.id
733
+ }
734
+ }
735
+
736
+ // 发送文件
737
+ override async messageSendFile (conversationId: string, fileBox: FileBoxInterface): Promise<string | void> {
738
+ const metadata: FileBoxMetadataMessage = fileBox.metadata as FileBoxMetadataMessage
739
+
740
+ const fileType
741
+ = fileBox.mediaType && fileBox.mediaType !== 'application/octet-stream'
742
+ ? fileBox.mediaType
743
+ : path.extname(fileBox.name)
744
+
745
+ // @ts-ignore
746
+ const fileUrl = fileBox.remoteUrl || ''
747
+ if (metadata.type === 'emoticon') {
748
+ PUPPET.throwUnsupportedError(conversationId, fileBox)
749
+ } else if (fileBox.mediaType.startsWith('image/')) {
750
+ if (fileUrl) {
751
+ const msgInfo = await this._client?.sendUrlImg(conversationId, fileUrl, this._self?.wxid)
752
+
753
+ if (msgInfo) {
754
+ await this._cacheMgr?.setMessage(msgInfo.id, msgInfo)
755
+ return msgInfo.id
756
+ }
757
+
758
+ }
759
+ } else if (fileBox.mediaType === 'audio/silk') {
760
+ PUPPET.throwUnsupportedError(conversationId, fileBox)
761
+ } else if (fileType.includes('video/mp4') || fileType.includes('.mp4')) {
762
+ const msgInfo = await this._client?.sendVideo(conversationId, fileUrl, this._self?.wxid)
763
+ if (msgInfo) {
764
+ await this._cacheMgr?.setMessage(msgInfo.id, msgInfo)
765
+ return msgInfo.id
766
+ }
767
+ } else {
768
+ if (fileUrl) {
769
+ const msgInfo = await this._client?.sendCloudFile(conversationId, fileUrl, this._self?.wxid)
770
+ if (msgInfo) {
771
+ await this._cacheMgr?.setMessage(msgInfo.id, msgInfo)
772
+ return msgInfo.id
773
+ }
774
+ }
775
+ }
776
+ }
777
+
778
+ // 发送小程序
779
+ override async messageSendMiniProgram (toUserName: string, mpPayload: PUPPET.payloads.MiniProgram): Promise<void | string> {
780
+ const miniProgram = {
781
+ appid: mpPayload.appid,
782
+ contactId: toUserName,
783
+ content: mpPayload.description,
784
+ username: mpPayload.username,
785
+ pagePath: mpPayload.pagePath,
786
+ thumbUrl: mpPayload.thumbUrl,
787
+ iconUrl: mpPayload.iconUrl,
788
+ title: mpPayload.title,
789
+ }
790
+
791
+ if (!mpPayload.thumbUrl) {
792
+ log.warn(PRE, 'no thumb image found while sending mimi program')
793
+ }
794
+
795
+ const res = await this._client?.sendMiniProgram(miniProgram, this._self?.wxid)
796
+ if (res) {
797
+ await this._cacheMgr?.setMessage(res.id, res)
798
+ return res.id
799
+ }
800
+ }
801
+
802
+ // 发送文字
803
+ override async messageSendText (conversationId: string, text: string, mentionIdList?: string[]): Promise<string | void> {
804
+ if (mentionIdList && mentionIdList.length) {
805
+ const msgInfo = await this._client?.sendAtText(conversationId, text, mentionIdList, this._self?.wxid)
806
+ if (msgInfo) {
807
+ await this._cacheMgr?.setMessage(msgInfo.id, msgInfo)
808
+ return msgInfo.id
809
+ }
810
+ }
811
+
812
+ const msgInfo = await this._client?.sendText(conversationId, text, this._self?.wxid)
813
+
814
+ if (msgInfo) {
815
+ await this._cacheMgr?.setMessage(msgInfo.id, msgInfo)
816
+ return msgInfo.id
817
+ }
818
+ }
819
+
820
+ // 发送h5链接
821
+ override async messageSendUrl (conversationId: string, urlLinkPayload: PUPPET.payloads.UrlLink): Promise<string | void> {
822
+ const urlCard = {
823
+ contactId: conversationId,
824
+ content: urlLinkPayload.description,
825
+ jumpUrl: urlLinkPayload.url,
826
+ imageUrl: urlLinkPayload.thumbnailUrl,
827
+ title: urlLinkPayload.title,
828
+ }
829
+ if (!urlLinkPayload.thumbnailUrl) {
830
+ log.warn(PRE, 'no thumb image found while sending mimi program')
831
+ }
832
+ const msgInfo = await this._client?.sendShareCard(urlCard, this._self?.wxid)
833
+
834
+ if (msgInfo) {
835
+ await this._cacheMgr?.setMessage(msgInfo.id, msgInfo)
836
+ return msgInfo.id
837
+ }
838
+ }
839
+
840
+ /**
841
+ * 确认收款
842
+ */
843
+ override async messageSendPost (conversationId: string, postPayload: PUPPET.payloads.Post): Promise<void> {
844
+ const msgType = postPayload.sayableList[0] as PUPPET.payloads.Sayable
845
+ if (msgType.type !== 'Text') {
846
+ throw new Error(`Wrong Post!!! please check your Post payload to make sure it right ${conversationId}`)
847
+ }
848
+ }
849
+
850
+ /**
851
+ * 消息撤回 暂不支持
852
+ * @param messageId
853
+ */
854
+ override async messageRecall (messageId: string): Promise<boolean> {
855
+ return PUPPET.throwUnsupportedError(messageId)
856
+ }
857
+
858
+ /**
859
+ * 消息转发
860
+ * @param toUserName
861
+ * @param messageId
862
+ */
863
+ override async messageForward (toUserName: string, messageId: string): Promise<void> {
864
+ const messagePayload = await this.messageRawPayload(messageId)
865
+ const message = await this.messageRawPayloadParser(messagePayload)
866
+
867
+ switch (message.type) {
868
+ case PUPPET.types.Message.Text:
869
+ await this.messageSendText(toUserName, message.text!)
870
+ break
871
+
872
+ case PUPPET.types.Message.Image: {
873
+ const imageFileBox = await this.messageImage(messageId)
874
+ await this.messageSendFile(toUserName, imageFileBox)
875
+ break
876
+ }
877
+ case PUPPET.types.Message.Audio: {
878
+ const audioFileBox = await this.messageFile(messageId)
879
+ await this.messageSendFile(toUserName, audioFileBox)
880
+ break
881
+ }
882
+ case PUPPET.types.Message.Video: {
883
+ const videoFileBox = await this.messageFile(messageId)
884
+ await this.messageSendFile(toUserName, videoFileBox)
885
+ break
886
+ }
887
+ default:
888
+ throw new Error(`Message forwarding is unsupported for messageId:${messageId}, type:${message.type}`)
889
+ }
890
+ }
891
+
892
+ /****************************************************************************
893
+ * room
894
+ ***************************************************************************/
895
+
896
+ // 拉人进群
897
+ override async roomAdd (roomId : string, contactId : string): Promise<void> {
898
+ let type:number = 1 // 1 直接拉 2 发送邀请链接 人数超过40需要对方同意
899
+ if (roomId) {
900
+ const ret = await this.roomRawPayload(roomId)
901
+ if (ret && ret.memberNum && ret.memberNum > 38) {
902
+ type = 2
903
+ }
904
+ }
905
+ await this._client?.inviteToGroup(roomId, contactId, type)
906
+ }
907
+
908
+ // 获取群头像
909
+ override async roomAvatar (roomId: string): Promise<FileBoxInterface> {
910
+ const chatroom = await this.roomRawPayload(roomId)
911
+ if (chatroom && chatroom.avatar) {
912
+ return FileBox.fromUrl(chatroom.avatar)
913
+ } else {
914
+ // return dummy FileBox object
915
+ return FileBox.fromBuffer(Buffer.from(new ArrayBuffer(0)), 'room-avatar.jpg')
916
+ }
917
+ }
918
+
919
+ // 创建群聊 暂不支持
920
+ override async roomCreate (
921
+ contactIdList : string[],
922
+ topic : string,
923
+ ): Promise<string> {
924
+ return PUPPET.throwUnsupportedError(contactIdList, topic)
925
+ }
926
+
927
+ // 删除群聊 暂不支持
928
+ override async roomDel (
929
+ roomId : string,
930
+ contactId : string,
931
+ ): Promise<void> {
932
+ return PUPPET.throwUnsupportedError(roomId, contactId)
933
+ }
934
+
935
+ // 获取群聊列表
936
+ override async roomList (): Promise<string[]> {
937
+ return this._cacheMgr!.getRoomIds()
938
+ }
939
+
940
+ // 获取群二维码 暂不支持
941
+ override async roomQRCode (roomId: string): Promise<string> {
942
+ return PUPPET.throwUnsupportedError(roomId)
943
+ }
944
+
945
+ // 机器人退出群聊 暂不支持
946
+ override async roomQuit (roomId: string): Promise<void> {
947
+ return this._client?.roomQuit(roomId)
948
+ }
949
+
950
+ override async roomTopic (roomId: string) : Promise<string>
951
+ override async roomTopic (roomId: string, topic: string) : Promise<void>
952
+
953
+ // 修改群名称
954
+ override async roomTopic (
955
+ roomId : string,
956
+ topic? : string,
957
+ ): Promise<void | string> {
958
+ await this._client?.setGroupName(roomId, topic)
959
+ }
960
+
961
+ override async roomAnnounce (roomId: string) : Promise<string>
962
+ override async roomAnnounce (roomId: string, text: string) : Promise<void>
963
+
964
+ // 修改群公告
965
+ override async roomAnnounce (roomId: string, text?: string) : Promise<void | string> {
966
+ if (text !== undefined) {
967
+ await this._client?.sendAnnouncement(roomId, text)
968
+ }
969
+ return ''
970
+ }
971
+
972
+ // 获取群成员列表
973
+ override async roomMemberList (roomId: string) : Promise<string[]> {
974
+ const roomMemberMap = await this._getRoomMemberList(roomId)
975
+ return Object.values(roomMemberMap).map((m) => m.wxid)
976
+ }
977
+
978
+ // 接受群邀请 暂不支持
979
+ override async roomInvitationAccept (roomInvitationId: string): Promise<void> {
980
+ return PUPPET.throwUnsupportedError(roomInvitationId)
981
+ }
982
+
983
+ /****************************************************************************
984
+ * RawPayload section
985
+ ***************************************************************************/
986
+
987
+ // 解析联系人信息格式化为Wechaty 格式
988
+ override async contactRawPayloadParser (payload: ContactPayload): Promise<PUPPET.payloads.Contact> {
989
+ return engineContactToWechaty(payload)
990
+ }
991
+
992
+ // 获取联系人信息 原格式
993
+ override async contactRawPayload (id: string): Promise<ContactPayload | undefined> {
994
+ log.silly(PRE, 'contactRawPayload(%s) @ %s', id, this)
995
+ if (id.startsWith(SEARCH_CONTACT_PREFIX)) {
996
+ const searchContact = await this._cacheMgr?.getContactSearch(id)
997
+ return searchContact
998
+ }
999
+
1000
+ let ret = await this._cacheMgr!.getContact(id)
1001
+ if (!ret) {
1002
+ ret = await CachedPromiseFunc(`contactRawPayload-${id}`, async () => {
1003
+ const contact = await this._refreshContact(id)
1004
+ return contact
1005
+ })
1006
+ return ret
1007
+ }
1008
+ return ret
1009
+ }
1010
+
1011
+ /**
1012
+ * 解析原始消息体为Wechaty支持的格式
1013
+ * @param payload
1014
+ */
1015
+ override async messageRawPayloadParser (payload: MessagePayload): Promise<PUPPET.payloads.Message> {
1016
+ return engineMessageToWechaty(this, payload)
1017
+ }
1018
+
1019
+ /**
1020
+ * 根据消息id 获取消息
1021
+ * @param id
1022
+ */
1023
+ override async messageRawPayload (id: string): Promise<MessagePayload> {
1024
+ const ret = await this._cacheMgr!.getMessage(id)
1025
+ if (!ret) {
1026
+ throw new Error(`can not find message in cache for messageId: ${id}`)
1027
+ }
1028
+
1029
+ return ret
1030
+ }
1031
+
1032
+ /**
1033
+ * 群数据格式化为Wechaty 支持类型
1034
+ * @param rawPayload
1035
+ */
1036
+ override async roomRawPayloadParser (payload: ContactPayload): Promise<PUPPET.payloads.Room> {
1037
+ return engineRoomToWechaty(payload)
1038
+ }
1039
+
1040
+ /**
1041
+ * 查找群基础信息
1042
+ * @param id
1043
+ */
1044
+ override async roomRawPayload (id: string): Promise<ContactPayload|undefined> {
1045
+ let ret = await this._cacheMgr!.getRoom(id)
1046
+ if (!ret) {
1047
+ const contact = await this._refreshContact(id)
1048
+ ret = contact
1049
+ }
1050
+ return ret
1051
+ }
1052
+
1053
+ /**
1054
+ * 查找群成员信息
1055
+ * @param roomId
1056
+ * @param contactId
1057
+ */
1058
+ override async roomMemberRawPayload (roomId: string, contactId: string): Promise<ContactPayload> {
1059
+ const roomMemberMap = await this._getRoomMemberList(roomId)
1060
+ if (roomMemberMap[contactId]) {
1061
+ return roomMemberMap[contactId]!
1062
+ }
1063
+ const newMap = await this._getRoomMemberList(roomId, true)
1064
+
1065
+ return newMap[contactId]!
1066
+ }
1067
+
1068
+ /**
1069
+ * 解析群成员信息
1070
+ * @param rawPayload
1071
+ */
1072
+ override async roomMemberRawPayloadParser (rawPayload: ContactPayload): Promise<PUPPET.payloads.RoomMember> {
1073
+ return engineRoomMemberToWechaty(rawPayload)
1074
+ }
1075
+
1076
+ /**
1077
+ * 接收群邀请信息 暂不支持
1078
+ * @param roomInvitationId
1079
+ */
1080
+ override async roomInvitationRawPayload (roomInvitationId: string): Promise<any> {
1081
+ return PUPPET.throwUnsupportedError(roomInvitationId)
1082
+ }
1083
+
1084
+ /**
1085
+ * 解析群邀请信息 暂不支持
1086
+ * @param rawPayload
1087
+ */
1088
+ override async roomInvitationRawPayloadParser (rawPayload: any): Promise<PUPPET.payloads.RoomInvitation> {
1089
+ return PUPPET.throwUnsupportedError(rawPayload)
1090
+ }
1091
+
1092
+ /**
1093
+ * 好友申请信息解析
1094
+ * @param rawPayload
1095
+ */
1096
+ override async friendshipRawPayloadParser (rawPayload: PUPPET.payloads.Friendship): Promise<PUPPET.payloads.Friendship> {
1097
+ return rawPayload
1098
+ }
1099
+
1100
+ /**
1101
+ * 获取好友申请信息
1102
+ * @param id
1103
+ */
1104
+ override async friendshipRawPayload (id: string): Promise<PUPPET.payloads.Friendship> {
1105
+ const ret = await this._cacheMgr!.getFriendshipRawPayload(id)
1106
+
1107
+ if (!ret) {
1108
+ throw new Error(`Can not find friendship for id: ${id}`)
1109
+ }
1110
+
1111
+ return ret
1112
+ }
1113
+ /****************************************************************************
1114
+ * extra methods section
1115
+ ***************************************************************************/
1116
+
1117
+ async syncRoom () {
1118
+ if (this.state.active() !== true) {
1119
+ throw new Error('Can not sync contact before login')
1120
+ }
1121
+ await this._client?.getGroupList(1, 100)
1122
+ }
1123
+ /****************************************************************************
1124
+ * private section
1125
+ ***************************************************************************/
1126
+
1127
+ // 获取群成员列表
1128
+ private async _getRoomMemberList (roomId: string, force?: boolean): Promise<RoomMemberMap> {
1129
+ // FIX: https://github.com/wechaty/puppet-padlocal/issues/115
1130
+ if (!this._cacheMgr) {
1131
+ return {}
1132
+ }
1133
+
1134
+ let ret = await this._cacheMgr!.getRoomMember(roomId)
1135
+
1136
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1137
+ if (!ret || (ret && !Object.keys(ret).length) || force) {
1138
+ const resMembers = await this._client?.getGroupMembers(roomId) || []
1139
+
1140
+ const roomMemberMap: RoomMemberMap = {}
1141
+ for (const roomMember of resMembers) {
1142
+ const hasContact = await this._cacheMgr!.hasContact(roomMember.wxid)
1143
+ let MemberInfo: ContactPayload
1144
+ // save chat room member as contact, to forbid massive this._client.api.getContact(id) requests while room.ready()
1145
+ if (!hasContact) {
1146
+ MemberInfo = chatRoomMemberToContact(roomMember)
1147
+ await this._cacheMgr!.setContact(MemberInfo.wxid, MemberInfo)
1148
+ roomMemberMap[roomMember.wxid] = MemberInfo
1149
+ } else {
1150
+ MemberInfo = await this._cacheMgr!.getContact(roomMember.wxid) as ContactPayload
1151
+ roomMemberMap[roomMember.wxid] = MemberInfo
1152
+ }
1153
+ }
1154
+ ret = roomMemberMap
1155
+ await this._updateRoomMember(roomId, roomMemberMap)
1156
+ }
1157
+
1158
+ return ret
1159
+ }
1160
+
1161
+ // 更新联系人缓存
1162
+ private async _updateContactCache (contact: ContactPayload): Promise<void> {
1163
+ if (!contact.wxid) {
1164
+ log.warn(PRE, `wxid is required for contact: ${JSON.stringify(contact)}`)
1165
+ return
1166
+ }
1167
+
1168
+ if (isRoomId(contact.wxid)) {
1169
+ const oldRoomPayload = await this._cacheMgr!.getRoom(contact.wxid)
1170
+
1171
+ const roomId = contact.wxid
1172
+ let finalPayload: ContactPayload = contact
1173
+ if (oldRoomPayload) {
1174
+ finalPayload = Object.assign(oldRoomPayload, contact)
1175
+ }
1176
+ await this._cacheMgr!.setRoom(roomId, finalPayload)
1177
+
1178
+ if (!finalPayload.chatroommemberList || finalPayload.chatroommemberList.length === 0) {
1179
+ const map = await this._getRoomMemberList(roomId)
1180
+ await this._cacheMgr!.setRoom(roomId, Object.assign(finalPayload, { chatroommemberList: Object.keys(map) }))
1181
+ }
1182
+
1183
+ } else {
1184
+ const oldContactPaylod = await this._cacheMgr!.getContact(contact.wxid)
1185
+ if (oldContactPaylod) {
1186
+ await this._cacheMgr!.setContact(contact.wxid, Object.assign(oldContactPaylod, contact))
1187
+ } else {
1188
+ await this._cacheMgr!.setContact(contact.wxid, contact)
1189
+ }
1190
+ }
1191
+ }
1192
+
1193
+ // 更新群成员
1194
+ private async _updateRoomMember (roomId: string, roomMemberMap?: RoomMemberMap) {
1195
+ if (roomMemberMap) {
1196
+ await this._cacheMgr!.setRoomMember(roomId, roomMemberMap)
1197
+ } else {
1198
+ await this._cacheMgr!.deleteRoomMember(roomId)
1199
+ }
1200
+ }
1201
+
1202
+ /** this.emit('login', { contactId: userId })
1203
+ * 更新群成员信息
1204
+ * @param roomId
1205
+ */
1206
+ public async _updateRoom (roomId:string) {
1207
+ if (!roomId) {
1208
+ log.warn(PRE, 'roomid is required for updateRoom')
1209
+ return
1210
+ }
1211
+ let contact: ContactPayload | undefined = await this._client?.searchContact([ roomId ]) as ContactPayload | undefined
1212
+
1213
+ if (contact) {
1214
+ const memeberMap: RoomMemberMap = await this._getRoomMemberList(contact.wxid, true)
1215
+ const chatroommemberList = Object.values(memeberMap).map(item => item.wxid)
1216
+ contact = { ...contact, memberNum: Object.keys(memeberMap).length, chatroommemberList }
1217
+ await this._onPushContact(contact)
1218
+ }
1219
+ }
1220
+
1221
+ // 添加好友信息到缓存
1222
+ private async _onPushContact (contact: ContactPayload): Promise<void> {
1223
+ log.silly(PRE, `on push contact: ${JSON.stringify(contact)}`)
1224
+
1225
+ await this._updateContactCache(contact)
1226
+
1227
+ if (contact.wxid) {
1228
+ const aliasToSet = await this._cacheMgr!.getContactStrangerAlias(contact.wxid)
1229
+ if (aliasToSet) {
1230
+ await this.contactAlias(contact.wxid, aliasToSet)
1231
+ await this._cacheMgr!.deleteContactStrangerAlias(contact.wxid)
1232
+ }
1233
+ }
1234
+ }
1235
+
1236
+ private async _onPushMessage (message: MessagePayload): Promise<void> {
1237
+ const messageId = message.id
1238
+ log.silly(PRE, `on push original message: ${JSON.stringify(message)}`)
1239
+ if (await this._cacheMgr!.hasMessage(messageId)) {
1240
+ return
1241
+ }
1242
+ await this._cacheMgr!.setMessage(message.id, message)
1243
+ const event = await parseEvent(this, message)
1244
+ log.info('event-------', JSON.stringify(event))
1245
+ switch (event.type) {
1246
+ case EventType.Message:
1247
+ this.emit('message', {
1248
+ messageId,
1249
+ })
1250
+ break
1251
+ case EventType.Friendship: {
1252
+ await this._cacheMgr?.setFriendshipRawPayload(event.payload.contactId, event.payload)
1253
+
1254
+ this.emit('friendship', {
1255
+ friendshipId: event.payload.contactId,
1256
+ type: event.payload.type,
1257
+ })
1258
+ break
1259
+ }
1260
+ case EventType.RoomInvite: {
1261
+ const roomInvite: PUPPET.payloads.RoomInvitation = event.payload
1262
+ await this._cacheMgr!.setRoomInvitation(messageId, roomInvite)
1263
+
1264
+ this.emit('room-invite', {
1265
+ roomInvitationId: messageId,
1266
+ })
1267
+ break
1268
+ }
1269
+ case EventType.RoomJoin: {
1270
+ // const roomJoin: PUPPET.payloads.EventRoomJoin = event.payload
1271
+ // await this._updateRoomMember(roomJoin.roomId)
1272
+ // this.emit('room-join', roomJoin)
1273
+ break
1274
+ }
1275
+ case EventType.RoomLeave: {
1276
+ // const roomLeave: PUPPET.payloads.EventRoomLeave = event.payload
1277
+ // this.emit('room-leave', roomLeave)
1278
+
1279
+ // await this._updateRoomMember(roomLeave.roomId)
1280
+ break
1281
+ }
1282
+ case EventType.RoomTopic: {
1283
+ // const roomTopic: PUPPET.payloads.EventRoomTopic = event.payload
1284
+ // this.emit('room-topic', roomTopic)
1285
+ break
1286
+ }
1287
+ }
1288
+ }
1289
+
1290
+ // 刷新用户信息
1291
+ private async _refreshContact (wxid: string, isFriend?: number): Promise<ContactPayload | undefined> {
1292
+ const contact = await this._client?.searchContactDetail([ wxid ]) as ContactPayload | undefined
1293
+ // may return contact with empty payload, empty username, nickname, etc.
1294
+ if (contact && !contact.wxid) {
1295
+ contact.wxid = wxid
1296
+ await this._updateContactCache({ ...contact, isFriend })
1297
+ return contact
1298
+ } else if (contact) {
1299
+ return contact
1300
+ }
1301
+ return undefined
1302
+ }
1303
+
1304
+ // 开始监听心跳
1305
+ private async _startPuppetHeart (firstTime: boolean = true) {
1306
+ if (firstTime && this._heartBeatTimer) {
1307
+ return
1308
+ }
1309
+ this.emit('heartbeat', { data: 'heartbeat@matrix' })
1310
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
1311
+ this._heartBeatTimer = setTimeout(async (): Promise<void> => {
1312
+ await this._startPuppetHeart(false)
1313
+ return undefined
1314
+ }, 15 * 1000) // 15s
1315
+ }
1316
+
1317
+ // 停止监听心跳
1318
+ private _stopPuppetHeart () {
1319
+ if (!this._heartBeatTimer) {
1320
+ return
1321
+ }
1322
+
1323
+ clearTimeout(this._heartBeatTimer)
1324
+ this._heartBeatTimer = undefined
1325
+ }
1326
+
1327
+ /**
1328
+ * 解析图片
1329
+ * @param messageId
1330
+ * @param messagePayload
1331
+ * @private
1332
+ */
1333
+ private async _getMessageImageFileBox (messageId: string, messagePayload: MessagePayload):Promise<FileBoxInterface> {
1334
+ const imageInfo: ImageMessagePayload = await parseImageMessagePayload(messagePayload)
1335
+ if (!imageInfo.file_id) {
1336
+ log.error(`Can not get file for message: ${messageId}`)
1337
+ }
1338
+ const url = await this._client?.downloadImage(imageInfo)
1339
+ return FileBox.fromUrl(url)
1340
+ }
1341
+
1342
+ private async _getMessageAudioFileBox (messageId: string, messagePayload: MessagePayload):Promise<FileBoxInterface> {
1343
+ const audioInfo: AudioMessagePayload = await parseAudioMessagePayload(messagePayload)
1344
+ if (!audioInfo.length) {
1345
+ log.error(`Can not get file for message: ${messageId}`)
1346
+ }
1347
+ const url = await this._client?.downloadAudio(messageId, audioInfo)
1348
+ return FileBox.fromUrl(url)
1349
+ }
1350
+
1351
+ private async _getMessageVideoFileBox (messageId: string, messagePayload: MessagePayload):Promise<FileBoxInterface> {
1352
+ const videoInfo: VideoMessagePayload = await parseVideoMessagePayload(messagePayload)
1353
+ if (!videoInfo.file_id) {
1354
+ log.error(`Can not get file for message: ${messageId}`)
1355
+ }
1356
+ const url = await this._client?.downloadVideo(videoInfo)
1357
+ log.info(PRE, '_getMessageVideoFileBox(): %s', url)
1358
+ return FileBox.fromUrl(url)
1359
+ }
1360
+
1361
+ /**
1362
+ * 解析文件
1363
+ * @param messageId
1364
+ * @param messagePayload
1365
+ * @private
1366
+ */
1367
+ private async _getMessageFileFileBox (messageId: string, messagePayload: MessagePayload):Promise<FileBoxInterface> {
1368
+ const appPayload: AppMessagePayload = await parseAppmsgMessagePayload(messagePayload.msg)
1369
+ if (!appPayload.appattach?.attachid) {
1370
+ log.error(`Can not get file for message: ${messageId}`)
1371
+ }
1372
+ const appattach = appPayload.appattach
1373
+ const params = {
1374
+ aes_key: appattach?.aeskey || '',
1375
+ file_id: appattach?.attachid || '',
1376
+ file_name: appPayload.title,
1377
+ file_size: appattach?.totallen || '',
1378
+ }
1379
+
1380
+ const url = await this._client?.downloadFile(params)
1381
+
1382
+ if (!url) {
1383
+ log.error(`Can not get file url: ${JSON.stringify(params)}`)
1384
+ }
1385
+
1386
+ return FileBox.fromUrl(url, { name: appPayload.title })
1387
+ }
1388
+
1389
+ // @ts-ignore
1390
+ public async syncContact () {
1391
+ if (!this.currentUserId) {
1392
+ throw new Error('Can not sync contact before login')
1393
+ }
1394
+ log.info('syncContact')
1395
+ await this._client!.syncContact()
1396
+ }
1397
+
1398
+ }
1399
+
1400
+ export { PuppetMatrix, VERSION }
1401
+
1402
+ export default PuppetMatrix