@ardennguyen/zalo-agent-cli 1.0.7 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1275) hide show
  1. package/DISCLAIMER.md +2 -2
  2. package/LICENSE +456 -21
  3. package/NOTICE +127 -0
  4. package/README.md +169 -70
  5. package/node_modules/asynckit/LICENSE +21 -0
  6. package/node_modules/asynckit/README.md +233 -0
  7. package/node_modules/asynckit/bench.js +76 -0
  8. package/node_modules/asynckit/index.js +6 -0
  9. package/node_modules/asynckit/lib/abort.js +29 -0
  10. package/node_modules/asynckit/lib/async.js +34 -0
  11. package/node_modules/asynckit/lib/defer.js +26 -0
  12. package/node_modules/asynckit/lib/iterate.js +75 -0
  13. package/node_modules/asynckit/lib/readable_asynckit.js +91 -0
  14. package/node_modules/asynckit/lib/readable_parallel.js +25 -0
  15. package/node_modules/asynckit/lib/readable_serial.js +25 -0
  16. package/node_modules/asynckit/lib/readable_serial_ordered.js +29 -0
  17. package/node_modules/asynckit/lib/state.js +37 -0
  18. package/node_modules/asynckit/lib/streamify.js +141 -0
  19. package/node_modules/asynckit/lib/terminator.js +29 -0
  20. package/node_modules/asynckit/package.json +63 -0
  21. package/node_modules/asynckit/parallel.js +43 -0
  22. package/node_modules/asynckit/serial.js +17 -0
  23. package/node_modules/asynckit/serialOrdered.js +75 -0
  24. package/node_modules/asynckit/stream.js +21 -0
  25. package/node_modules/bignumber.js/CHANGELOG.md +381 -0
  26. package/node_modules/bignumber.js/LICENCE.md +26 -0
  27. package/node_modules/bignumber.js/README.md +289 -0
  28. package/node_modules/bignumber.js/bignumber.d.mts +6 -0
  29. package/node_modules/bignumber.js/bignumber.d.ts +5 -0
  30. package/node_modules/bignumber.js/bignumber.js +2922 -0
  31. package/node_modules/bignumber.js/bignumber.mjs +2907 -0
  32. package/node_modules/bignumber.js/doc/API.html +2249 -0
  33. package/node_modules/bignumber.js/package.json +60 -0
  34. package/node_modules/bignumber.js/types.d.ts +1821 -0
  35. package/node_modules/call-bind-apply-helpers/.eslintrc +17 -0
  36. package/node_modules/call-bind-apply-helpers/.github/FUNDING.yml +12 -0
  37. package/node_modules/call-bind-apply-helpers/.nycrc +9 -0
  38. package/node_modules/call-bind-apply-helpers/CHANGELOG.md +30 -0
  39. package/node_modules/call-bind-apply-helpers/LICENSE +21 -0
  40. package/node_modules/call-bind-apply-helpers/README.md +62 -0
  41. package/node_modules/call-bind-apply-helpers/actualApply.d.ts +1 -0
  42. package/node_modules/call-bind-apply-helpers/actualApply.js +10 -0
  43. package/node_modules/call-bind-apply-helpers/applyBind.d.ts +19 -0
  44. package/node_modules/call-bind-apply-helpers/applyBind.js +10 -0
  45. package/node_modules/call-bind-apply-helpers/functionApply.d.ts +1 -0
  46. package/node_modules/call-bind-apply-helpers/functionApply.js +4 -0
  47. package/node_modules/call-bind-apply-helpers/functionCall.d.ts +1 -0
  48. package/node_modules/call-bind-apply-helpers/functionCall.js +4 -0
  49. package/node_modules/call-bind-apply-helpers/index.d.ts +64 -0
  50. package/node_modules/call-bind-apply-helpers/index.js +15 -0
  51. package/node_modules/call-bind-apply-helpers/package.json +85 -0
  52. package/node_modules/call-bind-apply-helpers/reflectApply.d.ts +3 -0
  53. package/node_modules/call-bind-apply-helpers/reflectApply.js +4 -0
  54. package/node_modules/call-bind-apply-helpers/test/index.js +63 -0
  55. package/node_modules/call-bind-apply-helpers/tsconfig.json +9 -0
  56. package/node_modules/combined-stream/License +19 -0
  57. package/node_modules/combined-stream/Readme.md +138 -0
  58. package/node_modules/combined-stream/lib/combined_stream.js +208 -0
  59. package/node_modules/combined-stream/package.json +25 -0
  60. package/node_modules/crypto-js/CONTRIBUTING.md +28 -0
  61. package/node_modules/crypto-js/LICENSE +24 -0
  62. package/node_modules/crypto-js/README.md +275 -0
  63. package/node_modules/crypto-js/aes.js +234 -0
  64. package/node_modules/crypto-js/blowfish.js +471 -0
  65. package/node_modules/crypto-js/bower.json +39 -0
  66. package/node_modules/crypto-js/cipher-core.js +895 -0
  67. package/node_modules/crypto-js/core.js +807 -0
  68. package/node_modules/crypto-js/crypto-js.js +6657 -0
  69. package/node_modules/crypto-js/docs/QuickStartGuide.wiki +470 -0
  70. package/node_modules/crypto-js/enc-base64.js +136 -0
  71. package/node_modules/crypto-js/enc-base64url.js +148 -0
  72. package/node_modules/crypto-js/enc-hex.js +18 -0
  73. package/node_modules/crypto-js/enc-latin1.js +18 -0
  74. package/node_modules/crypto-js/enc-utf16.js +149 -0
  75. package/node_modules/crypto-js/enc-utf8.js +18 -0
  76. package/node_modules/crypto-js/evpkdf.js +134 -0
  77. package/node_modules/crypto-js/format-hex.js +66 -0
  78. package/node_modules/crypto-js/format-openssl.js +18 -0
  79. package/node_modules/crypto-js/hmac-md5.js +18 -0
  80. package/node_modules/crypto-js/hmac-ripemd160.js +18 -0
  81. package/node_modules/crypto-js/hmac-sha1.js +18 -0
  82. package/node_modules/crypto-js/hmac-sha224.js +18 -0
  83. package/node_modules/crypto-js/hmac-sha256.js +18 -0
  84. package/node_modules/crypto-js/hmac-sha3.js +18 -0
  85. package/node_modules/crypto-js/hmac-sha384.js +18 -0
  86. package/node_modules/crypto-js/hmac-sha512.js +18 -0
  87. package/node_modules/crypto-js/hmac.js +143 -0
  88. package/node_modules/crypto-js/index.js +18 -0
  89. package/node_modules/crypto-js/lib-typedarrays.js +76 -0
  90. package/node_modules/crypto-js/md5.js +268 -0
  91. package/node_modules/crypto-js/mode-cfb.js +80 -0
  92. package/node_modules/crypto-js/mode-ctr-gladman.js +116 -0
  93. package/node_modules/crypto-js/mode-ctr.js +58 -0
  94. package/node_modules/crypto-js/mode-ecb.js +40 -0
  95. package/node_modules/crypto-js/mode-ofb.js +54 -0
  96. package/node_modules/crypto-js/package.json +42 -0
  97. package/node_modules/crypto-js/pad-ansix923.js +49 -0
  98. package/node_modules/crypto-js/pad-iso10126.js +44 -0
  99. package/node_modules/crypto-js/pad-iso97971.js +40 -0
  100. package/node_modules/crypto-js/pad-nopadding.js +30 -0
  101. package/node_modules/crypto-js/pad-pkcs7.js +18 -0
  102. package/node_modules/crypto-js/pad-zeropadding.js +47 -0
  103. package/node_modules/crypto-js/pbkdf2.js +145 -0
  104. package/node_modules/crypto-js/rabbit-legacy.js +190 -0
  105. package/node_modules/crypto-js/rabbit.js +192 -0
  106. package/node_modules/crypto-js/rc4.js +139 -0
  107. package/node_modules/crypto-js/ripemd160.js +267 -0
  108. package/node_modules/crypto-js/sha1.js +150 -0
  109. package/node_modules/crypto-js/sha224.js +80 -0
  110. package/node_modules/crypto-js/sha256.js +199 -0
  111. package/node_modules/crypto-js/sha3.js +326 -0
  112. package/node_modules/crypto-js/sha384.js +83 -0
  113. package/node_modules/crypto-js/sha512.js +326 -0
  114. package/node_modules/crypto-js/tripledes.js +779 -0
  115. package/node_modules/crypto-js/x64-core.js +304 -0
  116. package/node_modules/delayed-stream/.npmignore +1 -0
  117. package/node_modules/delayed-stream/License +19 -0
  118. package/node_modules/delayed-stream/Makefile +7 -0
  119. package/node_modules/delayed-stream/Readme.md +141 -0
  120. package/node_modules/delayed-stream/lib/delayed_stream.js +107 -0
  121. package/node_modules/delayed-stream/package.json +27 -0
  122. package/node_modules/dunder-proto/.eslintrc +5 -0
  123. package/node_modules/dunder-proto/.github/FUNDING.yml +12 -0
  124. package/node_modules/dunder-proto/.nycrc +13 -0
  125. package/node_modules/dunder-proto/CHANGELOG.md +24 -0
  126. package/node_modules/dunder-proto/LICENSE +21 -0
  127. package/node_modules/dunder-proto/README.md +54 -0
  128. package/node_modules/dunder-proto/get.d.ts +5 -0
  129. package/node_modules/dunder-proto/get.js +30 -0
  130. package/node_modules/dunder-proto/package.json +76 -0
  131. package/node_modules/dunder-proto/set.d.ts +5 -0
  132. package/node_modules/dunder-proto/set.js +35 -0
  133. package/node_modules/dunder-proto/test/get.js +34 -0
  134. package/node_modules/dunder-proto/test/index.js +4 -0
  135. package/node_modules/dunder-proto/test/set.js +50 -0
  136. package/node_modules/dunder-proto/tsconfig.json +9 -0
  137. package/node_modules/es-define-property/.eslintrc +13 -0
  138. package/node_modules/es-define-property/.github/FUNDING.yml +12 -0
  139. package/node_modules/es-define-property/.nycrc +9 -0
  140. package/node_modules/es-define-property/CHANGELOG.md +29 -0
  141. package/node_modules/es-define-property/LICENSE +21 -0
  142. package/node_modules/es-define-property/README.md +49 -0
  143. package/node_modules/es-define-property/index.d.ts +3 -0
  144. package/node_modules/es-define-property/index.js +14 -0
  145. package/node_modules/es-define-property/package.json +81 -0
  146. package/node_modules/es-define-property/test/index.js +56 -0
  147. package/node_modules/es-define-property/tsconfig.json +10 -0
  148. package/node_modules/es-errors/.eslintrc +5 -0
  149. package/node_modules/es-errors/.github/FUNDING.yml +12 -0
  150. package/node_modules/es-errors/CHANGELOG.md +40 -0
  151. package/node_modules/es-errors/LICENSE +21 -0
  152. package/node_modules/es-errors/README.md +55 -0
  153. package/node_modules/es-errors/eval.d.ts +3 -0
  154. package/node_modules/es-errors/eval.js +4 -0
  155. package/node_modules/es-errors/index.d.ts +3 -0
  156. package/node_modules/es-errors/index.js +4 -0
  157. package/node_modules/es-errors/package.json +80 -0
  158. package/node_modules/es-errors/range.d.ts +3 -0
  159. package/node_modules/es-errors/range.js +4 -0
  160. package/node_modules/es-errors/ref.d.ts +3 -0
  161. package/node_modules/es-errors/ref.js +4 -0
  162. package/node_modules/es-errors/syntax.d.ts +3 -0
  163. package/node_modules/es-errors/syntax.js +4 -0
  164. package/node_modules/es-errors/test/index.js +19 -0
  165. package/node_modules/es-errors/tsconfig.json +49 -0
  166. package/node_modules/es-errors/type.d.ts +3 -0
  167. package/node_modules/es-errors/type.js +4 -0
  168. package/node_modules/es-errors/uri.d.ts +3 -0
  169. package/node_modules/es-errors/uri.js +4 -0
  170. package/node_modules/es-object-atoms/.eslintrc +16 -0
  171. package/node_modules/es-object-atoms/.github/FUNDING.yml +12 -0
  172. package/node_modules/es-object-atoms/CHANGELOG.md +44 -0
  173. package/node_modules/es-object-atoms/LICENSE +21 -0
  174. package/node_modules/es-object-atoms/README.md +63 -0
  175. package/node_modules/es-object-atoms/RequireObjectCoercible.d.ts +3 -0
  176. package/node_modules/es-object-atoms/RequireObjectCoercible.js +11 -0
  177. package/node_modules/es-object-atoms/ToObject.d.ts +7 -0
  178. package/node_modules/es-object-atoms/ToObject.js +10 -0
  179. package/node_modules/es-object-atoms/index.d.ts +3 -0
  180. package/node_modules/es-object-atoms/index.js +4 -0
  181. package/node_modules/es-object-atoms/isObject.d.ts +3 -0
  182. package/node_modules/es-object-atoms/isObject.js +6 -0
  183. package/node_modules/es-object-atoms/package.json +79 -0
  184. package/node_modules/es-object-atoms/test/index.js +38 -0
  185. package/node_modules/es-object-atoms/tsconfig.json +7 -0
  186. package/node_modules/es-set-tostringtag/.eslintrc +13 -0
  187. package/node_modules/es-set-tostringtag/.nycrc +9 -0
  188. package/node_modules/es-set-tostringtag/CHANGELOG.md +67 -0
  189. package/node_modules/es-set-tostringtag/LICENSE +21 -0
  190. package/node_modules/es-set-tostringtag/README.md +53 -0
  191. package/node_modules/es-set-tostringtag/index.d.ts +10 -0
  192. package/node_modules/es-set-tostringtag/index.js +35 -0
  193. package/node_modules/es-set-tostringtag/package.json +78 -0
  194. package/node_modules/es-set-tostringtag/test/index.js +85 -0
  195. package/node_modules/es-set-tostringtag/tsconfig.json +9 -0
  196. package/node_modules/form-data/CHANGELOG.md +686 -0
  197. package/node_modules/form-data/License +19 -0
  198. package/node_modules/form-data/README.md +355 -0
  199. package/node_modules/form-data/index.d.ts +62 -0
  200. package/node_modules/form-data/lib/browser.js +4 -0
  201. package/node_modules/form-data/lib/form_data.js +506 -0
  202. package/node_modules/form-data/lib/populate.js +10 -0
  203. package/node_modules/form-data/node_modules/mime-db/HISTORY.md +507 -0
  204. package/node_modules/form-data/node_modules/mime-db/LICENSE +23 -0
  205. package/node_modules/form-data/node_modules/mime-db/README.md +100 -0
  206. package/node_modules/form-data/node_modules/mime-db/db.json +8519 -0
  207. package/node_modules/form-data/node_modules/mime-db/index.js +12 -0
  208. package/node_modules/form-data/node_modules/mime-db/package.json +60 -0
  209. package/node_modules/form-data/node_modules/mime-types/HISTORY.md +397 -0
  210. package/node_modules/form-data/node_modules/mime-types/LICENSE +23 -0
  211. package/node_modules/form-data/node_modules/mime-types/README.md +113 -0
  212. package/node_modules/form-data/node_modules/mime-types/index.js +188 -0
  213. package/node_modules/form-data/node_modules/mime-types/package.json +44 -0
  214. package/node_modules/form-data/package.json +82 -0
  215. package/node_modules/function-bind/.eslintrc +21 -0
  216. package/node_modules/function-bind/.github/FUNDING.yml +12 -0
  217. package/node_modules/function-bind/.github/SECURITY.md +3 -0
  218. package/node_modules/function-bind/.nycrc +13 -0
  219. package/node_modules/function-bind/CHANGELOG.md +136 -0
  220. package/node_modules/function-bind/LICENSE +20 -0
  221. package/node_modules/function-bind/README.md +46 -0
  222. package/node_modules/function-bind/implementation.js +84 -0
  223. package/node_modules/function-bind/index.js +5 -0
  224. package/node_modules/function-bind/package.json +87 -0
  225. package/node_modules/function-bind/test/.eslintrc +9 -0
  226. package/node_modules/function-bind/test/index.js +252 -0
  227. package/node_modules/get-intrinsic/.eslintrc +42 -0
  228. package/node_modules/get-intrinsic/.github/FUNDING.yml +12 -0
  229. package/node_modules/get-intrinsic/.nycrc +9 -0
  230. package/node_modules/get-intrinsic/CHANGELOG.md +186 -0
  231. package/node_modules/get-intrinsic/LICENSE +21 -0
  232. package/node_modules/get-intrinsic/README.md +71 -0
  233. package/node_modules/get-intrinsic/index.js +378 -0
  234. package/node_modules/get-intrinsic/package.json +97 -0
  235. package/node_modules/get-intrinsic/test/GetIntrinsic.js +274 -0
  236. package/node_modules/get-proto/.eslintrc +10 -0
  237. package/node_modules/get-proto/.github/FUNDING.yml +12 -0
  238. package/node_modules/get-proto/.nycrc +9 -0
  239. package/node_modules/get-proto/CHANGELOG.md +21 -0
  240. package/node_modules/get-proto/LICENSE +21 -0
  241. package/node_modules/get-proto/Object.getPrototypeOf.d.ts +5 -0
  242. package/node_modules/get-proto/Object.getPrototypeOf.js +6 -0
  243. package/node_modules/get-proto/README.md +50 -0
  244. package/node_modules/get-proto/Reflect.getPrototypeOf.d.ts +3 -0
  245. package/node_modules/get-proto/Reflect.getPrototypeOf.js +4 -0
  246. package/node_modules/get-proto/index.d.ts +5 -0
  247. package/node_modules/get-proto/index.js +27 -0
  248. package/node_modules/get-proto/package.json +81 -0
  249. package/node_modules/get-proto/test/index.js +68 -0
  250. package/node_modules/get-proto/tsconfig.json +9 -0
  251. package/node_modules/gopd/.eslintrc +16 -0
  252. package/node_modules/gopd/.github/FUNDING.yml +12 -0
  253. package/node_modules/gopd/CHANGELOG.md +45 -0
  254. package/node_modules/gopd/LICENSE +21 -0
  255. package/node_modules/gopd/README.md +40 -0
  256. package/node_modules/gopd/gOPD.d.ts +1 -0
  257. package/node_modules/gopd/gOPD.js +4 -0
  258. package/node_modules/gopd/index.d.ts +5 -0
  259. package/node_modules/gopd/index.js +15 -0
  260. package/node_modules/gopd/package.json +77 -0
  261. package/node_modules/gopd/test/index.js +36 -0
  262. package/node_modules/gopd/tsconfig.json +9 -0
  263. package/node_modules/has-symbols/.eslintrc +11 -0
  264. package/node_modules/has-symbols/.github/FUNDING.yml +12 -0
  265. package/node_modules/has-symbols/.nycrc +9 -0
  266. package/node_modules/has-symbols/CHANGELOG.md +91 -0
  267. package/node_modules/has-symbols/LICENSE +21 -0
  268. package/node_modules/has-symbols/README.md +46 -0
  269. package/node_modules/has-symbols/index.d.ts +3 -0
  270. package/node_modules/has-symbols/index.js +14 -0
  271. package/node_modules/has-symbols/package.json +111 -0
  272. package/node_modules/has-symbols/shams.d.ts +3 -0
  273. package/node_modules/has-symbols/shams.js +45 -0
  274. package/node_modules/has-symbols/test/index.js +22 -0
  275. package/node_modules/has-symbols/test/shams/core-js.js +29 -0
  276. package/node_modules/has-symbols/test/shams/get-own-property-symbols.js +29 -0
  277. package/node_modules/has-symbols/test/tests.js +58 -0
  278. package/node_modules/has-symbols/tsconfig.json +10 -0
  279. package/node_modules/has-tostringtag/.eslintrc +5 -0
  280. package/node_modules/has-tostringtag/.github/FUNDING.yml +12 -0
  281. package/node_modules/has-tostringtag/.nycrc +13 -0
  282. package/node_modules/has-tostringtag/CHANGELOG.md +42 -0
  283. package/node_modules/has-tostringtag/LICENSE +21 -0
  284. package/node_modules/has-tostringtag/README.md +46 -0
  285. package/node_modules/has-tostringtag/index.d.ts +3 -0
  286. package/node_modules/has-tostringtag/index.js +8 -0
  287. package/node_modules/has-tostringtag/package.json +108 -0
  288. package/node_modules/has-tostringtag/shams.d.ts +3 -0
  289. package/node_modules/has-tostringtag/shams.js +8 -0
  290. package/node_modules/has-tostringtag/test/index.js +21 -0
  291. package/node_modules/has-tostringtag/test/shams/core-js.js +31 -0
  292. package/node_modules/has-tostringtag/test/shams/get-own-property-symbols.js +30 -0
  293. package/node_modules/has-tostringtag/test/tests.js +15 -0
  294. package/node_modules/has-tostringtag/tsconfig.json +49 -0
  295. package/node_modules/hasown/.github/FUNDING.yml +12 -0
  296. package/node_modules/hasown/.nycrc +13 -0
  297. package/node_modules/hasown/CHANGELOG.md +58 -0
  298. package/node_modules/hasown/LICENSE +21 -0
  299. package/node_modules/hasown/README.md +40 -0
  300. package/node_modules/hasown/eslint.config.mjs +6 -0
  301. package/node_modules/hasown/index.d.ts +3 -0
  302. package/node_modules/hasown/index.js +8 -0
  303. package/node_modules/hasown/package.json +91 -0
  304. package/node_modules/hasown/tsconfig.json +6 -0
  305. package/node_modules/json-bigint/LICENSE +20 -0
  306. package/node_modules/json-bigint/README.md +240 -0
  307. package/node_modules/json-bigint/index.js +12 -0
  308. package/node_modules/json-bigint/lib/parse.js +443 -0
  309. package/node_modules/json-bigint/lib/stringify.js +384 -0
  310. package/node_modules/json-bigint/package.json +34 -0
  311. package/node_modules/math-intrinsics/.eslintrc +16 -0
  312. package/node_modules/math-intrinsics/.github/FUNDING.yml +12 -0
  313. package/node_modules/math-intrinsics/CHANGELOG.md +24 -0
  314. package/node_modules/math-intrinsics/LICENSE +21 -0
  315. package/node_modules/math-intrinsics/README.md +50 -0
  316. package/node_modules/math-intrinsics/abs.d.ts +1 -0
  317. package/node_modules/math-intrinsics/abs.js +4 -0
  318. package/node_modules/math-intrinsics/constants/maxArrayLength.d.ts +3 -0
  319. package/node_modules/math-intrinsics/constants/maxArrayLength.js +4 -0
  320. package/node_modules/math-intrinsics/constants/maxSafeInteger.d.ts +3 -0
  321. package/node_modules/math-intrinsics/constants/maxSafeInteger.js +5 -0
  322. package/node_modules/math-intrinsics/constants/maxValue.d.ts +3 -0
  323. package/node_modules/math-intrinsics/constants/maxValue.js +5 -0
  324. package/node_modules/math-intrinsics/floor.d.ts +1 -0
  325. package/node_modules/math-intrinsics/floor.js +4 -0
  326. package/node_modules/math-intrinsics/isFinite.d.ts +3 -0
  327. package/node_modules/math-intrinsics/isFinite.js +12 -0
  328. package/node_modules/math-intrinsics/isInteger.d.ts +3 -0
  329. package/node_modules/math-intrinsics/isInteger.js +16 -0
  330. package/node_modules/math-intrinsics/isNaN.d.ts +1 -0
  331. package/node_modules/math-intrinsics/isNaN.js +6 -0
  332. package/node_modules/math-intrinsics/isNegativeZero.d.ts +3 -0
  333. package/node_modules/math-intrinsics/isNegativeZero.js +6 -0
  334. package/node_modules/math-intrinsics/max.d.ts +1 -0
  335. package/node_modules/math-intrinsics/max.js +4 -0
  336. package/node_modules/math-intrinsics/min.d.ts +1 -0
  337. package/node_modules/math-intrinsics/min.js +4 -0
  338. package/node_modules/math-intrinsics/mod.d.ts +3 -0
  339. package/node_modules/math-intrinsics/mod.js +9 -0
  340. package/node_modules/math-intrinsics/package.json +86 -0
  341. package/node_modules/math-intrinsics/pow.d.ts +1 -0
  342. package/node_modules/math-intrinsics/pow.js +4 -0
  343. package/node_modules/math-intrinsics/round.d.ts +1 -0
  344. package/node_modules/math-intrinsics/round.js +4 -0
  345. package/node_modules/math-intrinsics/sign.d.ts +3 -0
  346. package/node_modules/math-intrinsics/sign.js +11 -0
  347. package/node_modules/math-intrinsics/test/index.js +192 -0
  348. package/node_modules/math-intrinsics/tsconfig.json +3 -0
  349. package/node_modules/pako/LICENSE +21 -0
  350. package/node_modules/pako/README.md +155 -0
  351. package/node_modules/pako/dist/pako.es5.js +6760 -0
  352. package/node_modules/pako/dist/pako.es5.min.js +2 -0
  353. package/node_modules/pako/dist/pako.esm.mjs +6945 -0
  354. package/node_modules/pako/dist/pako.js +6964 -0
  355. package/node_modules/pako/dist/pako.min.js +2 -0
  356. package/node_modules/pako/dist/pako_deflate.es5.js +3953 -0
  357. package/node_modules/pako/dist/pako_deflate.es5.min.js +2 -0
  358. package/node_modules/pako/dist/pako_deflate.js +4154 -0
  359. package/node_modules/pako/dist/pako_deflate.min.js +2 -0
  360. package/node_modules/pako/dist/pako_inflate.es5.js +3272 -0
  361. package/node_modules/pako/dist/pako_inflate.es5.min.js +2 -0
  362. package/node_modules/pako/dist/pako_inflate.js +3279 -0
  363. package/node_modules/pako/dist/pako_inflate.min.js +2 -0
  364. package/node_modules/pako/index.js +18 -0
  365. package/node_modules/pako/lib/deflate.js +387 -0
  366. package/node_modules/pako/lib/inflate.js +456 -0
  367. package/node_modules/pako/lib/utils/common.js +48 -0
  368. package/node_modules/pako/lib/utils/strings.js +174 -0
  369. package/node_modules/pako/lib/zlib/README +59 -0
  370. package/node_modules/pako/lib/zlib/adler32.js +51 -0
  371. package/node_modules/pako/lib/zlib/constants.js +68 -0
  372. package/node_modules/pako/lib/zlib/crc32.js +59 -0
  373. package/node_modules/pako/lib/zlib/deflate.js +2069 -0
  374. package/node_modules/pako/lib/zlib/gzheader.js +58 -0
  375. package/node_modules/pako/lib/zlib/inffast.js +344 -0
  376. package/node_modules/pako/lib/zlib/inflate.js +1575 -0
  377. package/node_modules/pako/lib/zlib/inftrees.js +340 -0
  378. package/node_modules/pako/lib/zlib/messages.js +32 -0
  379. package/node_modules/pako/lib/zlib/trees.js +1179 -0
  380. package/node_modules/pako/lib/zlib/zstream.js +47 -0
  381. package/node_modules/pako/package.json +73 -0
  382. package/node_modules/semver/LICENSE +15 -0
  383. package/node_modules/semver/README.md +680 -0
  384. package/node_modules/semver/bin/semver.js +195 -0
  385. package/node_modules/semver/classes/comparator.js +143 -0
  386. package/node_modules/semver/classes/index.js +7 -0
  387. package/node_modules/semver/classes/range.js +577 -0
  388. package/node_modules/semver/classes/semver.js +350 -0
  389. package/node_modules/semver/functions/clean.js +8 -0
  390. package/node_modules/semver/functions/cmp.js +54 -0
  391. package/node_modules/semver/functions/coerce.js +62 -0
  392. package/node_modules/semver/functions/compare-build.js +9 -0
  393. package/node_modules/semver/functions/compare-loose.js +5 -0
  394. package/node_modules/semver/functions/compare.js +7 -0
  395. package/node_modules/semver/functions/diff.js +60 -0
  396. package/node_modules/semver/functions/eq.js +5 -0
  397. package/node_modules/semver/functions/gt.js +5 -0
  398. package/node_modules/semver/functions/gte.js +5 -0
  399. package/node_modules/semver/functions/inc.js +21 -0
  400. package/node_modules/semver/functions/lt.js +5 -0
  401. package/node_modules/semver/functions/lte.js +5 -0
  402. package/node_modules/semver/functions/major.js +5 -0
  403. package/node_modules/semver/functions/minor.js +5 -0
  404. package/node_modules/semver/functions/neq.js +5 -0
  405. package/node_modules/semver/functions/parse.js +18 -0
  406. package/node_modules/semver/functions/patch.js +5 -0
  407. package/node_modules/semver/functions/prerelease.js +8 -0
  408. package/node_modules/semver/functions/rcompare.js +5 -0
  409. package/node_modules/semver/functions/rsort.js +5 -0
  410. package/node_modules/semver/functions/satisfies.js +12 -0
  411. package/node_modules/semver/functions/sort.js +5 -0
  412. package/node_modules/semver/functions/truncate.js +48 -0
  413. package/node_modules/semver/functions/valid.js +8 -0
  414. package/node_modules/semver/index.js +93 -0
  415. package/node_modules/semver/internal/constants.js +37 -0
  416. package/node_modules/semver/internal/debug.js +11 -0
  417. package/node_modules/semver/internal/identifiers.js +29 -0
  418. package/node_modules/semver/internal/lrucache.js +42 -0
  419. package/node_modules/semver/internal/parse-options.js +17 -0
  420. package/node_modules/semver/internal/re.js +223 -0
  421. package/node_modules/semver/package.json +78 -0
  422. package/node_modules/semver/preload.js +4 -0
  423. package/node_modules/semver/range.bnf +17 -0
  424. package/node_modules/semver/ranges/gtr.js +6 -0
  425. package/node_modules/semver/ranges/intersects.js +9 -0
  426. package/node_modules/semver/ranges/ltr.js +6 -0
  427. package/node_modules/semver/ranges/max-satisfying.js +27 -0
  428. package/node_modules/semver/ranges/min-satisfying.js +26 -0
  429. package/node_modules/semver/ranges/min-version.js +63 -0
  430. package/node_modules/semver/ranges/outside.js +82 -0
  431. package/node_modules/semver/ranges/simplify.js +49 -0
  432. package/node_modules/semver/ranges/subset.js +249 -0
  433. package/node_modules/semver/ranges/to-comparators.js +10 -0
  434. package/node_modules/semver/ranges/valid.js +13 -0
  435. package/node_modules/spark-md5/LICENSE +13 -0
  436. package/node_modules/spark-md5/README.md +191 -0
  437. package/node_modules/spark-md5/package.json +35 -0
  438. package/node_modules/spark-md5/spark-md5.js +751 -0
  439. package/node_modules/spark-md5/spark-md5.min.js +1 -0
  440. package/node_modules/tldts/LICENSE +13 -0
  441. package/node_modules/tldts/README.md +327 -0
  442. package/node_modules/tldts/bin/cli.js +21 -0
  443. package/node_modules/tldts/dist/cjs/index.js +666 -0
  444. package/node_modules/tldts/dist/cjs/index.js.map +1 -0
  445. package/node_modules/tldts/dist/cjs/src/data/trie.js +14 -0
  446. package/node_modules/tldts/dist/cjs/src/data/trie.js.map +1 -0
  447. package/node_modules/tldts/dist/cjs/src/suffix-trie.js +67 -0
  448. package/node_modules/tldts/dist/cjs/src/suffix-trie.js.map +1 -0
  449. package/node_modules/tldts/dist/cjs/tsconfig.tsbuildinfo +1 -0
  450. package/node_modules/tldts/dist/es6/index.js +33 -0
  451. package/node_modules/tldts/dist/es6/index.js.map +1 -0
  452. package/node_modules/tldts/dist/es6/src/data/trie.js +11 -0
  453. package/node_modules/tldts/dist/es6/src/data/trie.js.map +1 -0
  454. package/node_modules/tldts/dist/es6/src/suffix-trie.js +64 -0
  455. package/node_modules/tldts/dist/es6/src/suffix-trie.js.map +1 -0
  456. package/node_modules/tldts/dist/es6/tsconfig.bundle.tsbuildinfo +1 -0
  457. package/node_modules/tldts/dist/index.cjs.min.js +2 -0
  458. package/node_modules/tldts/dist/index.cjs.min.js.map +1 -0
  459. package/node_modules/tldts/dist/index.esm.min.js +2 -0
  460. package/node_modules/tldts/dist/index.esm.min.js.map +1 -0
  461. package/node_modules/tldts/dist/index.umd.min.js +2 -0
  462. package/node_modules/tldts/dist/index.umd.min.js.map +1 -0
  463. package/node_modules/tldts/dist/types/index.d.ts +7 -0
  464. package/node_modules/tldts/dist/types/src/data/trie.d.ts +5 -0
  465. package/node_modules/tldts/dist/types/src/suffix-trie.d.ts +5 -0
  466. package/node_modules/tldts/index.ts +62 -0
  467. package/node_modules/tldts/package.json +91 -0
  468. package/node_modules/tldts/src/data/trie.ts +14 -0
  469. package/node_modules/tldts/src/suffix-trie.ts +110 -0
  470. package/node_modules/tldts-core/LICENSE +13 -0
  471. package/node_modules/tldts-core/README.md +3 -0
  472. package/node_modules/tldts-core/dist/cjs/index.js +561 -0
  473. package/node_modules/tldts-core/dist/cjs/index.js.map +1 -0
  474. package/node_modules/tldts-core/dist/cjs/src/domain-without-suffix.js +15 -0
  475. package/node_modules/tldts-core/dist/cjs/src/domain-without-suffix.js.map +1 -0
  476. package/node_modules/tldts-core/dist/cjs/src/domain.js +83 -0
  477. package/node_modules/tldts-core/dist/cjs/src/domain.js.map +1 -0
  478. package/node_modules/tldts-core/dist/cjs/src/extract-hostname.js +149 -0
  479. package/node_modules/tldts-core/dist/cjs/src/extract-hostname.js.map +1 -0
  480. package/node_modules/tldts-core/dist/cjs/src/factory.js +104 -0
  481. package/node_modules/tldts-core/dist/cjs/src/factory.js.map +1 -0
  482. package/node_modules/tldts-core/dist/cjs/src/is-ip.js +72 -0
  483. package/node_modules/tldts-core/dist/cjs/src/is-ip.js.map +1 -0
  484. package/node_modules/tldts-core/dist/cjs/src/is-valid.js +69 -0
  485. package/node_modules/tldts-core/dist/cjs/src/is-valid.js.map +1 -0
  486. package/node_modules/tldts-core/dist/cjs/src/lookup/fast-path.js +69 -0
  487. package/node_modules/tldts-core/dist/cjs/src/lookup/fast-path.js.map +1 -0
  488. package/node_modules/tldts-core/dist/cjs/src/lookup/interface.js +3 -0
  489. package/node_modules/tldts-core/dist/cjs/src/lookup/interface.js.map +1 -0
  490. package/node_modules/tldts-core/dist/cjs/src/options.js +22 -0
  491. package/node_modules/tldts-core/dist/cjs/src/options.js.map +1 -0
  492. package/node_modules/tldts-core/dist/cjs/src/subdomain.js +14 -0
  493. package/node_modules/tldts-core/dist/cjs/src/subdomain.js.map +1 -0
  494. package/node_modules/tldts-core/dist/cjs/tsconfig.tsbuildinfo +1 -0
  495. package/node_modules/tldts-core/dist/es6/index.js +4 -0
  496. package/node_modules/tldts-core/dist/es6/index.js.map +1 -0
  497. package/node_modules/tldts-core/dist/es6/src/domain-without-suffix.js +12 -0
  498. package/node_modules/tldts-core/dist/es6/src/domain-without-suffix.js.map +1 -0
  499. package/node_modules/tldts-core/dist/es6/src/domain.js +80 -0
  500. package/node_modules/tldts-core/dist/es6/src/domain.js.map +1 -0
  501. package/node_modules/tldts-core/dist/es6/src/extract-hostname.js +146 -0
  502. package/node_modules/tldts-core/dist/es6/src/extract-hostname.js.map +1 -0
  503. package/node_modules/tldts-core/dist/es6/src/factory.js +99 -0
  504. package/node_modules/tldts-core/dist/es6/src/factory.js.map +1 -0
  505. package/node_modules/tldts-core/dist/es6/src/is-ip.js +69 -0
  506. package/node_modules/tldts-core/dist/es6/src/is-ip.js.map +1 -0
  507. package/node_modules/tldts-core/dist/es6/src/is-valid.js +66 -0
  508. package/node_modules/tldts-core/dist/es6/src/is-valid.js.map +1 -0
  509. package/node_modules/tldts-core/dist/es6/src/lookup/fast-path.js +66 -0
  510. package/node_modules/tldts-core/dist/es6/src/lookup/fast-path.js.map +1 -0
  511. package/node_modules/tldts-core/dist/es6/src/lookup/interface.js +2 -0
  512. package/node_modules/tldts-core/dist/es6/src/lookup/interface.js.map +1 -0
  513. package/node_modules/tldts-core/dist/es6/src/options.js +19 -0
  514. package/node_modules/tldts-core/dist/es6/src/options.js.map +1 -0
  515. package/node_modules/tldts-core/dist/es6/src/subdomain.js +11 -0
  516. package/node_modules/tldts-core/dist/es6/src/subdomain.js.map +1 -0
  517. package/node_modules/tldts-core/dist/es6/tsconfig.bundle.tsbuildinfo +1 -0
  518. package/node_modules/tldts-core/dist/types/index.d.ts +4 -0
  519. package/node_modules/tldts-core/dist/types/src/domain-without-suffix.d.ts +6 -0
  520. package/node_modules/tldts-core/dist/types/src/domain.d.ts +5 -0
  521. package/node_modules/tldts-core/dist/types/src/extract-hostname.d.ts +5 -0
  522. package/node_modules/tldts-core/dist/types/src/factory.d.ts +28 -0
  523. package/node_modules/tldts-core/dist/types/src/is-ip.d.ts +6 -0
  524. package/node_modules/tldts-core/dist/types/src/is-valid.d.ts +15 -0
  525. package/node_modules/tldts-core/dist/types/src/lookup/fast-path.d.ts +2 -0
  526. package/node_modules/tldts-core/dist/types/src/lookup/interface.d.ts +9 -0
  527. package/node_modules/tldts-core/dist/types/src/options.d.ts +10 -0
  528. package/node_modules/tldts-core/dist/types/src/subdomain.d.ts +4 -0
  529. package/node_modules/tldts-core/index.ts +10 -0
  530. package/node_modules/tldts-core/package.json +68 -0
  531. package/node_modules/tldts-core/src/domain-without-suffix.ts +14 -0
  532. package/node_modules/tldts-core/src/domain.ts +100 -0
  533. package/node_modules/tldts-core/src/extract-hostname.ts +170 -0
  534. package/node_modules/tldts-core/src/factory.ts +160 -0
  535. package/node_modules/tldts-core/src/is-ip.ts +87 -0
  536. package/node_modules/tldts-core/src/is-valid.ts +79 -0
  537. package/node_modules/tldts-core/src/lookup/fast-path.ts +80 -0
  538. package/node_modules/tldts-core/src/lookup/interface.ts +10 -0
  539. package/node_modules/tldts-core/src/options.ts +39 -0
  540. package/node_modules/tldts-core/src/subdomain.ts +11 -0
  541. package/node_modules/tough-cookie/LICENSE +12 -0
  542. package/node_modules/tough-cookie/README.md +154 -0
  543. package/node_modules/tough-cookie/dist/cookie/canonicalDomain.d.ts +33 -0
  544. package/node_modules/tough-cookie/dist/cookie/canonicalDomain.js +65 -0
  545. package/node_modules/tough-cookie/dist/cookie/constants.d.ts +54 -0
  546. package/node_modules/tough-cookie/dist/cookie/constants.js +38 -0
  547. package/node_modules/tough-cookie/dist/cookie/cookie.d.ts +326 -0
  548. package/node_modules/tough-cookie/dist/cookie/cookie.js +831 -0
  549. package/node_modules/tough-cookie/dist/cookie/cookieCompare.d.ts +58 -0
  550. package/node_modules/tough-cookie/dist/cookie/cookieCompare.js +84 -0
  551. package/node_modules/tough-cookie/dist/cookie/cookieJar.d.ts +621 -0
  552. package/node_modules/tough-cookie/dist/cookie/cookieJar.js +1000 -0
  553. package/node_modules/tough-cookie/dist/cookie/defaultPath.d.ts +40 -0
  554. package/node_modules/tough-cookie/dist/cookie/defaultPath.js +60 -0
  555. package/node_modules/tough-cookie/dist/cookie/domainMatch.d.ts +38 -0
  556. package/node_modules/tough-cookie/dist/cookie/domainMatch.js +94 -0
  557. package/node_modules/tough-cookie/dist/cookie/formatDate.d.ts +15 -0
  558. package/node_modules/tough-cookie/dist/cookie/formatDate.js +20 -0
  559. package/node_modules/tough-cookie/dist/cookie/index.d.ts +29 -0
  560. package/node_modules/tough-cookie/dist/cookie/index.js +54 -0
  561. package/node_modules/tough-cookie/dist/cookie/parseDate.d.ts +103 -0
  562. package/node_modules/tough-cookie/dist/cookie/parseDate.js +323 -0
  563. package/node_modules/tough-cookie/dist/cookie/permutePath.d.ts +14 -0
  564. package/node_modules/tough-cookie/dist/cookie/permutePath.js +32 -0
  565. package/node_modules/tough-cookie/dist/getPublicSuffix.d.ts +55 -0
  566. package/node_modules/tough-cookie/dist/getPublicSuffix.js +71 -0
  567. package/node_modules/tough-cookie/dist/memstore.d.ts +220 -0
  568. package/node_modules/tough-cookie/dist/memstore.js +187 -0
  569. package/node_modules/tough-cookie/dist/pathMatch.d.ts +17 -0
  570. package/node_modules/tough-cookie/dist/pathMatch.js +40 -0
  571. package/node_modules/tough-cookie/dist/permuteDomain.d.ts +15 -0
  572. package/node_modules/tough-cookie/dist/permuteDomain.js +44 -0
  573. package/node_modules/tough-cookie/dist/store.d.ts +211 -0
  574. package/node_modules/tough-cookie/dist/store.js +76 -0
  575. package/node_modules/tough-cookie/dist/utils.d.ts +34 -0
  576. package/node_modules/tough-cookie/dist/utils.js +99 -0
  577. package/node_modules/tough-cookie/dist/validators.d.ts +24 -0
  578. package/node_modules/tough-cookie/dist/validators.js +90 -0
  579. package/node_modules/tough-cookie/dist/version.d.ts +5 -0
  580. package/node_modules/tough-cookie/dist/version.js +8 -0
  581. package/node_modules/tough-cookie/package.json +144 -0
  582. package/node_modules/ws/LICENSE +20 -0
  583. package/node_modules/ws/README.md +548 -0
  584. package/node_modules/ws/browser.js +8 -0
  585. package/node_modules/ws/index.js +22 -0
  586. package/node_modules/ws/lib/buffer-util.js +131 -0
  587. package/node_modules/ws/lib/constants.js +19 -0
  588. package/node_modules/ws/lib/event-target.js +292 -0
  589. package/node_modules/ws/lib/extension.js +203 -0
  590. package/node_modules/ws/lib/limiter.js +55 -0
  591. package/node_modules/ws/lib/permessage-deflate.js +530 -0
  592. package/node_modules/ws/lib/receiver.js +743 -0
  593. package/node_modules/ws/lib/sender.js +607 -0
  594. package/node_modules/ws/lib/stream.js +161 -0
  595. package/node_modules/ws/lib/subprotocol.js +62 -0
  596. package/node_modules/ws/lib/validation.js +152 -0
  597. package/node_modules/ws/lib/websocket-server.js +562 -0
  598. package/node_modules/ws/lib/websocket.js +1407 -0
  599. package/node_modules/ws/package.json +74 -0
  600. package/node_modules/ws/wrapper.mjs +21 -0
  601. package/node_modules/zca-js/.prettierrc +5 -0
  602. package/node_modules/zca-js/CODE_OF_CONDUCT.md +163 -0
  603. package/node_modules/zca-js/CONTRIBUTING.md +470 -0
  604. package/node_modules/zca-js/LICENSE +21 -0
  605. package/node_modules/zca-js/README.md +225 -0
  606. package/node_modules/zca-js/SECURITY.md +83 -0
  607. package/node_modules/zca-js/dist/Errors/ZaloApiError.d.ts +4 -0
  608. package/node_modules/zca-js/dist/Errors/ZaloApiError.js +7 -0
  609. package/node_modules/zca-js/dist/Errors/ZaloApiLoginQRAborted.d.ts +4 -0
  610. package/node_modules/zca-js/dist/Errors/ZaloApiLoginQRAborted.js +7 -0
  611. package/node_modules/zca-js/dist/Errors/ZaloApiLoginQRDeclined.d.ts +4 -0
  612. package/node_modules/zca-js/dist/Errors/ZaloApiLoginQRDeclined.js +7 -0
  613. package/node_modules/zca-js/dist/Errors/ZaloApiMissingImageMetadataGetter.d.ts +4 -0
  614. package/node_modules/zca-js/dist/Errors/ZaloApiMissingImageMetadataGetter.js +7 -0
  615. package/node_modules/zca-js/dist/Errors/index.d.ts +4 -0
  616. package/node_modules/zca-js/dist/Errors/index.js +4 -0
  617. package/node_modules/zca-js/dist/apis/acceptFriendRequest.d.ts +2 -0
  618. package/node_modules/zca-js/dist/apis/acceptFriendRequest.js +28 -0
  619. package/node_modules/zca-js/dist/apis/addGroupBlockedMember.d.ts +2 -0
  620. package/node_modules/zca-js/dist/apis/addGroupBlockedMember.js +28 -0
  621. package/node_modules/zca-js/dist/apis/addGroupDeputy.d.ts +2 -0
  622. package/node_modules/zca-js/dist/apis/addGroupDeputy.js +30 -0
  623. package/node_modules/zca-js/dist/apis/addPollOptions.d.ts +14 -0
  624. package/node_modules/zca-js/dist/apis/addPollOptions.js +26 -0
  625. package/node_modules/zca-js/dist/apis/addQuickMessage.d.ts +11 -0
  626. package/node_modules/zca-js/dist/apis/addQuickMessage.js +60 -0
  627. package/node_modules/zca-js/dist/apis/addReaction.d.ts +18 -0
  628. package/node_modules/zca-js/dist/apis/addReaction.js +294 -0
  629. package/node_modules/zca-js/dist/apis/addUnreadMark.d.ts +8 -0
  630. package/node_modules/zca-js/dist/apis/addUnreadMark.js +52 -0
  631. package/node_modules/zca-js/dist/apis/addUserToGroup.d.ts +5 -0
  632. package/node_modules/zca-js/dist/apis/addUserToGroup.js +34 -0
  633. package/node_modules/zca-js/dist/apis/blockUser.d.ts +2 -0
  634. package/node_modules/zca-js/dist/apis/blockUser.js +28 -0
  635. package/node_modules/zca-js/dist/apis/blockViewFeed.d.ts +2 -0
  636. package/node_modules/zca-js/dist/apis/blockViewFeed.js +30 -0
  637. package/node_modules/zca-js/dist/apis/changeAccountAvatar.d.ts +3 -0
  638. package/node_modules/zca-js/dist/apis/changeAccountAvatar.js +52 -0
  639. package/node_modules/zca-js/dist/apis/changeFriendAlias.d.ts +2 -0
  640. package/node_modules/zca-js/dist/apis/changeFriendAlias.js +27 -0
  641. package/node_modules/zca-js/dist/apis/changeGroupAvatar.d.ts +3 -0
  642. package/node_modules/zca-js/dist/apis/changeGroupAvatar.js +44 -0
  643. package/node_modules/zca-js/dist/apis/changeGroupName.d.ts +4 -0
  644. package/node_modules/zca-js/dist/apis/changeGroupName.js +32 -0
  645. package/node_modules/zca-js/dist/apis/changeGroupOwner.d.ts +4 -0
  646. package/node_modules/zca-js/dist/apis/changeGroupOwner.js +30 -0
  647. package/node_modules/zca-js/dist/apis/createAutoReply.d.ts +14 -0
  648. package/node_modules/zca-js/dist/apis/createAutoReply.js +37 -0
  649. package/node_modules/zca-js/dist/apis/createBankAccount.d.ts +8 -0
  650. package/node_modules/zca-js/dist/apis/createBankAccount.js +32 -0
  651. package/node_modules/zca-js/dist/apis/createCatalog.d.ts +7 -0
  652. package/node_modules/zca-js/dist/apis/createCatalog.js +29 -0
  653. package/node_modules/zca-js/dist/apis/createGroup.d.ts +28 -0
  654. package/node_modules/zca-js/dist/apis/createGroup.js +43 -0
  655. package/node_modules/zca-js/dist/apis/createNote.d.ts +7 -0
  656. package/node_modules/zca-js/dist/apis/createNote.js +47 -0
  657. package/node_modules/zca-js/dist/apis/createPoll.d.ts +36 -0
  658. package/node_modules/zca-js/dist/apis/createPoll.js +40 -0
  659. package/node_modules/zca-js/dist/apis/createProductCatalog.d.ts +23 -0
  660. package/node_modules/zca-js/dist/apis/createProductCatalog.js +50 -0
  661. package/node_modules/zca-js/dist/apis/createReminder.d.ts +12 -0
  662. package/node_modules/zca-js/dist/apis/createReminder.js +63 -0
  663. package/node_modules/zca-js/dist/apis/custom.d.ts +9 -0
  664. package/node_modules/zca-js/dist/apis/custom.js +15 -0
  665. package/node_modules/zca-js/dist/apis/deleteAutoReply.d.ts +5 -0
  666. package/node_modules/zca-js/dist/apis/deleteAutoReply.js +29 -0
  667. package/node_modules/zca-js/dist/apis/deleteAvatar.d.ts +9 -0
  668. package/node_modules/zca-js/dist/apis/deleteAvatar.js +27 -0
  669. package/node_modules/zca-js/dist/apis/deleteBankAccount.d.ts +11 -0
  670. package/node_modules/zca-js/dist/apis/deleteBankAccount.js +32 -0
  671. package/node_modules/zca-js/dist/apis/deleteCatalog.d.ts +2 -0
  672. package/node_modules/zca-js/dist/apis/deleteCatalog.js +28 -0
  673. package/node_modules/zca-js/dist/apis/deleteChat.d.ts +19 -0
  674. package/node_modules/zca-js/dist/apis/deleteChat.js +50 -0
  675. package/node_modules/zca-js/dist/apis/deleteGroupInviteBox.d.ts +9 -0
  676. package/node_modules/zca-js/dist/apis/deleteGroupInviteBox.js +27 -0
  677. package/node_modules/zca-js/dist/apis/deleteMessage.d.ts +14 -0
  678. package/node_modules/zca-js/dist/apis/deleteMessage.js +52 -0
  679. package/node_modules/zca-js/dist/apis/deleteProductCatalog.d.ts +10 -0
  680. package/node_modules/zca-js/dist/apis/deleteProductCatalog.js +31 -0
  681. package/node_modules/zca-js/dist/apis/deleteSnapshotMobileMsg.js +18 -0
  682. package/node_modules/zca-js/dist/apis/disableGroupLink.d.ts +2 -0
  683. package/node_modules/zca-js/dist/apis/disableGroupLink.js +24 -0
  684. package/node_modules/zca-js/dist/apis/disperseGroup.d.ts +2 -0
  685. package/node_modules/zca-js/dist/apis/disperseGroup.js +28 -0
  686. package/node_modules/zca-js/dist/apis/editNote.d.ts +17 -0
  687. package/node_modules/zca-js/dist/apis/editNote.js +46 -0
  688. package/node_modules/zca-js/dist/apis/editReminder.d.ts +13 -0
  689. package/node_modules/zca-js/dist/apis/editReminder.js +61 -0
  690. package/node_modules/zca-js/dist/apis/enableGroupLink.d.ts +6 -0
  691. package/node_modules/zca-js/dist/apis/enableGroupLink.js +25 -0
  692. package/node_modules/zca-js/dist/apis/fetchAccountInfo.d.ts +5 -0
  693. package/node_modules/zca-js/dist/apis/fetchAccountInfo.js +10 -0
  694. package/node_modules/zca-js/dist/apis/findUser.d.ts +3 -0
  695. package/node_modules/zca-js/dist/apis/findUser.js +42 -0
  696. package/node_modules/zca-js/dist/apis/findUserByUsername.d.ts +3 -0
  697. package/node_modules/zca-js/dist/apis/findUserByUsername.js +27 -0
  698. package/node_modules/zca-js/dist/apis/forwardMessage.d.ts +24 -0
  699. package/node_modules/zca-js/dist/apis/forwardMessage.js +114 -0
  700. package/node_modules/zca-js/dist/apis/getAliasList.d.ts +8 -0
  701. package/node_modules/zca-js/dist/apis/getAliasList.js +27 -0
  702. package/node_modules/zca-js/dist/apis/getAllFriends.d.ts +3 -0
  703. package/node_modules/zca-js/dist/apis/getAllFriends.js +34 -0
  704. package/node_modules/zca-js/dist/apis/getAllGroups.d.ts +7 -0
  705. package/node_modules/zca-js/dist/apis/getAllGroups.js +10 -0
  706. package/node_modules/zca-js/dist/apis/getArchivedChatList.d.ts +5 -0
  707. package/node_modules/zca-js/dist/apis/getArchivedChatList.js +23 -0
  708. package/node_modules/zca-js/dist/apis/getAutoDeleteChat.d.ts +9 -0
  709. package/node_modules/zca-js/dist/apis/getAutoDeleteChat.js +21 -0
  710. package/node_modules/zca-js/dist/apis/getAutoReplyList.d.ts +6 -0
  711. package/node_modules/zca-js/dist/apis/getAutoReplyList.js +24 -0
  712. package/node_modules/zca-js/dist/apis/getAvatarList.d.ts +12 -0
  713. package/node_modules/zca-js/dist/apis/getAvatarList.js +28 -0
  714. package/node_modules/zca-js/dist/apis/getAvatarUrlProfile.d.ts +7 -0
  715. package/node_modules/zca-js/dist/apis/getAvatarUrlProfile.js +30 -0
  716. package/node_modules/zca-js/dist/apis/getBizAccount.d.ts +24 -0
  717. package/node_modules/zca-js/dist/apis/getBizAccount.js +27 -0
  718. package/node_modules/zca-js/dist/apis/getCatalogList.d.ts +18 -0
  719. package/node_modules/zca-js/dist/apis/getCatalogList.js +32 -0
  720. package/node_modules/zca-js/dist/apis/getCloseFriends.d.ts +3 -0
  721. package/node_modules/zca-js/dist/apis/getCloseFriends.js +20 -0
  722. package/node_modules/zca-js/dist/apis/getContext.d.ts +1 -0
  723. package/node_modules/zca-js/dist/apis/getContext.js +4 -0
  724. package/node_modules/zca-js/dist/apis/getCookie.d.ts +1 -0
  725. package/node_modules/zca-js/dist/apis/getCookie.js +9 -0
  726. package/node_modules/zca-js/dist/apis/getCrossDB.js +18 -0
  727. package/node_modules/zca-js/dist/apis/getFriendBoardList.d.ts +5 -0
  728. package/node_modules/zca-js/dist/apis/getFriendBoardList.js +26 -0
  729. package/node_modules/zca-js/dist/apis/getFriendOnlines.d.ts +10 -0
  730. package/node_modules/zca-js/dist/apis/getFriendOnlines.js +35 -0
  731. package/node_modules/zca-js/dist/apis/getFriendRecommendations.d.ts +42 -0
  732. package/node_modules/zca-js/dist/apis/getFriendRecommendations.js +27 -0
  733. package/node_modules/zca-js/dist/apis/getFriendRequestStatus.d.ts +8 -0
  734. package/node_modules/zca-js/dist/apis/getFriendRequestStatus.js +25 -0
  735. package/node_modules/zca-js/dist/apis/getFullAvatar.d.ts +5 -0
  736. package/node_modules/zca-js/dist/apis/getFullAvatar.js +25 -0
  737. package/node_modules/zca-js/dist/apis/getGroupBlockedMember.d.ts +23 -0
  738. package/node_modules/zca-js/dist/apis/getGroupBlockedMember.js +29 -0
  739. package/node_modules/zca-js/dist/apis/getGroupChatHistory.d.ts +8 -0
  740. package/node_modules/zca-js/dist/apis/getGroupChatHistory.js +36 -0
  741. package/node_modules/zca-js/dist/apis/getGroupInfo.d.ts +16 -0
  742. package/node_modules/zca-js/dist/apis/getGroupInfo.js +32 -0
  743. package/node_modules/zca-js/dist/apis/getGroupInviteBoxInfo.d.ts +32 -0
  744. package/node_modules/zca-js/dist/apis/getGroupInviteBoxInfo.js +38 -0
  745. package/node_modules/zca-js/dist/apis/getGroupInviteBoxList.d.ts +38 -0
  746. package/node_modules/zca-js/dist/apis/getGroupInviteBoxList.js +31 -0
  747. package/node_modules/zca-js/dist/apis/getGroupLinkDetail.d.ts +9 -0
  748. package/node_modules/zca-js/dist/apis/getGroupLinkDetail.js +25 -0
  749. package/node_modules/zca-js/dist/apis/getGroupLinkInfo.d.ts +34 -0
  750. package/node_modules/zca-js/dist/apis/getGroupLinkInfo.js +28 -0
  751. package/node_modules/zca-js/dist/apis/getGroupMembersInfo.d.ts +17 -0
  752. package/node_modules/zca-js/dist/apis/getGroupMembersInfo.js +24 -0
  753. package/node_modules/zca-js/dist/apis/getHiddenConversations.d.ts +11 -0
  754. package/node_modules/zca-js/dist/apis/getHiddenConversations.js +23 -0
  755. package/node_modules/zca-js/dist/apis/getLabels.d.ts +7 -0
  756. package/node_modules/zca-js/dist/apis/getLabels.js +28 -0
  757. package/node_modules/zca-js/dist/apis/getListBank.d.ts +5 -0
  758. package/node_modules/zca-js/dist/apis/getListBank.js +20 -0
  759. package/node_modules/zca-js/dist/apis/getListBankAccount.d.ts +7 -0
  760. package/node_modules/zca-js/dist/apis/getListBankAccount.js +27 -0
  761. package/node_modules/zca-js/dist/apis/getListBoard.d.ts +21 -0
  762. package/node_modules/zca-js/dist/apis/getListBoard.js +45 -0
  763. package/node_modules/zca-js/dist/apis/getListDevice.d.ts +10 -0
  764. package/node_modules/zca-js/dist/apis/getListDevice.js +22 -0
  765. package/node_modules/zca-js/dist/apis/getListReminder.d.ts +28 -0
  766. package/node_modules/zca-js/dist/apis/getListReminder.js +47 -0
  767. package/node_modules/zca-js/dist/apis/getMultiUsersByPhones.d.ts +5 -0
  768. package/node_modules/zca-js/dist/apis/getMultiUsersByPhones.js +39 -0
  769. package/node_modules/zca-js/dist/apis/getMute.d.ts +13 -0
  770. package/node_modules/zca-js/dist/apis/getMute.js +22 -0
  771. package/node_modules/zca-js/dist/apis/getOwnId.d.ts +1 -0
  772. package/node_modules/zca-js/dist/apis/getOwnId.js +4 -0
  773. package/node_modules/zca-js/dist/apis/getPendingGroupMembers.d.ts +11 -0
  774. package/node_modules/zca-js/dist/apis/getPendingGroupMembers.js +27 -0
  775. package/node_modules/zca-js/dist/apis/getPinConversations.d.ts +5 -0
  776. package/node_modules/zca-js/dist/apis/getPinConversations.js +22 -0
  777. package/node_modules/zca-js/dist/apis/getPollDetail.d.ts +3 -0
  778. package/node_modules/zca-js/dist/apis/getPollDetail.js +30 -0
  779. package/node_modules/zca-js/dist/apis/getProductCatalogList.d.ts +20 -0
  780. package/node_modules/zca-js/dist/apis/getProductCatalogList.js +33 -0
  781. package/node_modules/zca-js/dist/apis/getQR.d.ts +4 -0
  782. package/node_modules/zca-js/dist/apis/getQR.js +29 -0
  783. package/node_modules/zca-js/dist/apis/getQuickMessageList.d.ts +7 -0
  784. package/node_modules/zca-js/dist/apis/getQuickMessageList.js +24 -0
  785. package/node_modules/zca-js/dist/apis/getRelatedFriendGroup.d.ts +6 -0
  786. package/node_modules/zca-js/dist/apis/getRelatedFriendGroup.js +30 -0
  787. package/node_modules/zca-js/dist/apis/getReminder.d.ts +3 -0
  788. package/node_modules/zca-js/dist/apis/getReminder.js +25 -0
  789. package/node_modules/zca-js/dist/apis/getReminderResponses.d.ts +5 -0
  790. package/node_modules/zca-js/dist/apis/getReminderResponses.js +24 -0
  791. package/node_modules/zca-js/dist/apis/getSentFriendRequest.d.ts +18 -0
  792. package/node_modules/zca-js/dist/apis/getSentFriendRequest.js +24 -0
  793. package/node_modules/zca-js/dist/apis/getSettings.d.ts +3 -0
  794. package/node_modules/zca-js/dist/apis/getSettings.js +20 -0
  795. package/node_modules/zca-js/dist/apis/getStickerCategoryDetail.d.ts +3 -0
  796. package/node_modules/zca-js/dist/apis/getStickerCategoryDetail.js +24 -0
  797. package/node_modules/zca-js/dist/apis/getStickers.d.ts +1 -0
  798. package/node_modules/zca-js/dist/apis/getStickers.js +40 -0
  799. package/node_modules/zca-js/dist/apis/getStickersDetail.d.ts +3 -0
  800. package/node_modules/zca-js/dist/apis/getStickersDetail.js +40 -0
  801. package/node_modules/zca-js/dist/apis/getUnreadMark.d.ts +14 -0
  802. package/node_modules/zca-js/dist/apis/getUnreadMark.js +30 -0
  803. package/node_modules/zca-js/dist/apis/getUserInfo.d.ts +8 -0
  804. package/node_modules/zca-js/dist/apis/getUserInfo.js +44 -0
  805. package/node_modules/zca-js/dist/apis/inviteUserToGroups.d.ts +10 -0
  806. package/node_modules/zca-js/dist/apis/inviteUserToGroups.js +30 -0
  807. package/node_modules/zca-js/dist/apis/joinGroupInviteBox.d.ts +2 -0
  808. package/node_modules/zca-js/dist/apis/joinGroupInviteBox.js +25 -0
  809. package/node_modules/zca-js/dist/apis/joinGroupLink.d.ts +2 -0
  810. package/node_modules/zca-js/dist/apis/joinGroupLink.js +27 -0
  811. package/node_modules/zca-js/dist/apis/keepAlive.d.ts +4 -0
  812. package/node_modules/zca-js/dist/apis/keepAlive.js +22 -0
  813. package/node_modules/zca-js/dist/apis/lastOnline.d.ts +7 -0
  814. package/node_modules/zca-js/dist/apis/lastOnline.js +26 -0
  815. package/node_modules/zca-js/dist/apis/leaveGroup.d.ts +4 -0
  816. package/node_modules/zca-js/dist/apis/leaveGroup.js +33 -0
  817. package/node_modules/zca-js/dist/apis/listen.d.ts +102 -0
  818. package/node_modules/zca-js/dist/apis/listen.js +425 -0
  819. package/node_modules/zca-js/dist/apis/lockPoll.d.ts +2 -0
  820. package/node_modules/zca-js/dist/apis/lockPoll.js +28 -0
  821. package/node_modules/zca-js/dist/apis/login.d.ts +3 -0
  822. package/node_modules/zca-js/dist/apis/login.js +96 -0
  823. package/node_modules/zca-js/dist/apis/loginQR.d.ts +71 -0
  824. package/node_modules/zca-js/dist/apis/loginQR.js +376 -0
  825. package/node_modules/zca-js/dist/apis/logoutV2.js +79 -0
  826. package/node_modules/zca-js/dist/apis/lostFocus.d.ts +4 -0
  827. package/node_modules/zca-js/dist/apis/lostFocus.js +23 -0
  828. package/node_modules/zca-js/dist/apis/parseLink.d.ts +21 -0
  829. package/node_modules/zca-js/dist/apis/parseLink.js +27 -0
  830. package/node_modules/zca-js/dist/apis/pullMobileMsg.js +22 -0
  831. package/node_modules/zca-js/dist/apis/registerCatalog.d.ts +2 -0
  832. package/node_modules/zca-js/dist/apis/registerCatalog.js +27 -0
  833. package/node_modules/zca-js/dist/apis/rejectFriendRequest.d.ts +2 -0
  834. package/node_modules/zca-js/dist/apis/rejectFriendRequest.js +27 -0
  835. package/node_modules/zca-js/dist/apis/removeFriend.d.ts +2 -0
  836. package/node_modules/zca-js/dist/apis/removeFriend.js +28 -0
  837. package/node_modules/zca-js/dist/apis/removeFriendAlias.d.ts +2 -0
  838. package/node_modules/zca-js/dist/apis/removeFriendAlias.js +24 -0
  839. package/node_modules/zca-js/dist/apis/removeGroupBlockedMember.d.ts +2 -0
  840. package/node_modules/zca-js/dist/apis/removeGroupBlockedMember.js +28 -0
  841. package/node_modules/zca-js/dist/apis/removeGroupDeputy.d.ts +2 -0
  842. package/node_modules/zca-js/dist/apis/removeGroupDeputy.js +30 -0
  843. package/node_modules/zca-js/dist/apis/removeQuickMessage.d.ts +5 -0
  844. package/node_modules/zca-js/dist/apis/removeQuickMessage.js +27 -0
  845. package/node_modules/zca-js/dist/apis/removeReminder.d.ts +3 -0
  846. package/node_modules/zca-js/dist/apis/removeReminder.js +40 -0
  847. package/node_modules/zca-js/dist/apis/removeUnreadMark.d.ts +8 -0
  848. package/node_modules/zca-js/dist/apis/removeUnreadMark.js +50 -0
  849. package/node_modules/zca-js/dist/apis/removeUserFromGroup.d.ts +4 -0
  850. package/node_modules/zca-js/dist/apis/removeUserFromGroup.js +34 -0
  851. package/node_modules/zca-js/dist/apis/requestSyncMessage.js +18 -0
  852. package/node_modules/zca-js/dist/apis/resetHiddenConversPin.d.ts +2 -0
  853. package/node_modules/zca-js/dist/apis/resetHiddenConversPin.js +20 -0
  854. package/node_modules/zca-js/dist/apis/reuseAvatar.d.ts +2 -0
  855. package/node_modules/zca-js/dist/apis/reuseAvatar.js +26 -0
  856. package/node_modules/zca-js/dist/apis/reviewPendingMemberRequest.d.ts +14 -0
  857. package/node_modules/zca-js/dist/apis/reviewPendingMemberRequest.js +38 -0
  858. package/node_modules/zca-js/dist/apis/scanURL.d.ts +4 -0
  859. package/node_modules/zca-js/dist/apis/scanURL.js +28 -0
  860. package/node_modules/zca-js/dist/apis/searchSticker.d.ts +3 -0
  861. package/node_modules/zca-js/dist/apis/searchSticker.js +28 -0
  862. package/node_modules/zca-js/dist/apis/sendBankCard.d.ts +9 -0
  863. package/node_modules/zca-js/dist/apis/sendBankCard.js +53 -0
  864. package/node_modules/zca-js/dist/apis/sendCard.d.ts +10 -0
  865. package/node_modules/zca-js/dist/apis/sendCard.js +75 -0
  866. package/node_modules/zca-js/dist/apis/sendDeliveredEvent.d.ts +16 -0
  867. package/node_modules/zca-js/dist/apis/sendDeliveredEvent.js +55 -0
  868. package/node_modules/zca-js/dist/apis/sendFriendRequest.d.ts +2 -0
  869. package/node_modules/zca-js/dist/apis/sendFriendRequest.js +39 -0
  870. package/node_modules/zca-js/dist/apis/sendLink.d.ts +10 -0
  871. package/node_modules/zca-js/dist/apis/sendLink.js +78 -0
  872. package/node_modules/zca-js/dist/apis/sendMessage.d.ts +105 -0
  873. package/node_modules/zca-js/dist/apis/sendMessage.js +486 -0
  874. package/node_modules/zca-js/dist/apis/sendReport.d.ts +17 -0
  875. package/node_modules/zca-js/dist/apis/sendReport.js +53 -0
  876. package/node_modules/zca-js/dist/apis/sendSeenEvent.d.ts +16 -0
  877. package/node_modules/zca-js/dist/apis/sendSeenEvent.js +63 -0
  878. package/node_modules/zca-js/dist/apis/sendSticker.d.ts +10 -0
  879. package/node_modules/zca-js/dist/apis/sendSticker.js +74 -0
  880. package/node_modules/zca-js/dist/apis/sendTypingEvent.d.ts +5 -0
  881. package/node_modules/zca-js/dist/apis/sendTypingEvent.js +33 -0
  882. package/node_modules/zca-js/dist/apis/sendVideo.d.ts +35 -0
  883. package/node_modules/zca-js/dist/apis/sendVideo.js +134 -0
  884. package/node_modules/zca-js/dist/apis/sendVoice.d.ts +12 -0
  885. package/node_modules/zca-js/dist/apis/sendVoice.js +89 -0
  886. package/node_modules/zca-js/dist/apis/setHiddenConversations.d.ts +3 -0
  887. package/node_modules/zca-js/dist/apis/setHiddenConversations.js +39 -0
  888. package/node_modules/zca-js/dist/apis/setMute.d.ts +20 -0
  889. package/node_modules/zca-js/dist/apis/setMute.js +67 -0
  890. package/node_modules/zca-js/dist/apis/setPinnedConversations.d.ts +3 -0
  891. package/node_modules/zca-js/dist/apis/setPinnedConversations.js +34 -0
  892. package/node_modules/zca-js/dist/apis/sharePoll.d.ts +2 -0
  893. package/node_modules/zca-js/dist/apis/sharePoll.js +28 -0
  894. package/node_modules/zca-js/dist/apis/unblockUser.d.ts +2 -0
  895. package/node_modules/zca-js/dist/apis/unblockUser.js +28 -0
  896. package/node_modules/zca-js/dist/apis/undo.d.ts +9 -0
  897. package/node_modules/zca-js/dist/apis/undo.js +42 -0
  898. package/node_modules/zca-js/dist/apis/undoFriendRequest.d.ts +2 -0
  899. package/node_modules/zca-js/dist/apis/undoFriendRequest.js +27 -0
  900. package/node_modules/zca-js/dist/apis/updateActiveStatus.d.ts +4 -0
  901. package/node_modules/zca-js/dist/apis/updateActiveStatus.js +27 -0
  902. package/node_modules/zca-js/dist/apis/updateArchivedChatList.d.ts +10 -0
  903. package/node_modules/zca-js/dist/apis/updateArchivedChatList.js +34 -0
  904. package/node_modules/zca-js/dist/apis/updateAutoDeleteChat.d.ts +9 -0
  905. package/node_modules/zca-js/dist/apis/updateAutoDeleteChat.js +40 -0
  906. package/node_modules/zca-js/dist/apis/updateAutoReply.d.ts +15 -0
  907. package/node_modules/zca-js/dist/apis/updateAutoReply.js +38 -0
  908. package/node_modules/zca-js/dist/apis/updateBankAccount.d.ts +9 -0
  909. package/node_modules/zca-js/dist/apis/updateBankAccount.js +31 -0
  910. package/node_modules/zca-js/dist/apis/updateCatalog.d.ts +11 -0
  911. package/node_modules/zca-js/dist/apis/updateCatalog.js +30 -0
  912. package/node_modules/zca-js/dist/apis/updateGroupSettings.d.ts +40 -0
  913. package/node_modules/zca-js/dist/apis/updateGroupSettings.js +43 -0
  914. package/node_modules/zca-js/dist/apis/updateHiddenConversPin.d.ts +2 -0
  915. package/node_modules/zca-js/dist/apis/updateHiddenConversPin.js +30 -0
  916. package/node_modules/zca-js/dist/apis/updateLabels.d.ts +15 -0
  917. package/node_modules/zca-js/dist/apis/updateLabels.js +34 -0
  918. package/node_modules/zca-js/dist/apis/updateLang.d.ts +6 -0
  919. package/node_modules/zca-js/dist/apis/updateLang.js +30 -0
  920. package/node_modules/zca-js/dist/apis/updateProductCatalog.d.ts +25 -0
  921. package/node_modules/zca-js/dist/apis/updateProductCatalog.js +51 -0
  922. package/node_modules/zca-js/dist/apis/updateProfile.d.ts +20 -0
  923. package/node_modules/zca-js/dist/apis/updateProfile.js +43 -0
  924. package/node_modules/zca-js/dist/apis/updateProfileBio.d.ts +2 -0
  925. package/node_modules/zca-js/dist/apis/updateProfileBio.js +27 -0
  926. package/node_modules/zca-js/dist/apis/updateQuickMessage.d.ts +11 -0
  927. package/node_modules/zca-js/dist/apis/updateQuickMessage.js +61 -0
  928. package/node_modules/zca-js/dist/apis/updateSettings.d.ts +16 -0
  929. package/node_modules/zca-js/dist/apis/updateSettings.js +90 -0
  930. package/node_modules/zca-js/dist/apis/upgradeGroupToCommunity.d.ts +2 -0
  931. package/node_modules/zca-js/dist/apis/upgradeGroupToCommunity.js +27 -0
  932. package/node_modules/zca-js/dist/apis/uploadAttachment.d.ts +50 -0
  933. package/node_modules/zca-js/dist/apis/uploadAttachment.js +197 -0
  934. package/node_modules/zca-js/dist/apis/uploadProductPhoto.d.ts +14 -0
  935. package/node_modules/zca-js/dist/apis/uploadProductPhoto.js +50 -0
  936. package/node_modules/zca-js/dist/apis/votePoll.d.ts +5 -0
  937. package/node_modules/zca-js/dist/apis/votePoll.js +29 -0
  938. package/node_modules/zca-js/dist/apis.d.ts +317 -0
  939. package/node_modules/zca-js/dist/apis.js +327 -0
  940. package/node_modules/zca-js/dist/cjs/Errors/ZaloApiError.cjs +11 -0
  941. package/node_modules/zca-js/dist/cjs/Errors/ZaloApiLoginQRAborted.cjs +12 -0
  942. package/node_modules/zca-js/dist/cjs/Errors/ZaloApiLoginQRDeclined.cjs +12 -0
  943. package/node_modules/zca-js/dist/cjs/Errors/ZaloApiMissingImageMetadataGetter.cjs +12 -0
  944. package/node_modules/zca-js/dist/cjs/apis/acceptFriendRequest.cjs +33 -0
  945. package/node_modules/zca-js/dist/cjs/apis/addGroupBlockedMember.cjs +33 -0
  946. package/node_modules/zca-js/dist/cjs/apis/addGroupDeputy.cjs +35 -0
  947. package/node_modules/zca-js/dist/cjs/apis/addPollOptions.cjs +31 -0
  948. package/node_modules/zca-js/dist/cjs/apis/addQuickMessage.cjs +65 -0
  949. package/node_modules/zca-js/dist/cjs/apis/addReaction.cjs +308 -0
  950. package/node_modules/zca-js/dist/cjs/apis/addUnreadMark.cjs +66 -0
  951. package/node_modules/zca-js/dist/cjs/apis/addUserToGroup.cjs +39 -0
  952. package/node_modules/zca-js/dist/cjs/apis/blockUser.cjs +33 -0
  953. package/node_modules/zca-js/dist/cjs/apis/blockViewFeed.cjs +35 -0
  954. package/node_modules/zca-js/dist/cjs/apis/changeAccountAvatar.cjs +57 -0
  955. package/node_modules/zca-js/dist/cjs/apis/changeFriendAlias.cjs +32 -0
  956. package/node_modules/zca-js/dist/cjs/apis/changeGroupAvatar.cjs +49 -0
  957. package/node_modules/zca-js/dist/cjs/apis/changeGroupName.cjs +37 -0
  958. package/node_modules/zca-js/dist/cjs/apis/changeGroupOwner.cjs +35 -0
  959. package/node_modules/zca-js/dist/cjs/apis/createAutoReply.cjs +42 -0
  960. package/node_modules/zca-js/dist/cjs/apis/createBankAccount.cjs +37 -0
  961. package/node_modules/zca-js/dist/cjs/apis/createCatalog.cjs +34 -0
  962. package/node_modules/zca-js/dist/cjs/apis/createGroup.cjs +48 -0
  963. package/node_modules/zca-js/dist/cjs/apis/createNote.cjs +52 -0
  964. package/node_modules/zca-js/dist/cjs/apis/createPoll.cjs +45 -0
  965. package/node_modules/zca-js/dist/cjs/apis/createProductCatalog.cjs +55 -0
  966. package/node_modules/zca-js/dist/cjs/apis/createReminder.cjs +77 -0
  967. package/node_modules/zca-js/dist/cjs/apis/custom.cjs +19 -0
  968. package/node_modules/zca-js/dist/cjs/apis/deleteAutoReply.cjs +34 -0
  969. package/node_modules/zca-js/dist/cjs/apis/deleteAvatar.cjs +32 -0
  970. package/node_modules/zca-js/dist/cjs/apis/deleteBankAccount.cjs +37 -0
  971. package/node_modules/zca-js/dist/cjs/apis/deleteCatalog.cjs +33 -0
  972. package/node_modules/zca-js/dist/cjs/apis/deleteChat.cjs +64 -0
  973. package/node_modules/zca-js/dist/cjs/apis/deleteGroupInviteBox.cjs +32 -0
  974. package/node_modules/zca-js/dist/cjs/apis/deleteMessage.cjs +66 -0
  975. package/node_modules/zca-js/dist/cjs/apis/deleteProductCatalog.cjs +36 -0
  976. package/node_modules/zca-js/dist/cjs/apis/deleteSnapshotMobileMsg.cjs +22 -0
  977. package/node_modules/zca-js/dist/cjs/apis/disableGroupLink.cjs +29 -0
  978. package/node_modules/zca-js/dist/cjs/apis/disperseGroup.cjs +33 -0
  979. package/node_modules/zca-js/dist/cjs/apis/editNote.cjs +51 -0
  980. package/node_modules/zca-js/dist/cjs/apis/editReminder.cjs +75 -0
  981. package/node_modules/zca-js/dist/cjs/apis/enableGroupLink.cjs +30 -0
  982. package/node_modules/zca-js/dist/cjs/apis/fetchAccountInfo.cjs +15 -0
  983. package/node_modules/zca-js/dist/cjs/apis/findUser.cjs +56 -0
  984. package/node_modules/zca-js/dist/cjs/apis/findUserByUsername.cjs +41 -0
  985. package/node_modules/zca-js/dist/cjs/apis/forwardMessage.cjs +129 -0
  986. package/node_modules/zca-js/dist/cjs/apis/getAliasList.cjs +32 -0
  987. package/node_modules/zca-js/dist/cjs/apis/getAllFriends.cjs +48 -0
  988. package/node_modules/zca-js/dist/cjs/apis/getAllGroups.cjs +15 -0
  989. package/node_modules/zca-js/dist/cjs/apis/getArchivedChatList.cjs +28 -0
  990. package/node_modules/zca-js/dist/cjs/apis/getAutoDeleteChat.cjs +26 -0
  991. package/node_modules/zca-js/dist/cjs/apis/getAutoReplyList.cjs +29 -0
  992. package/node_modules/zca-js/dist/cjs/apis/getAvatarList.cjs +33 -0
  993. package/node_modules/zca-js/dist/cjs/apis/getAvatarUrlProfile.cjs +44 -0
  994. package/node_modules/zca-js/dist/cjs/apis/getBizAccount.cjs +32 -0
  995. package/node_modules/zca-js/dist/cjs/apis/getCatalogList.cjs +37 -0
  996. package/node_modules/zca-js/dist/cjs/apis/getCloseFriends.cjs +25 -0
  997. package/node_modules/zca-js/dist/cjs/apis/getContext.cjs +9 -0
  998. package/node_modules/zca-js/dist/cjs/apis/getCookie.cjs +14 -0
  999. package/node_modules/zca-js/dist/cjs/apis/getCrossDB.cjs +22 -0
  1000. package/node_modules/zca-js/dist/cjs/apis/getFriendBoardList.cjs +31 -0
  1001. package/node_modules/zca-js/dist/cjs/apis/getFriendOnlines.cjs +40 -0
  1002. package/node_modules/zca-js/dist/cjs/apis/getFriendRecommendations.cjs +32 -0
  1003. package/node_modules/zca-js/dist/cjs/apis/getFriendRequestStatus.cjs +30 -0
  1004. package/node_modules/zca-js/dist/cjs/apis/getFullAvatar.cjs +30 -0
  1005. package/node_modules/zca-js/dist/cjs/apis/getGroupBlockedMember.cjs +34 -0
  1006. package/node_modules/zca-js/dist/cjs/apis/getGroupChatHistory.cjs +51 -0
  1007. package/node_modules/zca-js/dist/cjs/apis/getGroupInfo.cjs +37 -0
  1008. package/node_modules/zca-js/dist/cjs/apis/getGroupInviteBoxInfo.cjs +43 -0
  1009. package/node_modules/zca-js/dist/cjs/apis/getGroupInviteBoxList.cjs +36 -0
  1010. package/node_modules/zca-js/dist/cjs/apis/getGroupLinkDetail.cjs +30 -0
  1011. package/node_modules/zca-js/dist/cjs/apis/getGroupLinkInfo.cjs +33 -0
  1012. package/node_modules/zca-js/dist/cjs/apis/getGroupMembersInfo.cjs +29 -0
  1013. package/node_modules/zca-js/dist/cjs/apis/getHiddenConversations.cjs +28 -0
  1014. package/node_modules/zca-js/dist/cjs/apis/getLabels.cjs +33 -0
  1015. package/node_modules/zca-js/dist/cjs/apis/getListBank.cjs +25 -0
  1016. package/node_modules/zca-js/dist/cjs/apis/getListBankAccount.cjs +32 -0
  1017. package/node_modules/zca-js/dist/cjs/apis/getListBoard.cjs +59 -0
  1018. package/node_modules/zca-js/dist/cjs/apis/getListDevice.cjs +27 -0
  1019. package/node_modules/zca-js/dist/cjs/apis/getListReminder.cjs +61 -0
  1020. package/node_modules/zca-js/dist/cjs/apis/getMultiUsersByPhones.cjs +53 -0
  1021. package/node_modules/zca-js/dist/cjs/apis/getMute.cjs +27 -0
  1022. package/node_modules/zca-js/dist/cjs/apis/getOwnId.cjs +9 -0
  1023. package/node_modules/zca-js/dist/cjs/apis/getPendingGroupMembers.cjs +32 -0
  1024. package/node_modules/zca-js/dist/cjs/apis/getPinConversations.cjs +27 -0
  1025. package/node_modules/zca-js/dist/cjs/apis/getPollDetail.cjs +35 -0
  1026. package/node_modules/zca-js/dist/cjs/apis/getProductCatalogList.cjs +38 -0
  1027. package/node_modules/zca-js/dist/cjs/apis/getQR.cjs +34 -0
  1028. package/node_modules/zca-js/dist/cjs/apis/getQuickMessageList.cjs +29 -0
  1029. package/node_modules/zca-js/dist/cjs/apis/getRelatedFriendGroup.cjs +35 -0
  1030. package/node_modules/zca-js/dist/cjs/apis/getReminder.cjs +30 -0
  1031. package/node_modules/zca-js/dist/cjs/apis/getReminderResponses.cjs +29 -0
  1032. package/node_modules/zca-js/dist/cjs/apis/getSentFriendRequest.cjs +29 -0
  1033. package/node_modules/zca-js/dist/cjs/apis/getSettings.cjs +25 -0
  1034. package/node_modules/zca-js/dist/cjs/apis/getStickerCategoryDetail.cjs +29 -0
  1035. package/node_modules/zca-js/dist/cjs/apis/getStickers.cjs +45 -0
  1036. package/node_modules/zca-js/dist/cjs/apis/getStickersDetail.cjs +45 -0
  1037. package/node_modules/zca-js/dist/cjs/apis/getUnreadMark.cjs +35 -0
  1038. package/node_modules/zca-js/dist/cjs/apis/getUserInfo.cjs +58 -0
  1039. package/node_modules/zca-js/dist/cjs/apis/inviteUserToGroups.cjs +35 -0
  1040. package/node_modules/zca-js/dist/cjs/apis/joinGroupInviteBox.cjs +30 -0
  1041. package/node_modules/zca-js/dist/cjs/apis/joinGroupLink.cjs +32 -0
  1042. package/node_modules/zca-js/dist/cjs/apis/keepAlive.cjs +27 -0
  1043. package/node_modules/zca-js/dist/cjs/apis/lastOnline.cjs +31 -0
  1044. package/node_modules/zca-js/dist/cjs/apis/leaveGroup.cjs +38 -0
  1045. package/node_modules/zca-js/dist/cjs/apis/listen.cjs +440 -0
  1046. package/node_modules/zca-js/dist/cjs/apis/lockPoll.cjs +33 -0
  1047. package/node_modules/zca-js/dist/cjs/apis/login.cjs +102 -0
  1048. package/node_modules/zca-js/dist/cjs/apis/loginQR.cjs +368 -0
  1049. package/node_modules/zca-js/dist/cjs/apis/logoutV2.cjs +83 -0
  1050. package/node_modules/zca-js/dist/cjs/apis/lostFocus.cjs +28 -0
  1051. package/node_modules/zca-js/dist/cjs/apis/parseLink.cjs +32 -0
  1052. package/node_modules/zca-js/dist/cjs/apis/pullMobileMsg.cjs +26 -0
  1053. package/node_modules/zca-js/dist/cjs/apis/registerCatalog.cjs +32 -0
  1054. package/node_modules/zca-js/dist/cjs/apis/rejectFriendRequest.cjs +32 -0
  1055. package/node_modules/zca-js/dist/cjs/apis/removeFriend.cjs +33 -0
  1056. package/node_modules/zca-js/dist/cjs/apis/removeFriendAlias.cjs +29 -0
  1057. package/node_modules/zca-js/dist/cjs/apis/removeGroupBlockedMember.cjs +33 -0
  1058. package/node_modules/zca-js/dist/cjs/apis/removeGroupDeputy.cjs +35 -0
  1059. package/node_modules/zca-js/dist/cjs/apis/removeQuickMessage.cjs +32 -0
  1060. package/node_modules/zca-js/dist/cjs/apis/removeReminder.cjs +54 -0
  1061. package/node_modules/zca-js/dist/cjs/apis/removeUnreadMark.cjs +64 -0
  1062. package/node_modules/zca-js/dist/cjs/apis/removeUserFromGroup.cjs +39 -0
  1063. package/node_modules/zca-js/dist/cjs/apis/requestSyncMessage.cjs +22 -0
  1064. package/node_modules/zca-js/dist/cjs/apis/resetHiddenConversPin.cjs +25 -0
  1065. package/node_modules/zca-js/dist/cjs/apis/reuseAvatar.cjs +31 -0
  1066. package/node_modules/zca-js/dist/cjs/apis/reviewPendingMemberRequest.cjs +43 -0
  1067. package/node_modules/zca-js/dist/cjs/apis/scanURL.cjs +33 -0
  1068. package/node_modules/zca-js/dist/cjs/apis/searchSticker.cjs +33 -0
  1069. package/node_modules/zca-js/dist/cjs/apis/sendBankCard.cjs +68 -0
  1070. package/node_modules/zca-js/dist/cjs/apis/sendCard.cjs +89 -0
  1071. package/node_modules/zca-js/dist/cjs/apis/sendDeliveredEvent.cjs +69 -0
  1072. package/node_modules/zca-js/dist/cjs/apis/sendFriendRequest.cjs +44 -0
  1073. package/node_modules/zca-js/dist/cjs/apis/sendLink.cjs +92 -0
  1074. package/node_modules/zca-js/dist/cjs/apis/sendMessage.cjs +500 -0
  1075. package/node_modules/zca-js/dist/cjs/apis/sendReport.cjs +67 -0
  1076. package/node_modules/zca-js/dist/cjs/apis/sendSeenEvent.cjs +77 -0
  1077. package/node_modules/zca-js/dist/cjs/apis/sendSticker.cjs +88 -0
  1078. package/node_modules/zca-js/dist/cjs/apis/sendTypingEvent.cjs +47 -0
  1079. package/node_modules/zca-js/dist/cjs/apis/sendVideo.cjs +148 -0
  1080. package/node_modules/zca-js/dist/cjs/apis/sendVoice.cjs +103 -0
  1081. package/node_modules/zca-js/dist/cjs/apis/setHiddenConversations.cjs +53 -0
  1082. package/node_modules/zca-js/dist/cjs/apis/setMute.cjs +81 -0
  1083. package/node_modules/zca-js/dist/cjs/apis/setPinnedConversations.cjs +48 -0
  1084. package/node_modules/zca-js/dist/cjs/apis/sharePoll.cjs +33 -0
  1085. package/node_modules/zca-js/dist/cjs/apis/unblockUser.cjs +33 -0
  1086. package/node_modules/zca-js/dist/cjs/apis/undo.cjs +56 -0
  1087. package/node_modules/zca-js/dist/cjs/apis/undoFriendRequest.cjs +32 -0
  1088. package/node_modules/zca-js/dist/cjs/apis/updateActiveStatus.cjs +32 -0
  1089. package/node_modules/zca-js/dist/cjs/apis/updateArchivedChatList.cjs +39 -0
  1090. package/node_modules/zca-js/dist/cjs/apis/updateAutoDeleteChat.cjs +54 -0
  1091. package/node_modules/zca-js/dist/cjs/apis/updateAutoReply.cjs +43 -0
  1092. package/node_modules/zca-js/dist/cjs/apis/updateBankAccount.cjs +36 -0
  1093. package/node_modules/zca-js/dist/cjs/apis/updateCatalog.cjs +35 -0
  1094. package/node_modules/zca-js/dist/cjs/apis/updateGroupSettings.cjs +48 -0
  1095. package/node_modules/zca-js/dist/cjs/apis/updateHiddenConversPin.cjs +35 -0
  1096. package/node_modules/zca-js/dist/cjs/apis/updateLabels.cjs +39 -0
  1097. package/node_modules/zca-js/dist/cjs/apis/updateLang.cjs +35 -0
  1098. package/node_modules/zca-js/dist/cjs/apis/updateProductCatalog.cjs +56 -0
  1099. package/node_modules/zca-js/dist/cjs/apis/updateProfile.cjs +48 -0
  1100. package/node_modules/zca-js/dist/cjs/apis/updateProfileBio.cjs +32 -0
  1101. package/node_modules/zca-js/dist/cjs/apis/updateQuickMessage.cjs +66 -0
  1102. package/node_modules/zca-js/dist/cjs/apis/updateSettings.cjs +95 -0
  1103. package/node_modules/zca-js/dist/cjs/apis/upgradeGroupToCommunity.cjs +32 -0
  1104. package/node_modules/zca-js/dist/cjs/apis/uploadAttachment.cjs +211 -0
  1105. package/node_modules/zca-js/dist/cjs/apis/uploadProductPhoto.cjs +55 -0
  1106. package/node_modules/zca-js/dist/cjs/apis/votePoll.cjs +34 -0
  1107. package/node_modules/zca-js/dist/cjs/apis.cjs +332 -0
  1108. package/node_modules/zca-js/dist/cjs/context.cjs +34 -0
  1109. package/node_modules/zca-js/dist/cjs/index.cjs +159 -0
  1110. package/node_modules/zca-js/dist/cjs/models/AutoReply.cjs +9 -0
  1111. package/node_modules/zca-js/dist/cjs/models/Bank.cjs +263 -0
  1112. package/node_modules/zca-js/dist/cjs/models/Board.cjs +8 -0
  1113. package/node_modules/zca-js/dist/cjs/models/DeliveredMessage.cjs +23 -0
  1114. package/node_modules/zca-js/dist/cjs/models/Enum.cjs +27 -0
  1115. package/node_modules/zca-js/dist/cjs/models/FriendEvent.cjs +87 -0
  1116. package/node_modules/zca-js/dist/cjs/models/Group.cjs +13 -0
  1117. package/node_modules/zca-js/dist/cjs/models/GroupEvent.cjs +94 -0
  1118. package/node_modules/zca-js/dist/cjs/models/Message.cjs +35 -0
  1119. package/node_modules/zca-js/dist/cjs/models/Reaction.cjs +74 -0
  1120. package/node_modules/zca-js/dist/cjs/models/Reminder.cjs +9 -0
  1121. package/node_modules/zca-js/dist/cjs/models/SeenMessage.cjs +23 -0
  1122. package/node_modules/zca-js/dist/cjs/models/Typing.cjs +23 -0
  1123. package/node_modules/zca-js/dist/cjs/models/Undo.cjs +16 -0
  1124. package/node_modules/zca-js/dist/cjs/models/ZBusiness.cjs +39 -0
  1125. package/node_modules/zca-js/dist/cjs/update.cjs +34 -0
  1126. package/node_modules/zca-js/dist/cjs/utils.cjs +703 -0
  1127. package/node_modules/zca-js/dist/cjs/zalo.cjs +112 -0
  1128. package/node_modules/zca-js/dist/context.d.ts +179 -0
  1129. package/node_modules/zca-js/dist/context.js +28 -0
  1130. package/node_modules/zca-js/dist/index.d.ts +166 -0
  1131. package/node_modules/zca-js/dist/index.js +14 -0
  1132. package/node_modules/zca-js/dist/models/Attachment.d.ts +9 -0
  1133. package/node_modules/zca-js/dist/models/Attachment.js +1 -0
  1134. package/node_modules/zca-js/dist/models/AutoReply.d.ts +20 -0
  1135. package/node_modules/zca-js/dist/models/AutoReply.js +7 -0
  1136. package/node_modules/zca-js/dist/models/Bank.d.ts +291 -0
  1137. package/node_modules/zca-js/dist/models/Bank.js +262 -0
  1138. package/node_modules/zca-js/dist/models/Board.d.ts +60 -0
  1139. package/node_modules/zca-js/dist/models/Board.js +6 -0
  1140. package/node_modules/zca-js/dist/models/Catalog.d.ts +16 -0
  1141. package/node_modules/zca-js/dist/models/Catalog.js +1 -0
  1142. package/node_modules/zca-js/dist/models/DeliveredMessage.d.ts +27 -0
  1143. package/node_modules/zca-js/dist/models/DeliveredMessage.js +17 -0
  1144. package/node_modules/zca-js/dist/models/Enum.d.ts +21 -0
  1145. package/node_modules/zca-js/dist/models/Enum.js +25 -0
  1146. package/node_modules/zca-js/dist/models/FriendEvent.d.ts +107 -0
  1147. package/node_modules/zca-js/dist/models/FriendEvent.js +83 -0
  1148. package/node_modules/zca-js/dist/models/Group.d.ts +125 -0
  1149. package/node_modules/zca-js/dist/models/Group.js +11 -0
  1150. package/node_modules/zca-js/dist/models/GroupEvent.d.ts +178 -0
  1151. package/node_modules/zca-js/dist/models/GroupEvent.js +90 -0
  1152. package/node_modules/zca-js/dist/models/Label.d.ts +10 -0
  1153. package/node_modules/zca-js/dist/models/Label.js +1 -0
  1154. package/node_modules/zca-js/dist/models/Message.d.ts +91 -0
  1155. package/node_modules/zca-js/dist/models/Message.js +29 -0
  1156. package/node_modules/zca-js/dist/models/ProductCatalog.d.ts +17 -0
  1157. package/node_modules/zca-js/dist/models/ProductCatalog.js +1 -0
  1158. package/node_modules/zca-js/dist/models/QuickMessage.d.ts +25 -0
  1159. package/node_modules/zca-js/dist/models/QuickMessage.js +1 -0
  1160. package/node_modules/zca-js/dist/models/Reaction.d.ts +85 -0
  1161. package/node_modules/zca-js/dist/models/Reaction.js +70 -0
  1162. package/node_modules/zca-js/dist/models/Reminder.d.ts +51 -0
  1163. package/node_modules/zca-js/dist/models/Reminder.js +7 -0
  1164. package/node_modules/zca-js/dist/models/SeenMessage.d.ts +26 -0
  1165. package/node_modules/zca-js/dist/models/SeenMessage.js +17 -0
  1166. package/node_modules/zca-js/dist/models/Sticker.d.ts +27 -0
  1167. package/node_modules/zca-js/dist/models/Sticker.js +1 -0
  1168. package/node_modules/zca-js/dist/models/Typing.d.ts +24 -0
  1169. package/node_modules/zca-js/dist/models/Typing.js +17 -0
  1170. package/node_modules/zca-js/dist/models/Undo.d.ts +34 -0
  1171. package/node_modules/zca-js/dist/models/Undo.js +12 -0
  1172. package/node_modules/zca-js/dist/models/User.d.ts +70 -0
  1173. package/node_modules/zca-js/dist/models/User.js +1 -0
  1174. package/node_modules/zca-js/dist/models/ZBusiness.d.ts +22 -0
  1175. package/node_modules/zca-js/dist/models/ZBusiness.js +35 -0
  1176. package/node_modules/zca-js/dist/models/index.d.ts +22 -0
  1177. package/node_modules/zca-js/dist/models/index.js +22 -0
  1178. package/node_modules/zca-js/dist/update.d.ts +2 -0
  1179. package/node_modules/zca-js/dist/update.js +29 -0
  1180. package/node_modules/zca-js/dist/utils.d.ts +167 -0
  1181. package/node_modules/zca-js/dist/utils.js +719 -0
  1182. package/node_modules/zca-js/dist/zalo.d.ts +41 -0
  1183. package/node_modules/zca-js/dist/zalo.js +107 -0
  1184. package/node_modules/zca-js/eslint.config.js +21 -0
  1185. package/node_modules/zca-js/index.d.ts +2 -0
  1186. package/node_modules/zca-js/package.json +78 -0
  1187. package/node_modules/zca-js/rollup.config.js +28 -0
  1188. package/package.json +80 -62
  1189. package/patches/zca-js+2.2.0.patch +1677 -0
  1190. package/src/cli.test.js +34 -5
  1191. package/src/commands/account.js +98 -5
  1192. package/src/commands/auto-reply.js +30 -10
  1193. package/src/commands/catalog.js +5 -4
  1194. package/src/commands/conv.js +551 -14
  1195. package/src/commands/friend.js +19 -7
  1196. package/src/commands/group.js +82 -31
  1197. package/src/commands/listen.js +624 -68
  1198. package/src/commands/login.js +179 -20
  1199. package/src/commands/mcp.js +422 -44
  1200. package/src/commands/msg.js +1288 -140
  1201. package/src/commands/oa-listen.js +130 -20
  1202. package/src/commands/oa.js +26 -5
  1203. package/src/commands/poll.js +7 -2
  1204. package/src/commands/profile.js +3 -2
  1205. package/src/commands/sync.js +2052 -0
  1206. package/src/core/accounts.js +69 -6
  1207. package/src/core/cached-message.js +200 -0
  1208. package/src/core/coverage.js +90 -0
  1209. package/src/core/current-user-names.js +104 -0
  1210. package/src/core/daemon-account.js +61 -0
  1211. package/src/core/daemon-channel.js +638 -0
  1212. package/src/core/daemon-sync.js +181 -0
  1213. package/src/core/db.js +1625 -0
  1214. package/src/core/forward.js +112 -0
  1215. package/src/core/group-history.js +248 -0
  1216. package/src/core/group-members.js +68 -0
  1217. package/src/core/group-settings.js +250 -0
  1218. package/src/core/history-fetch.js +208 -0
  1219. package/src/core/listener-lifecycle.js +90 -0
  1220. package/src/core/live-api.js +47 -0
  1221. package/src/core/live-store.js +733 -0
  1222. package/src/core/lock.js +129 -0
  1223. package/src/core/logout.js +289 -0
  1224. package/src/core/offline-queue.js +194 -0
  1225. package/src/core/pin.js +222 -0
  1226. package/src/core/read-state.js +318 -0
  1227. package/src/core/receipts.js +679 -0
  1228. package/src/core/recent-conversations.js +30 -0
  1229. package/src/core/self-heal.js +522 -0
  1230. package/src/core/socket-tap.js +154 -0
  1231. package/src/core/sync-v2/assets.js +181 -0
  1232. package/src/core/sync-v2/board.js +338 -0
  1233. package/src/core/sync-v2/conv-state.js +152 -0
  1234. package/src/core/sync-v2/gap-advice.js +110 -0
  1235. package/src/core/sync-v2/gid.js +106 -0
  1236. package/src/core/sync-v2/index.js +1259 -0
  1237. package/src/core/sync-v2/keepalive.js +177 -0
  1238. package/src/core/sync-v2/media.js +704 -0
  1239. package/src/core/sync-v2/message-types.js +522 -0
  1240. package/src/core/sync-v2/plan.js +95 -0
  1241. package/src/core/sync-v2/reactions.js +236 -0
  1242. package/src/core/sync-v2/renewlink.js +124 -0
  1243. package/src/core/sync-v2/senders.js +61 -0
  1244. package/src/core/sync-v2/zcloud-cipher.js +88 -0
  1245. package/src/core/sync-v2/zcloud.js +675 -0
  1246. package/src/core/sync.js +540 -0
  1247. package/src/core/zalo-client.js +179 -61
  1248. package/src/core/zca-custom.js +78 -0
  1249. package/src/index.js +15 -3
  1250. package/src/mcp/mcp-config.js +40 -3
  1251. package/src/mcp/mcp-http-transport.js +12 -2
  1252. package/src/mcp/mcp-server.js +5 -2
  1253. package/src/mcp/mcp-tools.js +969 -99
  1254. package/src/mcp/message-buffer.js +38 -8
  1255. package/src/mcp/message-buffer.test.js +67 -15
  1256. package/src/mcp/notifier.js +17 -1
  1257. package/src/mcp/notifier.test.js +6 -0
  1258. package/src/mcp/sync-jobs.js +82 -0
  1259. package/src/mcp/thread-name-cache.js +14 -1
  1260. package/src/mcp/thread-name-cache.test.js +4 -1
  1261. package/src/utils/bank-helpers.js +8 -3
  1262. package/src/utils/device-fingerprint.js +72 -0
  1263. package/src/utils/mentions.js +140 -0
  1264. package/src/utils/my-documents.js +95 -0
  1265. package/src/utils/open-file.js +49 -0
  1266. package/src/utils/output.js +75 -4
  1267. package/src/utils/parse-options.js +56 -0
  1268. package/src/utils/qr-http-server.js +44 -7
  1269. package/src/utils/quote.js +203 -0
  1270. package/src/utils/thread-type.js +72 -0
  1271. package/src/utils/update-check.js +42 -1
  1272. package/src/utils/urgency.js +29 -0
  1273. package/src/mcp/media-downloader.js +0 -191
  1274. package/src/mcp/media-downloader.test.js +0 -45
  1275. package/src/utils/qr-display.test.js +0 -97
@@ -0,0 +1,2052 @@
1
+ import { join } from "path";
2
+ import { getApi } from "../core/zalo-client.js";
3
+ import { getActive } from "../core/accounts.js";
4
+ import { CONFIG_DIR } from "../core/credentials.js";
5
+ import { acquireLock, releaseLock, checkLock } from "../core/lock.js";
6
+ import { error, info, success, warning, output } from "../utils/output.js";
7
+ import { parseIntAtLeast, parseIntOption } from "../utils/parse-options.js";
8
+ import { SyncManager } from "../core/sync.js";
9
+ import { SyncV2, resolveSyncWindow, FULL_HISTORY_FROM } from "../core/sync-v2/index.js";
10
+ import {
11
+ downloadSyncedMedia,
12
+ pruneDownloadedMedia,
13
+ describeDownloadReasons,
14
+ DOWNLOADABLE_KINDS,
15
+ } from "../core/sync-v2/media.js";
16
+ import { syncBoards } from "../core/sync-v2/board.js";
17
+ import { drainReactions, placeUnresolvedReactions } from "../core/sync-v2/reactions.js";
18
+ import { syncCloudIndex } from "../core/sync-v2/zcloud.js";
19
+ import { syncConvState } from "../core/sync-v2/conv-state.js";
20
+ import { planSyncRun } from "../core/sync-v2/plan.js";
21
+ import { startKeepAlive } from "../core/sync-v2/keepalive.js";
22
+ import { getSyncChannel, syncViaDaemon } from "../core/daemon-channel.js";
23
+ import { attachLiveStore } from "../core/live-store.js";
24
+ import {
25
+ initDb,
26
+ getRecentThreads,
27
+ getThreadNames,
28
+ countPendingAttachments,
29
+ getSyncState,
30
+ setSyncState,
31
+ clearSyncState,
32
+ getOrphanThreads,
33
+ recordConversationList,
34
+ } from "../core/db.js";
35
+
36
+ /** Zalo close code for a duplicate web session (Zalo Web is open elsewhere). */
37
+ const CLOSE_DUPLICATE = 3000;
38
+
39
+ /**
40
+ * Reaction-drain budget for the unified run.
41
+ *
42
+ * Named because the daemon path has to ask for exactly the same thing: the
43
+ * stage runs in another process there, and a page cap that differed between
44
+ * the two would make the same command truncate in one setup and not the other.
45
+ */
46
+ const DRAIN_PAGES = 20;
47
+ const DRAIN_WAIT_MS = 15000;
48
+
49
+ /**
50
+ * Human-friendly relative age for the "already synced …" skip message.
51
+ *
52
+ * @param {number|null} ms - age in milliseconds, or null.
53
+ * @returns {string}
54
+ */
55
+ function formatAge(ms) {
56
+ if (!Number.isFinite(ms) || ms < 1000) return "moments";
57
+ const sec = Math.round(ms / 1000);
58
+ if (sec < 60) return `${sec} seconds`;
59
+ const min = Math.round(sec / 60);
60
+ if (min < 60) return min === 1 ? "1 minute" : `${min} minutes`;
61
+ const hr = Math.round(min / 60);
62
+ if (hr < 24) return hr === 1 ? "1 hour" : `${hr} hours`;
63
+ const day = Math.round(hr / 24);
64
+ return day === 1 ? "1 day" : `${day} days`;
65
+ }
66
+
67
+ export function registerSyncCommands(program) {
68
+ program
69
+ .command("sync")
70
+ .description(
71
+ "Pull ALL message state in one run: message history (one phone prompt), the reaction backlog, " +
72
+ "pinned and unread conversations, notes/pins/polls/reminders, the zCloud index, and media. " +
73
+ "One lock and one socket window for the socket stages, then the REST stages. The sync-* " +
74
+ "commands remain for re-running a single stage",
75
+ )
76
+ .option(
77
+ "-F, --force",
78
+ "Restore messages even if a successful sync completed within the last hour (re-pings the phone)",
79
+ )
80
+ .option("-d, --days <n>", "Restore only the last N days of messages", parseIntAtLeast(1))
81
+ .option("--from <date>", "Restore messages from this date onward (YYYY-MM-DD); overrides --days")
82
+ .option(
83
+ "-w, --wait <seconds>",
84
+ "How long to wait for the phone confirmation (floored at 180)",
85
+ parseIntOption,
86
+ 180,
87
+ )
88
+ .option("--no-messages", "Skip the message restore (no phone prompt)")
89
+ .option("--no-reactions", "Skip the reaction backlog")
90
+ .option("--no-conv-state", "Skip pinned and unread conversations")
91
+ .option("--no-boards", "Skip notes, pinned messages, polls and reminders")
92
+ .option("--no-cloud", "Skip the zCloud index")
93
+ .option("--no-media", "Skip downloading attachments")
94
+ .option(
95
+ "--no-removals",
96
+ "Do not apply un-react entries from the reaction backlog (see sync-reactions --no-removals)",
97
+ )
98
+ .option(
99
+ "--shard-size <n>",
100
+ "Conversations per message batch (1-30, default 30). Fewer means more, smaller batches: " +
101
+ "the first one comes back sooner and less is lost if the connection drops, at the cost of " +
102
+ "more sync sessions. The server rejects a batch of more than 30",
103
+ parseIntAtLeast(1),
104
+ )
105
+ .option("--plan", "Print which stages would run, in what order and why, then exit. Sends nothing")
106
+ .action(async (opts) => {
107
+ // Only the message restore carries a window; accepting one with the
108
+ // restore switched off would silently mean nothing.
109
+ if ((opts.days !== undefined || opts.from !== undefined) && opts.messages === false) {
110
+ error("--days/--from apply to the message restore, which --no-messages switches off.");
111
+ process.exit(1);
112
+ }
113
+ await runUnifiedSync(requireAccount(), opts, Boolean(program.opts().json));
114
+ });
115
+
116
+ program
117
+ .command("sync-mobile")
118
+ .description(
119
+ "Restore message history from your phone into the local cache (zalo.db). " +
120
+ "This IS the real phone-backed restore (transfer-sync-v2) by default: it sends one " +
121
+ "sync request your phone confirms, then decrypts and stores your history. " +
122
+ "--socket asks for the old server backfill instead (measured empty); --legacy tries an old " +
123
+ "endpoint Zalo Web no longer calls (it answers empty).",
124
+ )
125
+ .option(
126
+ "-t, --transfer",
127
+ "Accepted and ignored — the phone-backed restore is the default now. Kept so the scripts, docs and muscle memory that pass it keep working",
128
+ )
129
+ .option(
130
+ "--socket",
131
+ "Ask for the old best-effort server socket backfill (cmd 510/511) instead of the phone-backed restore. Measured to answer empty, so this is a cheap probe, not a data path",
132
+ )
133
+ .option(
134
+ "-F, --force",
135
+ "Skip the 'already synced recently' shortcut and sync anyway. By default a sync is skipped when a successful one completed within the last hour and no gap is pending — mirroring Zalo Web, which only re-syncs when it thinks something is missing",
136
+ )
137
+ .option(
138
+ "-d, --days <n>",
139
+ "Restore only the last N days of history instead of everything. " +
140
+ "A narrower window asks the phone for fewer conversations, so the run is much shorter. " +
141
+ "Default: full history",
142
+ parseIntAtLeast(1),
143
+ )
144
+ .option(
145
+ "--from <date>",
146
+ "Restore everything from this date onward (YYYY-MM-DD). Overrides --days. " +
147
+ "The default is already everything your phone still holds, so this is for deliberately " +
148
+ "narrowing a run, not widening it",
149
+ )
150
+ .option(
151
+ "-L, --legacy",
152
+ "Try the old pull_mobile_msg/get_crossdb phone-transfer endpoint instead, which Zalo Web no longer " +
153
+ "calls and which answers empty. One attempt only — it pings your mobile app",
154
+ )
155
+ .option(
156
+ "-M, --messages-only",
157
+ "Restore messages but do NOT fetch their media. By default a transfer sync downloads the attachments it " +
158
+ "recorded once the messages are stored, because a message whose photo or file is missing is only half " +
159
+ "restored. Use this when you want the history quickly and will run `sync-media` later",
160
+ )
161
+ .option("-w, --wait <seconds>", "Give up after this long", parseIntOption, 30)
162
+ .option(
163
+ "--shard-size <n>",
164
+ "Conversations per message batch (1-30, default 30). Fewer means more, " +
165
+ "smaller batches: the first one comes back sooner and less is lost if the connection " +
166
+ "drops, at the cost of more sync sessions. The server rejects a batch of more than 30",
167
+ parseIntAtLeast(1),
168
+ )
169
+ .action(async (opts) => {
170
+ // --days is a property of the cmd 590 query the phone answers, so
171
+ // it only means anything on the transfer path. Say so instead of
172
+ // accepting the flag and quietly ignoring it.
173
+ // These shape the cmd 590 query the phone answers, so they mean
174
+ // nothing to the socket probe. They used to be an error WITHOUT
175
+ // --transfer; now that the restore is the default, the only way to
176
+ // pass one where it does not apply is to ask for --socket as well.
177
+ const restoreOnly = [
178
+ [opts.messagesOnly, "--messages-only"],
179
+ [opts.from !== undefined, "--from"],
180
+ [opts.days !== undefined, "--days"],
181
+ [opts.shardSize !== undefined, "--shard-size"],
182
+ ]
183
+ .filter(([passed]) => passed)
184
+ .map(([, flag]) => flag);
185
+ if (opts.socket && restoreOnly.length) {
186
+ const verb = restoreOnly.length === 1 ? "shapes" : "shape";
187
+ error(`${restoreOnly.join(", ")} ${verb} the phone-backed restore, which --socket switches off.`);
188
+ info("Drop --socket to use them.");
189
+ process.exit(1);
190
+ }
191
+
192
+ const activeAcc = getActive();
193
+ if (!activeAcc) {
194
+ error("No active account. Please login first.");
195
+ process.exit(1);
196
+ }
197
+
198
+ if (opts.legacy) {
199
+ await runLegacySync(activeAcc, opts);
200
+ return;
201
+ }
202
+ if (opts.socket) {
203
+ await runSocketBackfill(activeAcc, opts);
204
+ return;
205
+ }
206
+ await runTransferSync(activeAcc, opts);
207
+ });
208
+
209
+ program
210
+ .command("sync-media")
211
+ .description(
212
+ "Download the attachments a mobile sync recorded. transfer-sync carries only CDN " +
213
+ "references, never file bytes, so this is the separate fetch step. Needs no phone " +
214
+ "confirmation. Expired links are retried once through Zalo's renewlink endpoint",
215
+ )
216
+ .option("-T, --thread <threadId>", "Only this conversation")
217
+ .option(
218
+ "-k, --kind <kinds>",
219
+ `Comma-separated kinds to fetch (${[...DOWNLOADABLE_KINDS].join(", ")}). Default: all of them`,
220
+ )
221
+ .option("-n, --limit <n>", "Consider at most this many messages", parseIntAtLeast(1), 500)
222
+ .option("-d, --days <n>", "Only attachments from the last N days", parseIntAtLeast(1))
223
+ .option("-c, --concurrency <n>", "Parallel downloads", parseIntAtLeast(1), 4)
224
+ .option("-m, --max-size <mb>", "Skip attachments larger than this many MB", parseIntAtLeast(1))
225
+ .option(
226
+ "--timeout <seconds>",
227
+ "Give up on a single download after this long. Guards against a server that sends headers " +
228
+ "then stops writing, which would otherwise block a worker forever",
229
+ parseIntAtLeast(5),
230
+ 60,
231
+ )
232
+ .option("--thumbs", "Also save thumbnails alongside the full media")
233
+ .option(
234
+ "--prune <days|all>",
235
+ "Delete downloaded media instead of downloading it: either attached to messages older than " +
236
+ "N days, or `all` for every downloaded file. Message text is never touched. Always " +
237
+ "preview with --dry-run first",
238
+ )
239
+ .option("--all", "With --prune, delete every downloaded file regardless of age")
240
+ .option(
241
+ "--prune-orphans",
242
+ "Delete downloaded media belonging to conversations the account no longer has — dispersed " +
243
+ "groups, deleted chats, groups you were removed from. Message text is kept; use " +
244
+ "`conv forget --orphans` to remove that too",
245
+ )
246
+ .option(
247
+ "--all-history",
248
+ "Consider every attachment, not just those inside the window the last mobile sync covered",
249
+ )
250
+ .option(
251
+ "--include-pruned",
252
+ "Also re-fetch media you previously pruned. Pruning is treated as a decision, so it is " +
253
+ "skipped by automatic fetches until you ask for it back",
254
+ )
255
+ .option("--dry-run", "Report what would be fetched without downloading anything")
256
+ .action(async (opts) => {
257
+ if (opts.pruneOrphans) {
258
+ await runPruneOrphans(requireAccount(), opts);
259
+ return;
260
+ }
261
+ if (opts.prune !== undefined) {
262
+ // Validate the argument BEFORE anything else, so a typo is
263
+ // reported as a typo rather than as "no active account".
264
+ const wantsAll = Boolean(opts.all) || String(opts.prune).toLowerCase() === "all";
265
+ const n = Number(opts.prune);
266
+ if (!wantsAll && (!Number.isInteger(n) || n < 1)) {
267
+ error(`--prune needs a whole number of days (1 or more), or "all". Got: ${opts.prune}`);
268
+ info("Run: zalo-agent sync-media --prune 90 --dry-run");
269
+ process.exit(1);
270
+ }
271
+ await runMediaPrune(requireAccount(), opts);
272
+ return;
273
+ }
274
+ if (opts.all) {
275
+ error("--all only means anything together with --prune.");
276
+ info("Run: zalo-agent sync-media --prune all --dry-run");
277
+ process.exit(1);
278
+ }
279
+ await runMediaDownload(requireAccount(), opts);
280
+ });
281
+
282
+ program
283
+ .command("sync-reactions")
284
+ .description(
285
+ "Retrieve existing reactions from Zalo's servers into the local cache. Reactions are the one " +
286
+ "thing a transfer sync cannot restore — the Sync2 payload has no reaction field — but they " +
287
+ "ARE served over the socket (cmd 610 for 1-1, 611 for groups), which is how Zalo Web shows " +
288
+ "them after a fresh login. Needs no phone confirmation",
289
+ )
290
+ .option("-w, --wait <seconds>", "Per-page deadline", parseIntAtLeast(1), 15)
291
+ .option("-p, --pages <n>", "Max pages per thread type", parseIntAtLeast(1), 20)
292
+ .option(
293
+ "--no-removals",
294
+ "Do not apply un-react entries from the backlog. The default DOES apply them, because the " +
295
+ "backlog is an ordered action log rather than a snapshot: skipping them leaves reactions " +
296
+ "that were later taken off. Use this only to see every reaction a message ever had",
297
+ )
298
+ .action(async (opts) => {
299
+ await runReactionSync(requireAccount(), opts);
300
+ });
301
+
302
+ program
303
+ .command("sync-boards")
304
+ .description(
305
+ "Sync notes, pinned messages, polls and reminders into the local cache. These are NOT " +
306
+ "part of the message stream — Zalo keeps them behind per-thread board endpoints — so " +
307
+ "they need this separate pass. Needs no phone confirmation",
308
+ )
309
+ .option("-T, --thread <threadId>", "Only this conversation")
310
+ .option("-n, --limit <n>", "Visit at most this many threads (most recent first)", parseIntAtLeast(1), 200)
311
+ .option("-c, --concurrency <n>", "Threads fetched in parallel", parseIntAtLeast(1), 3)
312
+ .option("--no-reminders", "Skip reminders")
313
+ .option("--no-boards", "Skip notes/pinned messages/polls")
314
+ .action(async (opts) => {
315
+ await runBoardSync(requireAccount(), opts);
316
+ });
317
+
318
+ program
319
+ .command("sync-cloud")
320
+ .description(
321
+ "Walk the zCloud ('Cloud của tôi') media index and record it locally — the same " +
322
+ "reconciliation Zalo Web runs when it receives a cloud verify event. Records where " +
323
+ "each backup lives; it does not download or decrypt cloud blobs",
324
+ )
325
+ .option("-p, --pages <n>", "Maximum pages to walk", parseIntAtLeast(1), 50)
326
+ .option("-s, --page-size <n>", "Items per page (Zalo Web uses 300)", parseIntAtLeast(1), 300)
327
+ .option("-r, --resume <noiseId>", "Resume from this cursor instead of starting over")
328
+ .action(async (opts) => {
329
+ await runCloudSync(requireAccount(), opts);
330
+ });
331
+ }
332
+
333
+ /** The active account, or exit with the same message every command uses. */
334
+ function requireAccount() {
335
+ const acc = getActive();
336
+ if (!acc) {
337
+ error("No active account. Please login first.");
338
+ process.exit(1);
339
+ }
340
+ return acc;
341
+ }
342
+
343
+ const MB = 1024 * 1024;
344
+
345
+ /** Download attachments recorded by an earlier sync. No phone, no socket. */
346
+ async function runMediaDownload(activeAcc, opts) {
347
+ const accountDir = join(CONFIG_DIR, "accounts", activeAcc.ownId);
348
+ initDb(join(accountDir, "zalo.db"));
349
+
350
+ let kinds;
351
+ if (opts.kind) {
352
+ kinds = String(opts.kind)
353
+ .split(",")
354
+ .map((k) => k.trim().toLowerCase())
355
+ .filter(Boolean);
356
+ const unknown = kinds.filter((k) => !DOWNLOADABLE_KINDS.has(k));
357
+ if (unknown.length) {
358
+ error(`Unknown kind(s): ${unknown.join(", ")}`);
359
+ info(`Valid kinds: ${[...DOWNLOADABLE_KINDS].join(", ")}`);
360
+ process.exit(1);
361
+ }
362
+ }
363
+
364
+ // Follow the window the last mobile sync covered. Fetching media for
365
+ // messages outside it is pointless work: those rows were never refreshed,
366
+ // so their links are the oldest and likeliest to be dead. --all-history
367
+ // opts out, and an explicit --days still wins.
368
+ let since = opts.days ? Date.now() - opts.days * 86400000 : undefined;
369
+ if (since === undefined && !opts.allHistory) {
370
+ const covered = Number(getSyncState("lastSyncOkFrom"));
371
+ if (Number.isFinite(covered) && covered > 0) {
372
+ since = covered;
373
+ info(
374
+ `Limiting to the window the last sync covered (since ${new Date(covered).toISOString().slice(0, 10)}).`,
375
+ );
376
+ info("Pass --all-history to consider everything in the cache.");
377
+ }
378
+ }
379
+
380
+ const pending = countPendingAttachments(opts.thread || null);
381
+ if (!pending) {
382
+ success("No attachments waiting to be downloaded.");
383
+ info("Run `zalo-agent sync-mobile --transfer` first if you have not synced yet.");
384
+ process.exit(0);
385
+ }
386
+ info(`${pending} attachment(s) not yet downloaded.`);
387
+
388
+ // Media lives behind the same session as everything else, but only the
389
+ // renewal of an expired URL actually needs it — so a missing session
390
+ // degrades to "fetch what is still live" rather than failing outright.
391
+ let api = null;
392
+ try {
393
+ api = getApi();
394
+ } catch {
395
+ warning("No active session — expired links cannot be renewed on this run.");
396
+ }
397
+
398
+ let last = 0;
399
+ const stats = await downloadSyncedMedia({
400
+ api,
401
+ accountDir,
402
+ threadId: opts.thread,
403
+ kinds,
404
+ limit: opts.limit,
405
+ since,
406
+ concurrency: opts.concurrency,
407
+ maxBytes: opts.maxSize ? opts.maxSize * MB : undefined,
408
+ timeoutMs: (opts.timeout || 60) * 1000,
409
+ thumbs: Boolean(opts.thumbs),
410
+ includePruned: Boolean(opts.includePruned),
411
+ dryRun: Boolean(opts.dryRun),
412
+ threadNames: getThreadNames(),
413
+ onProgress: (p) => {
414
+ if (p.phase === "dry-run") info(p.detail);
415
+ // One line per 25 files keeps a 10k-file run readable.
416
+ if (p.phase === "saved" && (p.done === p.total || p.done - last >= 25)) {
417
+ last = p.done;
418
+ info(` ${p.done}/${p.total} downloaded`);
419
+ }
420
+ },
421
+ });
422
+
423
+ if (opts.dryRun) {
424
+ success(`Dry run: ${stats.considered} attachment(s) would be fetched.`);
425
+ process.exit(0);
426
+ }
427
+ success(`Downloaded ${stats.downloaded}/${stats.considered} attachment(s) (${formatBytes(stats.bytes)}).`);
428
+ if (stats.renewed) info(`Renewed ${stats.renewed} expired link(s).`);
429
+ if (stats.expired) {
430
+ warning(`${stats.expired} link(s) are gone (HTTP 404/410 or a lapsed signature).`);
431
+ info("Zalo only keeps media for a limited time; past that the file exists only on the sending device.");
432
+ }
433
+ if (stats.throttled) {
434
+ warning(
435
+ `${stats.throttled} request(s) were rate limited (${describeDownloadReasons(stats.reasons, "throttled")}).`,
436
+ );
437
+ info("Those attachments are still marked pending, so re-running picks them up. Wait a while first.");
438
+ info("A lower --concurrency makes a long run far less likely to trip it.");
439
+ }
440
+ // Deliberately not called rate limiting. Zalo answers 403 for a lapsed
441
+ // signature and under load alike, and nothing in the response says which.
442
+ // This bucket used to be merged into the one above and announced as near-
443
+ // certain throttling, which sent people off to wait and retry a link that
444
+ // no amount of waiting would bring back.
445
+ if (stats.unknown) {
446
+ warning(
447
+ `${stats.unknown} request(s) failed without saying why (${describeDownloadReasons(stats.reasons, "unknown")}).`,
448
+ );
449
+ info("A 403 from Zalo means either a lapsed signature or load — the response does not distinguish them.");
450
+ info("They stay pending, so a re-run retries them; if the same ones keep failing, waiting will not help.");
451
+ info("Only a fresh mobile sync can hand back a new link: `zalo-agent sync --from <YYYY-MM-DD>`.");
452
+ info("(It does not always issue one — the renewal hints Zalo sends are mobile-only.)");
453
+ }
454
+ if (stats.abortedEarly) {
455
+ warning("Stopped early: too many requests in a row came back unusable. Nothing is lost — re-run to continue.");
456
+ }
457
+ const other = stats.failed - stats.expired - stats.throttled - stats.unknown;
458
+ if (other > 0) {
459
+ warning(`${other} attachment(s) failed for other reasons.`);
460
+ for (const f of stats.failures.slice(0, 5)) info(` ${f.msgId}: ${f.reason}`);
461
+ }
462
+ process.exit(0);
463
+ }
464
+
465
+ /** Reclaim media held by conversations the account no longer has. */
466
+ async function runPruneOrphans(activeAcc, opts) {
467
+ const accountDir = join(CONFIG_DIR, "accounts", activeAcc.ownId);
468
+ initDb(join(accountDir, "zalo.db"));
469
+
470
+ // The recorded definition: the same set `sync`'s warning counts and
471
+ // `conv forget --orphans` removes.
472
+ const orphans = getOrphanThreads().filter((t) => t.files > 0);
473
+ if (!orphans.length) {
474
+ success("No orphaned conversations are holding downloaded media.");
475
+ info(
476
+ "Orphans come from leave/removal events, `conv delete`, and the conversation list a full-history sync returns.",
477
+ );
478
+ process.exit(0);
479
+ }
480
+
481
+ // The dry run goes through the same function, over the same rows, as the
482
+ // real one -- so what it lists and counts is what the real run deletes.
483
+ const dryRun = Boolean(opts.dryRun);
484
+ const total = { deleted: 0, present: 0, bytes: 0, missing: 0, failed: 0, failures: [] };
485
+ for (const t of orphans) {
486
+ const st = await pruneDownloadedMedia({ all: true, threadId: t.threadId, dryRun });
487
+ total.deleted += st.deleted;
488
+ total.present += st.considered - st.missing;
489
+ total.bytes += st.bytes;
490
+ total.missing += st.missing;
491
+ total.failed += st.failed;
492
+ total.failures.push(...st.failures);
493
+ }
494
+
495
+ if (dryRun) {
496
+ success(
497
+ `Dry run: ${total.present} file(s) (${formatBytes(total.bytes)}) across ${orphans.length} orphaned conversation(s).`,
498
+ );
499
+ // Every one of them. A preview that stops at a page does not show what
500
+ // the real run is about to remove.
501
+ for (const t of orphans) {
502
+ info(` ${t.threadId}${t.name ? ` (${t.name})` : ""} — ${t.files} file(s)`);
503
+ }
504
+ if (total.missing)
505
+ info(`${total.missing} row(s) point at files already gone; a real run clears those pointers.`);
506
+ info("Message text is kept. Use `conv forget --orphans` to remove that too.");
507
+ process.exit(0);
508
+ }
509
+
510
+ success(
511
+ `Deleted ${total.deleted} file(s) (${formatBytes(total.bytes)}) from ${orphans.length} orphaned conversation(s).`,
512
+ );
513
+ if (total.missing) info(`${total.missing} row(s) pointed at files already gone — those pointers were cleared.`);
514
+ if (total.failed) {
515
+ warning(`${total.failed} file(s) could not be deleted.`);
516
+ for (const f of total.failures.slice(0, 5)) info(` ${f.msgId}: ${f.reason}`);
517
+ }
518
+ info("Their message text is still here — `conv forget --orphans` removes that too.");
519
+ process.exit(0);
520
+ }
521
+
522
+ /** Delete downloaded media older than N days. Never removes message rows. */
523
+ async function runMediaPrune(activeAcc, opts) {
524
+ const accountDir = join(CONFIG_DIR, "accounts", activeAcc.ownId);
525
+ initDb(join(accountDir, "zalo.db"));
526
+
527
+ // "all" is a mode, not a very large number of days: a cutoff computed from
528
+ // a bad date could silently become delete-everything, a named mode cannot.
529
+ const wantsAll = Boolean(opts.all) || String(opts.prune).toLowerCase() === "all";
530
+ const days = wantsAll ? 0 : Number(opts.prune);
531
+ if (!wantsAll && (!Number.isInteger(days) || days < 1)) {
532
+ error(`--prune needs a whole number of days (1 or more), or "all". Got: ${opts.prune}`);
533
+ info("Run: zalo-agent sync-media --prune 90 --dry-run");
534
+ process.exit(1);
535
+ }
536
+
537
+ const scope = wantsAll ? "every downloaded file" : `media older than ${days} day(s)`;
538
+ const stats = await pruneDownloadedMedia({
539
+ olderThanDays: days,
540
+ all: wantsAll,
541
+ threadId: opts.thread,
542
+ dryRun: Boolean(opts.dryRun),
543
+ });
544
+
545
+ const cutoff = stats.all ? "any date" : new Date(stats.cutoff).toISOString().slice(0, 10);
546
+ if (!stats.considered) {
547
+ success(`Nothing to prune — no downloaded media matched ${scope}.`);
548
+ process.exit(0);
549
+ }
550
+ if (opts.dryRun) {
551
+ success(`Dry run: ${stats.considered} file(s), ${formatBytes(stats.bytes)} — ${scope}.`);
552
+ info("Message text is untouched; pruned files can be re-downloaded while their links live.");
553
+ info("Re-run without --dry-run to delete them.");
554
+ process.exit(0);
555
+ }
556
+ success(`Deleted ${stats.deleted} file(s), reclaiming ${formatBytes(stats.bytes)} (${scope}, before ${cutoff}).`);
557
+ if (stats.missing) info(`${stats.missing} row(s) pointed at files already gone — those pointers were cleared.`);
558
+ if (stats.failed) {
559
+ warning(`${stats.failed} file(s) could not be deleted.`);
560
+ for (const f of stats.failures.slice(0, 5)) info(` ${f.msgId}: ${f.reason}`);
561
+ }
562
+ // mediaPrunedAt keeps them out of every automatic fetch: a prune is a
563
+ // decision, not a gap to refill (db.js getAttachmentMessages).
564
+ info(
565
+ "Message history is unchanged. These attachments are not fetched again on their own; " +
566
+ "`zalo-agent sync-media --include-pruned` re-downloads them while their links still work.",
567
+ );
568
+ process.exit(0);
569
+ }
570
+
571
+ /** Sync board items + reminders for the cached threads. No phone, no socket. */
572
+ async function runBoardSync(activeAcc, opts) {
573
+ const accountDir = join(CONFIG_DIR, "accounts", activeAcc.ownId);
574
+ initDb(join(accountDir, "zalo.db"));
575
+
576
+ let api;
577
+ try {
578
+ api = getApi();
579
+ } catch (err) {
580
+ error(`Failed: ${err.message}`);
581
+ process.exit(1);
582
+ }
583
+
584
+ const r = await boardPass(api, opts);
585
+ if (r.status === "skipped") {
586
+ warning(opts.thread ? `Thread ${opts.thread} is not in the local cache.` : "No threads in the local cache.");
587
+ info("Run `zalo-agent sync-mobile --transfer` first.");
588
+ }
589
+ process.exit(0);
590
+ }
591
+
592
+ /**
593
+ * One board pass over the cached threads. Exit-free, so `sync` can run it as a
594
+ * stage and `sync-boards` as a command.
595
+ *
596
+ * @param {object} api
597
+ * @param {{limit?: number, thread?: string, boards?: boolean, reminders?: boolean, concurrency?: number}} opts
598
+ * @returns {Promise<{status: "ok"|"skipped", reason?: string, stats?: object}>}
599
+ */
600
+ async function boardPass(api, opts) {
601
+ const all = getRecentThreads(opts.limit);
602
+ const threads = (opts.thread ? all.filter((t) => String(t.threadId) === String(opts.thread)) : all).map((t) => ({
603
+ threadId: String(t.threadId),
604
+ type: t.type,
605
+ name: t.name,
606
+ }));
607
+ if (!threads.length) {
608
+ return {
609
+ status: "skipped",
610
+ reason: opts.thread ? `thread ${opts.thread} is not in the local cache` : "no threads in the local cache",
611
+ };
612
+ }
613
+
614
+ // A live board event flags its thread; those go first so a quick run after
615
+ // seeing "Board changed" refreshes the thing that actually moved.
616
+ const stale = threads.filter((t) => getSyncState(`boardStale:${t.threadId}`));
617
+ if (stale.length && !opts.thread) {
618
+ info(`${stale.length} thread(s) had a board change since the last pass — doing those first.`);
619
+ const rest = threads.filter((t) => !getSyncState(`boardStale:${t.threadId}`));
620
+ threads.length = 0;
621
+ threads.push(...stale, ...rest);
622
+ }
623
+
624
+ info(`Checking ${threads.length} thread(s) — one request each, so this is paced deliberately.`);
625
+ let last = 0;
626
+ const stats = await syncBoards({
627
+ api,
628
+ threads,
629
+ boards: opts.boards !== false,
630
+ reminders: opts.reminders !== false,
631
+ concurrency: opts.concurrency,
632
+ onProgress: (p) => {
633
+ // The flag exists to say "come back to this one". Clearing it is
634
+ // what makes the next run's prioritization mean anything, and it
635
+ // must not be cleared for a thread whose own fetch failed.
636
+ if (p.phase === "thread" && p.ok) clearSyncState(`boardStale:${p.threadId}`);
637
+ if (p.done === p.total || p.done - last >= 25) {
638
+ last = p.done;
639
+ info(` ${p.done}/${p.total} threads`);
640
+ }
641
+ },
642
+ });
643
+
644
+ success(
645
+ `Stored ${stats.boardItems} board item(s) and ${stats.reminders} reminder(s) from ${stats.threads} thread(s).`,
646
+ );
647
+ if (stats.failed) {
648
+ warning(`${stats.failed} request(s) failed (left groups and blocked peers are expected here).`);
649
+ for (const f of stats.failures.slice(0, 5)) info(` ${f.threadId} (${f.what}): ${f.reason}`);
650
+ }
651
+ return { status: "ok", stats };
652
+ }
653
+
654
+ /**
655
+ * Retrieve the reaction backlog over the socket. No phone confirmation.
656
+ *
657
+ * Reactions were long documented here as unrecoverable, which conflated two
658
+ * things: the transfer-sync payload genuinely has no reaction field, but the
659
+ * socket serves them on cmd 610/611 and Zalo Web asks for both on every
660
+ * connect. Measured on a real account, one request pair returned 28 direct and
661
+ * 50 group reactions while the local cache held one row.
662
+ *
663
+ * @param {{ownId: string, name?: string}} activeAcc
664
+ * @param {{wait?: number, pages?: number, applyRemovals?: boolean}} opts
665
+ */
666
+ async function runReactionSync(activeAcc, opts) {
667
+ const accountDir = join(CONFIG_DIR, "accounts", activeAcc.ownId);
668
+ initDb(join(accountDir, "zalo.db"));
669
+
670
+ let api;
671
+ try {
672
+ api = getApi();
673
+ } catch (err) {
674
+ error(`Failed: ${err.message}`);
675
+ process.exit(1);
676
+ }
677
+
678
+ const waitMs = Math.max(1, Number(opts.wait) || 15) * 1000;
679
+
680
+ // A daemon holding the account's session can drain on it. Nothing is
681
+ // stopped and nothing is evicted, so this is no longer a reason to refuse.
682
+ const chan = getSyncChannel(accountDir, "reactions");
683
+ if (chan) {
684
+ info("A listen/mcp daemon holds this account's session — draining on its socket.");
685
+ info("Requesting the reaction backlog (cmd 610 for 1-1, 611 for groups)…");
686
+ const r = await syncViaDaemon(accountDir, {
687
+ stage: "reactions",
688
+ params: { waitMs, maxPages: opts.pages, applyRemovals: opts.removals !== false },
689
+ onEvent: reactionProgress,
690
+ });
691
+ if (!r?.ok) {
692
+ error(`Failed: ${daemonStageError(r)}`);
693
+ process.exit(1);
694
+ }
695
+ reportReactionStage(r.result, r.result.placed || 0, r.result.unresolvedLeft || 0, opts.pages);
696
+ process.exit(0);
697
+ }
698
+
699
+ // One socket and one db writer per account, same as every other path that
700
+ // opens the WebSocket.
701
+ if (!acquireLock(accountDir)) {
702
+ error(`A listen daemon (or MCP server) is already running for account ${activeAcc.ownId}.`);
703
+ // It holds the lock but published no channel, so it cannot run the
704
+ // drain for us either. Restarting it is what makes that possible.
705
+ info("Stop it first — Zalo permits one web session per account.");
706
+ info("(A daemon started with a working sync channel would have run this drain on its own socket.)");
707
+ process.exit(1);
708
+ }
709
+
710
+ let exitCode = 1;
711
+
712
+ try {
713
+ info("Connecting…");
714
+ const connected = await connectListener(api, waitMs);
715
+
716
+ if (!connected.ok) {
717
+ if (connected.reason === "duplicate") {
718
+ error("Zalo closed this connection: another web session is already open on this account.");
719
+ info("Zalo allows one web session per account. Sign out of Zalo Web, then run this again.");
720
+ } else {
721
+ error(`Could not open a connection: ${connected.reason}`);
722
+ }
723
+ } else {
724
+ const stats = await drainPass(api, { waitMs, pages: opts.pages, removals: opts.removals });
725
+ reportReactionDrain(stats, opts);
726
+ exitCode = 0;
727
+ }
728
+ } catch (err) {
729
+ error(`Failed: ${err.message}`);
730
+ } finally {
731
+ try {
732
+ api.listener.stop();
733
+ } catch {
734
+ // Already closed — nothing to clean up.
735
+ }
736
+ releaseLock(accountDir);
737
+ }
738
+
739
+ process.exit(exitCode);
740
+ }
741
+
742
+ /**
743
+ * Drain the reaction backlog on an already-open socket. Exit-free.
744
+ *
745
+ * @param {object} api - with a started listener
746
+ * @param {{waitMs: number, pages?: number, removals?: boolean}} opts
747
+ * @returns {Promise<object>} drainReactions stats
748
+ */
749
+ function drainPass(api, opts) {
750
+ info("Requesting the reaction backlog (cmd 610 for 1-1, 611 for groups)…");
751
+ return drainReactions({
752
+ listener: api.listener,
753
+ timeoutMs: opts.waitMs,
754
+ maxPages: opts.pages,
755
+ applyRemovals: opts.removals !== false,
756
+ onProgress: reactionProgress,
757
+ });
758
+ }
759
+
760
+ /**
761
+ * Print one drain progress callback.
762
+ *
763
+ * Shared with the daemon path, where the identical callbacks arrive as events
764
+ * off the channel rather than from a local `drainReactions` — the run must
765
+ * look the same to the person watching it either way.
766
+ *
767
+ * @param {{phase: string, type?: string, page?: number, received?: number,
768
+ * more?: number, detail?: string}} p
769
+ */
770
+ function reactionProgress(p) {
771
+ if (p.phase === "page") {
772
+ info(` ${p.type} page ${p.page}: ${p.received} reaction(s)${p.more ? " (more)" : ""}`);
773
+ } else if (p.phase === "timeout") {
774
+ warning(` ${p.type}: ${p.detail}`);
775
+ } else if (p.phase === "warn") {
776
+ warning(` ${p.detail}`);
777
+ }
778
+ }
779
+
780
+ /**
781
+ * Report and classify a finished reaction stage, whichever socket it ran on.
782
+ *
783
+ * The retry pass runs in whichever process owns the db — here when this
784
+ * process holds the socket, inside the daemon when the stage ran there — so
785
+ * the two paths hand in `placed`/`left` already counted and share everything
786
+ * downstream of that.
787
+ *
788
+ * @param {object} stats - drainReactions stats
789
+ * @param {number} placed - unresolved reactions placed on the retry pass
790
+ * @param {number} left - still unplaceable
791
+ * @param {number} [pages=DRAIN_PAGES] - the cap that was asked for, so a
792
+ * truncation message names the number the caller would have to raise
793
+ * @returns {{status: string, reason: string, stats: object}}
794
+ */
795
+ function reportReactionStage(stats, placed, left, pages = DRAIN_PAGES) {
796
+ reportReactionDrain(stats, { pages });
797
+ if (placed) info(`Placed ${placed} reaction(s) whose message is now stored.`);
798
+ return {
799
+ status: stats.truncated ? "partial" : "ok",
800
+ reason: `${stats.stored + placed} stored`,
801
+ stats: { received: stats.received, stored: stats.stored + placed, unresolved: left },
802
+ };
803
+ }
804
+
805
+ /**
806
+ * Say why a stage the daemon was asked to run did not produce a result.
807
+ *
808
+ * Every one of these ends the stage. None of them may fall back to opening a
809
+ * socket here: a daemon that answered at all still holds the account's one web
810
+ * session, and a second would evict it — which is the harm this whole path
811
+ * exists to avoid.
812
+ *
813
+ * @param {object|null} r - syncViaDaemon() result; null means it vanished
814
+ * @returns {string}
815
+ */
816
+ function daemonStageError(r) {
817
+ if (!r) return "the daemon went away before the request — re-run `zalo-agent sync`";
818
+ if (r.status === 409) {
819
+ const since = r.busySince ? ` (started ${formatAge(Date.now() - Number(r.busySince))} ago)` : "";
820
+ return `a ${r.busyStage || "sync"} is already running on that daemon${since} — wait for it to finish`;
821
+ }
822
+ // 404 is the daemon that predates these routes entirely; 503 is a newer
823
+ // one wired without that stage. `getSyncChannel()` normally keeps us out
824
+ // of both by reading the descriptor first, so reaching here means the
825
+ // daemon was replaced between the plan and the request.
826
+ if (r.status === 404 || r.status === 503) {
827
+ return "that daemon does not run sync stages — restart it to pick the capability up";
828
+ }
829
+ if (r.disconnected) return `${r.error} — the daemon may have restarted; re-run \`zalo-agent sync\``;
830
+ return r.error || "the daemon reported no result";
831
+ }
832
+
833
+ /**
834
+ * Report a finished drain in the words `sync-reactions` has always used.
835
+ *
836
+ * @param {object} stats - drainReactions stats
837
+ * @param {{pages?: number}} opts
838
+ */
839
+ function reportReactionDrain(stats, opts) {
840
+ if (stats.received === 0) {
841
+ warning("The server returned no reactions.");
842
+ info(
843
+ "That is a caught-up queue, not a missing feature: this channel is what Zalo Web itself " +
844
+ "asks on every connect. Reactions arriving from now on are captured by `zalo-agent listen`.",
845
+ );
846
+ return;
847
+ }
848
+ success(
849
+ `Stored ${stats.stored} of ${stats.received} reaction(s) ` +
850
+ `(${stats.byType.dm} direct, ${stats.byType.group} group; ${stats.changed} row(s) changed).`,
851
+ );
852
+ if (stats.skippedRemovals) {
853
+ warning(
854
+ `Skipped ${stats.skippedRemovals} un-react entr(y/ies) because of --no-removals, so the ` +
855
+ "cache now holds reactions that were later taken off.",
856
+ );
857
+ }
858
+ if (stats.truncated) {
859
+ warning(`Stopped at the ${opts.pages}-page cap; re-run with a higher --pages for the rest.`);
860
+ }
861
+ }
862
+
863
+ /** Walk the zCloud index. No phone, no socket. */
864
+ async function runCloudSync(activeAcc, opts) {
865
+ const accountDir = join(CONFIG_DIR, "accounts", activeAcc.ownId);
866
+ initDb(join(accountDir, "zalo.db"));
867
+
868
+ let api;
869
+ try {
870
+ api = getApi();
871
+ } catch (err) {
872
+ error(`Failed: ${err.message}`);
873
+ process.exit(1);
874
+ }
875
+
876
+ const r = await cloudPass(api, opts);
877
+ if (r.status === "unavailable") {
878
+ error("Could not read the cloud index.");
879
+ for (const f of r.stats.failures.slice(0, 3)) info(` ${f.reason}`);
880
+ info("This account may not have zCloud enabled, or the endpoint may have changed.");
881
+ process.exit(1);
882
+ }
883
+ if (r.stats.lastNoiseId && !r.stats.complete) info(`Resume cursor: ${r.stats.lastNoiseId}`);
884
+ info("Cloud blobs are stored encrypted; this pass records where they live, it does not download them.");
885
+ process.exit(0);
886
+ }
887
+
888
+ /**
889
+ * One walk of the zCloud index. Exit-free.
890
+ *
891
+ * The cursor used to be printed and thrown away, so a walk capped by --pages
892
+ * could only be continued by hand-copying it into --resume. It is now kept:
893
+ * saved when the walk stops on the cap, cleared when the server says it has
894
+ * nothing further, and an explicit --resume still wins.
895
+ *
896
+ * @param {object} api
897
+ * @param {{resume?: string, pageSize?: number, pages?: number}} opts
898
+ * @returns {Promise<{status: "ok"|"unavailable", stats: object}>}
899
+ */
900
+ async function cloudPass(api, opts) {
901
+ const saved = getSyncState("cloudCursor");
902
+ const resume = opts.resume || saved || "";
903
+ if (!opts.resume && saved) info("Continuing the cloud walk from where the last capped run stopped.");
904
+ info("Walking the zCloud media index…");
905
+ const stats = await syncCloudIndex({
906
+ api,
907
+ lastNoiseId: resume,
908
+ pageSize: opts.pageSize,
909
+ maxPages: opts.pages,
910
+ onProgress: (p) => info(` page ${p.page}: ${p.items} item(s) so far`),
911
+ });
912
+ if (stats.failed && !stats.items) return { status: "unavailable", stats };
913
+ if (stats.complete) clearSyncState("cloudCursor");
914
+ else if (stats.lastNoiseId) setSyncState("cloudCursor", String(stats.lastNoiseId));
915
+ success(`Recorded ${stats.items} cloud item(s) across ${stats.pages} page(s).`);
916
+ return { status: "ok", stats };
917
+ }
918
+
919
+ /** Human-readable byte count for the download summary. */
920
+ function formatBytes(n) {
921
+ if (!n) return "0 B";
922
+ const units = ["B", "KB", "MB", "GB"];
923
+ let i = 0;
924
+ let v = n;
925
+ while (v >= 1024 && i < units.length - 1) {
926
+ v /= 1024;
927
+ i++;
928
+ }
929
+ return `${v.toFixed(i === 0 ? 0 : 1)} ${units[i]}`;
930
+ }
931
+
932
+ /**
933
+ * Open the listener socket and resolve once connected (or on close/error/timeout).
934
+ *
935
+ * @param {object} api
936
+ * @param {number} waitMs
937
+ * @returns {Promise<{ok: boolean, reason?: string}>}
938
+ */
939
+ function connectListener(api, waitMs) {
940
+ return new Promise((res) => {
941
+ let settled = false;
942
+ const onConnected = () => done({ ok: true });
943
+ const onClosed = (code) =>
944
+ done({ ok: false, reason: code === CLOSE_DUPLICATE ? "duplicate" : `closed (${code})` });
945
+ const onError = (e) => done({ ok: false, reason: e && e.message ? e.message : "socket error" });
946
+ // Every handler comes off again when this settles. It used to leave all
947
+ // three behind, which was harmless while a process connected exactly
948
+ // once -- a reconnect makes them accumulate, and a stale "closed"
949
+ // handler would resolve the NEXT connect attempt with the PREVIOUS
950
+ // socket's close code.
951
+ const done = (v) => {
952
+ if (settled) return;
953
+ settled = true;
954
+ clearTimeout(timer);
955
+ api.listener.removeListener("connected", onConnected);
956
+ api.listener.removeListener("closed", onClosed);
957
+ api.listener.removeListener("error", onError);
958
+ res(v);
959
+ };
960
+ const timer = setTimeout(() => done({ ok: false, reason: "timeout" }), waitMs);
961
+ api.listener.on("connected", onConnected);
962
+ api.listener.on("closed", onClosed);
963
+ api.listener.on("error", onError);
964
+ api.listener.start({ retryOnClose: false });
965
+ });
966
+ }
967
+
968
+ /**
969
+ * Re-open the socket after it dropped mid-stage.
970
+ *
971
+ * Handed to `SyncV2.restore()` as its `reconnect`: that class never starts or
972
+ * stops the listener itself, so the decision to reconnect is the caller's. A
973
+ * 1006 is NOT in the server's own `close_and_retry_codes`
974
+ * (`settings.features.socket`, measured: 5008 5007 3003 3000 5014 4002 5015
975
+ * 5017 5016), so zca-js will never retry one for us -- without this, a dropped
976
+ * wire ends the run and the phone confirmation it already spent is gone.
977
+ *
978
+ * @param {object} api
979
+ * @param {number} [waitMs=30000]
980
+ * @returns {Promise<boolean>} true once a live socket is back
981
+ */
982
+ async function reconnectListener(api, waitMs = 30000) {
983
+ // zca-js nulls `ws` on close and throws "Already started" while it is set,
984
+ // so a socket still hanging around has to be put down first.
985
+ if (api?.listener?.ws) await closeListener(api);
986
+ const r = await connectListener(api, waitMs);
987
+ return r.ok === true;
988
+ }
989
+
990
+ /**
991
+ * Real mobile restore over transfer-sync-v2 (socket cmd 590/591): enumerate
992
+ * conversations, request message history sharded at <=30 partitions, decrypt
993
+ * with libzproto, decode protobuf, map opaque conv ids to real thread ids via
994
+ * the friend/group lists, and write into zalo.db. Sends ONE sync request the
995
+ * owner confirms on their phone. See src/core/sync-v2/index.js.
996
+ *
997
+ * @param {{ownId: string, name?: string}} activeAcc
998
+ * @param {{force?: boolean, wait?: number, days?: number}} opts
999
+ */
1000
+ async function runTransferSync(activeAcc, opts) {
1001
+ const accountDir = join(CONFIG_DIR, "accounts", activeAcc.ownId);
1002
+
1003
+ let api;
1004
+ let syncManager;
1005
+ try {
1006
+ api = getApi();
1007
+ syncManager = new SyncManager(api, activeAcc.ownId);
1008
+ } catch (err) {
1009
+ error(`Failed: ${err.message}`);
1010
+ process.exit(1);
1011
+ }
1012
+
1013
+ const win = resolveSyncWindow(opts.days, Date.now(), opts.from);
1014
+
1015
+ // Debounce: skip a redundant run so we don't re-ping the phone, unless
1016
+ // --force. Asking for a wider window than the last run covered is not
1017
+ // redundant, so that is allowed through (reason "wider-window").
1018
+ const freshness = syncManager.checkSyncFreshness({ force: opts.force, coversFrom: win.from });
1019
+ if (freshness.skip) {
1020
+ success(`Already synced ${formatAge(freshness.ageMs)} ago — skipping to avoid re-pinging your phone.`);
1021
+ info("Pass --force to sync anyway.");
1022
+ process.exit(0);
1023
+ }
1024
+ if (freshness.reason === "wider-window") {
1025
+ info(`Last sync covered less than this — syncing ${win.label} despite the recent run.`);
1026
+ }
1027
+
1028
+ // Transfer sync needs time for the phone confirmation; use a generous window.
1029
+ const waitMs = Math.max(180, Number(opts.wait) || 0) * 1000;
1030
+ let exitCode = 1;
1031
+
1032
+ // A running daemon holds the account's one web session and can run the
1033
+ // restore on it. Stopping it to sync used to be the only option, and the
1034
+ // stop/start opened a fresh coverage gap around the very run meant to
1035
+ // close one. See src/core/daemon-channel.js.
1036
+ const chan = getSyncChannel(accountDir, "messages");
1037
+ if (chan) {
1038
+ // SyncV2 opens the db itself on the local path; here it opens the
1039
+ // daemon's copy in the daemon's process, so the media tail below has
1040
+ // nothing to read from until we open ours.
1041
+ initDb(join(accountDir, "zalo.db"));
1042
+ info("A listen/mcp daemon holds this account's session — running the restore on its socket.");
1043
+ info("Nothing is stopped: it keeps capturing live messages while the restore runs.");
1044
+ info(`Restoring ${win.label}.`);
1045
+ if (win.clamped) info("(--days reaches past the oldest history this sync can request.)");
1046
+ warning("This sends ONE sync request to your phone — confirm the 'ĐỒNG BỘ NGAY' prompt when it appears.");
1047
+ const startedAt = Date.now();
1048
+ const r = await syncViaDaemon(accountDir, {
1049
+ stage: "messages",
1050
+ params: { days: opts.days ?? null, from: opts.from, shardSize: opts.shardSize, waitMs },
1051
+ onEvent: ({ phase, detail }) => {
1052
+ if (phase === "confirm") warning(detail);
1053
+ else if (detail) info(` ${detail}`);
1054
+ },
1055
+ });
1056
+ if (!r?.ok) {
1057
+ error(`Failed: ${daemonStageError(r)}`);
1058
+ } else {
1059
+ reportRestore(r.result, win, { startedAt, keep: ownThreadIds(api, activeAcc.ownId) });
1060
+ exitCode = 0;
1061
+ }
1062
+ } else if (!acquireLock(accountDir)) {
1063
+ error(`A listen daemon is already running for account ${activeAcc.ownId}.`);
1064
+ // It holds the lock but published no channel, so it cannot run the
1065
+ // restore for us either. Restarting it is what makes that possible.
1066
+ info("Stop it first — one socket per account.");
1067
+ info("(A daemon started with a working sync channel would have run this restore on its own socket.)");
1068
+ process.exit(1);
1069
+ } else {
1070
+ // One heartbeat for the whole socket window. `SyncV2.restore()` can
1071
+ // hold this socket idle for minutes waiting on the phone, and the
1072
+ // server-advised ping is 180000 ms -- the full width of that wait.
1073
+ let heartbeat = null;
1074
+ try {
1075
+ info("Connecting…");
1076
+ const connected = await connectListener(api, 30000);
1077
+ if (!connected.ok) {
1078
+ if (connected.reason === "duplicate") {
1079
+ error("Zalo closed this connection: another web session is already open on this account.");
1080
+ info("Zalo allows one web session per account. Sign out of Zalo Web, then run this again.");
1081
+ } else {
1082
+ error(`Could not open a connection: ${connected.reason}`);
1083
+ }
1084
+ } else {
1085
+ syncManager.markConnected();
1086
+ heartbeat = startKeepAlive(api.listener);
1087
+ info(`Restoring ${win.label}.`);
1088
+ if (win.clamped) info("(--days reaches past the oldest history this sync can request.)");
1089
+ warning(
1090
+ "This sends ONE sync request to your phone — confirm the 'ĐỒNG BỘ NGAY' prompt when it appears.",
1091
+ );
1092
+ const sv = new SyncV2(api, activeAcc.ownId);
1093
+ const startedAt = Date.now();
1094
+ const res = await sv.restore({
1095
+ days: opts.days,
1096
+ from: opts.from,
1097
+ shardSize: opts.shardSize,
1098
+ waitMs,
1099
+ // This command owns the socket for the whole run, so it owns
1100
+ // the heartbeat too -- see runUnifiedSync for why.
1101
+ keepAlive: false,
1102
+ reconnect: () => reconnectListener(api),
1103
+ onStatus: ({ phase, detail }) => {
1104
+ if (phase === "confirm") warning(detail);
1105
+ else if (detail) info(` ${detail}`);
1106
+ },
1107
+ });
1108
+ reportRestore(res, win, { startedAt, keep: ownThreadIds(api, activeAcc.ownId) });
1109
+ exitCode = 0;
1110
+ }
1111
+ } catch (err) {
1112
+ error(`Failed: ${err.message}`);
1113
+ } finally {
1114
+ try {
1115
+ heartbeat?.stop();
1116
+ } catch {
1117
+ /* already stopped */
1118
+ }
1119
+ try {
1120
+ api.listener.stop();
1121
+ } catch {
1122
+ // already closed
1123
+ }
1124
+ releaseLock(accountDir);
1125
+ }
1126
+ }
1127
+
1128
+ // Media is fetched only after the socket is closed and the lock released:
1129
+ // it needs neither, and holding them through a multi-thousand-file
1130
+ // download would block `listen` for no reason. A failure here never turns
1131
+ // a successful restore into a failed run -- the messages are already safe.
1132
+ if (exitCode === 0 && !opts.messagesOnly) {
1133
+ try {
1134
+ await fetchMediaAfterRestore(accountDir, api, win.from);
1135
+ } catch (err) {
1136
+ warning(`Media download stopped: ${err.message}`);
1137
+ info("The messages are stored. Run `zalo-agent sync-media` to retry the files.");
1138
+ }
1139
+ } else if (exitCode === 0 && opts.messagesOnly) {
1140
+ const pending = countPendingAttachments();
1141
+ if (pending)
1142
+ info(`${pending} attachment(s) left undownloaded (--messages-only). Run \`zalo-agent sync-media\`.`);
1143
+ }
1144
+ process.exit(exitCode);
1145
+ }
1146
+
1147
+ /**
1148
+ * How long a conversation must have been quiet before a restore started for
1149
+ * that restore's conversation list to call it gone.
1150
+ *
1151
+ * The list is taken early in a run that can last many minutes, and a
1152
+ * conversation that starts meanwhile cannot be in it. Its messages carry
1153
+ * Zalo's clock, the run's start time carries ours, so the margin also absorbs
1154
+ * a local clock running ahead. Sparing a recently active conversation costs
1155
+ * nothing: the next full-history sync lists it or marks it.
1156
+ */
1157
+ const LIST_CLOCK_SKEW_MS = 5 * 60 * 1000;
1158
+
1159
+ /**
1160
+ * What a restore's conversation list can prove gone, and for which kinds.
1161
+ *
1162
+ * The list may mark a cached conversation gone only when it is the phone's
1163
+ * WHOLE list and every conversation in it was matched to a thread id:
1164
+ *
1165
+ * - a --days/--from run lists only what was active in its window;
1166
+ * - a partial run lists only the shards that arrived;
1167
+ * - a listed conversation the restore could not map keeps an opaque
1168
+ * `oneone/…` / `group/…` id and could be ANY cached thread of that kind (a
1169
+ * group you left, if the phone still lists it: only current groups are in
1170
+ * the map);
1171
+ * - a listed conversation that returned no messages is in no id list at all.
1172
+ *
1173
+ * Marking in any of those cases would have prune-orphans delete the media of
1174
+ * a conversation the account still has.
1175
+ *
1176
+ * @param {object} res - SyncV2.restore() result
1177
+ * @param {{from: number}} win - resolveSyncWindow() result
1178
+ * @returns {{present: string[], complete: boolean, markKinds: string[], unresolved: number, silent: number}}
1179
+ */
1180
+ function conversationListProof(res, win) {
1181
+ const present = Array.isArray(res?.liveThreadIds) ? res.liveThreadIds.map(String) : [];
1182
+ const listed = Number(res?.conversations) || 0;
1183
+ const complete = win?.from <= FULL_HISTORY_FROM && res?.reason === "complete" && listed > 0;
1184
+ const opaque = { dm: 0, group: 0 };
1185
+ for (const id of present) {
1186
+ if (id.startsWith("oneone/")) opaque.dm++;
1187
+ else if (id.startsWith("group/")) opaque.group++;
1188
+ }
1189
+ const silent = Math.max(0, listed - present.length);
1190
+ const markKinds = complete && !silent ? ["dm", "group"].filter((k) => !opaque[k]) : [];
1191
+ return { present, complete, markKinds, unresolved: opaque.dm + opaque.group, silent };
1192
+ }
1193
+
1194
+ /**
1195
+ * Threads a conversation list never marks gone: the account's own uid and its
1196
+ * My Documents chat (`loginInfo.send2me_id`).
1197
+ *
1198
+ * The friend list never holds the self-chat, so a restore can list it under an
1199
+ * id the cache does not use, or not map it at all -- and its media is what the
1200
+ * owner saved to themselves.
1201
+ *
1202
+ * @param {object} api
1203
+ * @param {string} ownId
1204
+ * @returns {string[]}
1205
+ */
1206
+ function ownThreadIds(api, ownId) {
1207
+ let send2me = null;
1208
+ try {
1209
+ send2me = api?.getContext?.()?.loginInfo?.send2me_id ?? null;
1210
+ } catch {
1211
+ /* no session context: the own uid is still kept */
1212
+ }
1213
+ return [ownId, send2me].filter(Boolean).map(String);
1214
+ }
1215
+
1216
+ /**
1217
+ * Record a restore's conversation list in zalo.db, so every later command
1218
+ * sees what it said -- prune-orphans and forget --orphans run long after the
1219
+ * list is gone.
1220
+ *
1221
+ * @param {object} res - SyncV2.restore() result
1222
+ * @param {{from: number}} win
1223
+ * @param {{startedAt?: number, keep?: string[]}} ctx - when the restore was started, and
1224
+ * the threads never to mark ({@link ownThreadIds})
1225
+ * @returns {object|null} the proof and what was recorded; null when nothing was
1226
+ */
1227
+ function recordRestoreList(res, win, ctx) {
1228
+ const startedAt = Number(ctx?.startedAt);
1229
+ if (!Number.isFinite(startedAt)) return null;
1230
+ const proof = conversationListProof(res, win);
1231
+ if (!proof.present.length) return null;
1232
+ const recorded = recordConversationList({
1233
+ present: proof.present,
1234
+ clearBefore: startedAt,
1235
+ markBefore: startedAt - LIST_CLOCK_SKEW_MS,
1236
+ markKinds: proof.markKinds,
1237
+ keep: ctx.keep || [],
1238
+ });
1239
+ return { ...proof, ...recorded };
1240
+ }
1241
+
1242
+ /**
1243
+ * Report a finished restore, in the words `sync-mobile --transfer` has always
1244
+ * used. Exit-free, and says what happened so `sync` can summarize it.
1245
+ *
1246
+ * Also records the restore's conversation list first (see recordRestoreList),
1247
+ * so the orphans it reports are the ones `sync-media --prune-orphans` and
1248
+ * `conv forget --orphans` will act on.
1249
+ *
1250
+ * @param {object} res - SyncV2.restore() result
1251
+ * @param {{label: string, days: number|null, from: number}} win
1252
+ * @param {{startedAt?: number, keep?: string[]}} [ctx] - see recordRestoreList
1253
+ * @returns {{status: "ok"|"partial"|"unconfirmed", reason: string}}
1254
+ */
1255
+ function reportRestore(res, win, ctx = {}) {
1256
+ // Before the early returns: a thread IN a partial list is still present.
1257
+ let list = null;
1258
+ try {
1259
+ list = recordRestoreList(res, win, ctx);
1260
+ } catch (e) {
1261
+ warning(`Could not record the conversation list: ${e.message}`);
1262
+ }
1263
+ if (res.conversations === 0 && res.reason === "empty-window") {
1264
+ // The phone answered; the window is just empty. Different problem,
1265
+ // different advice.
1266
+ success(`Nothing to restore — no conversation activity in ${win.label}.`);
1267
+ if (win.days) info("Pass a larger --days, or drop --days for full history.");
1268
+ return { status: "ok", reason: "phone confirmed: nothing missed in this window" };
1269
+ }
1270
+ if (res.reason === "partial" || res.reason === "socket-lost") {
1271
+ const how = res.reason === "socket-lost" ? "the connection dropped" : "the run was cut short";
1272
+ warning(
1273
+ `Partial restore: ${res.messagesSaved} message(s) from ${res.conversations} conversation(s) before ${how}.`,
1274
+ );
1275
+ info("What arrived is stored. Re-run with --force to fetch the rest.");
1276
+ if (res.reason === "socket-lost" && res.resumes) {
1277
+ info(`The connection was re-established ${res.resumes} time(s) and dropped again.`);
1278
+ }
1279
+ return { status: "partial", reason: `${res.messagesSaved} message(s) before ${how}` };
1280
+ }
1281
+ if (res.conversations === 0) {
1282
+ warning("No conversations returned — the phone prompt may not have been confirmed in time. Try again.");
1283
+ return { status: "unconfirmed", reason: "the phone prompt was not confirmed in time" };
1284
+ }
1285
+ success(
1286
+ `Restored ${res.messagesSaved} message(s) from ${res.conversations} conversation(s) (${win.label}) into the local cache.`,
1287
+ );
1288
+ info(
1289
+ `Threads resolved to real ids/names: ${res.threadsMapped}; unresolved (non-friend or OA): ${res.threadsUnmapped}.`,
1290
+ );
1291
+ const breakdown = Object.entries(res.typeCounts || {})
1292
+ .sort((a, b) => b[1] - a[1])
1293
+ .slice(0, 8)
1294
+ .map(([t, c]) => `${t} ${c}`)
1295
+ .join(", ");
1296
+ if (breakdown) info(`By type: ${breakdown}.`);
1297
+ if (res.attachmentsSaved) info(`${res.attachmentsSaved} message(s) carry media.`);
1298
+ // The RECORDED orphans -- this restore's list included -- read exactly as
1299
+ // the two commands recommended below read them. This used to pass the
1300
+ // list straight in, which reported conversations neither command could see.
1301
+ try {
1302
+ const orphans = getOrphanThreads();
1303
+ const withData = orphans.filter((t) => (t.messages || 0) + (t.files || 0) > 0);
1304
+ if (withData.length) {
1305
+ const files = withData.reduce((n, t) => n + (t.files || 0), 0);
1306
+ warning(
1307
+ `${withData.length} conversation(s) are no longer on your account but still cached here (${files} downloaded file(s)).`,
1308
+ );
1309
+ info("Reclaim the space with `zalo-agent sync-media --prune-orphans`,");
1310
+ info("or remove them entirely with `zalo-agent conv forget --orphans`.");
1311
+ }
1312
+ if (list?.complete && list.unproven) {
1313
+ const why = [];
1314
+ if (list.unresolved)
1315
+ why.push(`${list.unresolved} listed conversation(s) could not be matched to a thread id`);
1316
+ if (list.silent) why.push(`${list.silent} listed conversation(s) returned no messages`);
1317
+ if (!why.length) why.push("their kind (DM or group) is not recorded");
1318
+ info(
1319
+ `${list.unproven} other cached conversation(s) are missing from the conversation list but were not marked gone: ${why.join("; ")}.`,
1320
+ );
1321
+ }
1322
+ } catch {
1323
+ /* orphan reporting must never fail a successful restore */
1324
+ }
1325
+ return { status: "ok", reason: `${res.messagesSaved} message(s) from ${res.conversations} conversation(s)` };
1326
+ }
1327
+
1328
+ /**
1329
+ * Download everything the restore just recorded.
1330
+ *
1331
+ * Scoped to the window just synced and never to pruned media, but otherwise
1332
+ * uncapped: the point of a default-on fetch is that a restored
1333
+ * conversation is complete, and a silent 500-file ceiling would leave it not
1334
+ * obviously broken. Interrupting is safe -- `sync-media` resumes from whatever
1335
+ * still has no localPath.
1336
+ *
1337
+ * @param {string} accountDir
1338
+ * @param {object|null} api - needed only to renew expired links
1339
+ */
1340
+ async function fetchMediaAfterRestore(accountDir, api, since) {
1341
+ const pending = countPendingAttachments();
1342
+ if (!pending) return null;
1343
+
1344
+ info(`Downloading ${pending} attachment(s) — no phone confirmation needed. Ctrl-C is safe; it resumes.`);
1345
+ let last = 0;
1346
+ // Tallied here rather than read off the result: the result does not exist
1347
+ // until the whole download resolves, so progress lines would all read 0 B.
1348
+ let bytes = 0;
1349
+ const stats = await downloadSyncedMedia({
1350
+ api,
1351
+ accountDir,
1352
+ limit: Number.MAX_SAFE_INTEGER,
1353
+ // Only media inside the window this run actually covered, and never
1354
+ // anything deliberately pruned. Without both, a sync silently undoes a
1355
+ // `sync-media --prune`: pruning clears localPath to requeue the row, so
1356
+ // an unscoped fetch re-downloads exactly what was just deleted.
1357
+ since: Number.isFinite(since) && since > 0 ? since : undefined,
1358
+ includePruned: false,
1359
+ concurrency: 4,
1360
+ threadNames: getThreadNames(),
1361
+ onProgress: (p) => {
1362
+ if (p.phase !== "saved") return;
1363
+ bytes += p.bytes || 0;
1364
+ if (p.done === p.total || p.done - last >= 50) {
1365
+ last = p.done;
1366
+ info(` ${p.done}/${p.total} files (${formatBytes(bytes)})`);
1367
+ }
1368
+ },
1369
+ });
1370
+ success(`Downloaded ${stats.downloaded}/${stats.considered} file(s) (${formatBytes(stats.bytes)}).`);
1371
+ if (stats.renewed) info(`Renewed ${stats.renewed} expired link(s).`);
1372
+ if (stats.expired) {
1373
+ warning(`${stats.expired} link(s) are gone and could not be renewed.`);
1374
+ info("Zalo keeps media for a limited time; past that the file exists only on the sending device.");
1375
+ }
1376
+ if (stats.throttled) {
1377
+ warning(
1378
+ `${stats.throttled} request(s) were rate limited (${describeDownloadReasons(stats.reasons, "throttled")}).`,
1379
+ );
1380
+ info("Re-run `zalo-agent sync-media` later to pick them up; a lower --concurrency helps.");
1381
+ }
1382
+ if (stats.unknown) {
1383
+ warning(
1384
+ `${stats.unknown} request(s) failed without saying why (${describeDownloadReasons(stats.reasons, "unknown")}).`,
1385
+ );
1386
+ info("403 is ambiguous — a lapsed signature and load look identical. Re-run `zalo-agent sync-media` first;");
1387
+ info("if they keep failing, only a fresh `zalo-agent sync --from <YYYY-MM-DD>` can hand back a new link.");
1388
+ }
1389
+ if (stats.abortedEarly) warning("Media stopped early after too many unusable responses; nothing is lost.");
1390
+ return stats;
1391
+ }
1392
+
1393
+ /**
1394
+ * Stop the listener and wait for its socket to actually close.
1395
+ *
1396
+ * stop() returns at once, but the socket's own onclose runs later and resets
1397
+ * the listener a second time. Releasing daemon.lock before that lands would let
1398
+ * a `listen` started in the gap be nulled by our late reset. Bounded, so a
1399
+ * socket that already died cannot hang the run.
1400
+ *
1401
+ * @param {object} api
1402
+ * @param {number} [ms=3000]
1403
+ * @returns {Promise<void>}
1404
+ */
1405
+ function closeListener(api, ms = 3000) {
1406
+ return new Promise((res) => {
1407
+ let settled = false;
1408
+ const finish = () => {
1409
+ if (settled) return;
1410
+ settled = true;
1411
+ clearTimeout(timer);
1412
+ res();
1413
+ };
1414
+ const timer = setTimeout(finish, ms);
1415
+ try {
1416
+ api.listener.once("closed", finish);
1417
+ api.listener.once("disconnected", finish);
1418
+ api.listener.stop();
1419
+ } catch {
1420
+ finish();
1421
+ }
1422
+ });
1423
+ }
1424
+
1425
+ /** True while the listener's socket is connecting or open. */
1426
+ function socketAlive(api) {
1427
+ const ws = api?.listener?.ws;
1428
+ return Boolean(ws) && ws.readyState <= 1;
1429
+ }
1430
+
1431
+ /** One line per stage, for the human summary. */
1432
+ const STATUS_MARK = { ok: "✓", partial: "◐", skipped: "–", unavailable: "○", unconfirmed: "?", failed: "✗" };
1433
+
1434
+ /**
1435
+ * Print a plan without running it.
1436
+ *
1437
+ * @param {object} plan - planSyncRun() result
1438
+ * @param {object} win - resolveSyncWindow() result
1439
+ * @param {boolean} jsonMode
1440
+ */
1441
+ function printPlan(plan, win, jsonMode) {
1442
+ output(
1443
+ {
1444
+ window: win.label,
1445
+ openSocket: plan.openSocket,
1446
+ viaDaemon: plan.viaDaemon,
1447
+ stages: plan.stages.map((s) => ({
1448
+ stage: s.name,
1449
+ transport: s.transport,
1450
+ run: s.run,
1451
+ via: s.via,
1452
+ wakesPhone: s.phone && s.run,
1453
+ why: s.why,
1454
+ })),
1455
+ },
1456
+ jsonMode,
1457
+ () => {
1458
+ info(`Plan for \`zalo-agent sync\` — ${win.label}. Nothing has been sent.`);
1459
+ if (plan.viaDaemon) {
1460
+ info("Runs the socket stages on the running listen/mcp daemon's socket — opens no WebSocket here,");
1461
+ info("stops nothing, and the daemon keeps capturing live messages throughout.");
1462
+ } else {
1463
+ info(plan.openSocket ? "Opens the WebSocket once, for the socket stages." : "Opens no WebSocket.");
1464
+ }
1465
+ for (const s of plan.stages) {
1466
+ const tag = s.run ? (s.phone ? "RUN (wakes your phone)" : "RUN") : "skip";
1467
+ // The transport column says HOW; this says WHOSE socket.
1468
+ const where = s.run && s.via === "daemon" ? `${s.transport}→daemon` : s.transport;
1469
+ console.log(` ${tag.padEnd(24)} ${s.name.padEnd(10)} ${where.padEnd(14)} ${s.why || s.label}`);
1470
+ }
1471
+ },
1472
+ );
1473
+ }
1474
+
1475
+ /**
1476
+ * One run that pulls every kind of message state the account has.
1477
+ *
1478
+ * Reactions, pinned conversations, notes, polls and reminders are all state
1479
+ * of the messages and conversations, and they were split across five
1480
+ * commands -- two of which each opened their own socket and took their own
1481
+ * lock, so a full refresh meant running five things in the right order and
1482
+ * evicting Zalo Web twice. This runs them as stages of one process: one lock,
1483
+ * one socket window shared by the socket stages, then the REST stages, and one
1484
+ * exit code at the end. The five commands remain for targeted re-runs.
1485
+ *
1486
+ * Order, and why:
1487
+ * 1. open the socket once, with a live-store tap throughout, so nothing
1488
+ * that arrives during the run is lost;
1489
+ * 2. restore messages (the only phone prompt, at most once), alone and
1490
+ * exactly as `sync-mobile --transfer` does -- running the reaction drain
1491
+ * beside it cost the restore its socket on every live attempt;
1492
+ * 3. drain the reaction backlog on the same socket;
1493
+ * 4. retry reactions whose message was not stored when they arrived;
1494
+ * 5. close the socket, wait for it, release the lock;
1495
+ * 6. REST stages: pinned/unread, boards, cloud, then media last.
1496
+ *
1497
+ * Never calls a run* function: those end the process. Only exit-free helpers.
1498
+ *
1499
+ * @param {{ownId: string}} activeAcc
1500
+ * @param {object} opts - command options
1501
+ * @param {boolean} jsonMode
1502
+ */
1503
+ async function runUnifiedSync(activeAcc, opts, jsonMode) {
1504
+ const accountDir = join(CONFIG_DIR, "accounts", activeAcc.ownId);
1505
+ initDb(join(accountDir, "zalo.db"));
1506
+
1507
+ let api;
1508
+ let syncManager;
1509
+ try {
1510
+ api = getApi();
1511
+ syncManager = new SyncManager(api, activeAcc.ownId);
1512
+ } catch (err) {
1513
+ error(`Failed: ${err.message}`);
1514
+ process.exit(1);
1515
+ }
1516
+
1517
+ const win = resolveSyncWindow(opts.days, Date.now(), opts.from);
1518
+ const freshness = syncManager.checkSyncFreshness({ force: opts.force, coversFrom: win.from });
1519
+ const want = {
1520
+ messages: opts.messages !== false,
1521
+ reactions: opts.reactions !== false,
1522
+ convState: opts.convState !== false,
1523
+ boards: opts.boards !== false,
1524
+ cloud: opts.cloud !== false,
1525
+ media: opts.media !== false,
1526
+ };
1527
+
1528
+ // A running listen/mcp daemon holds the account's one web session — and can
1529
+ // now run the socket stages on it. So a daemon being up no longer means
1530
+ // these stages are skipped, and the old recipe (stop it, sync, start it
1531
+ // again) is no longer the way to close a gap: the stop/start itself opened
1532
+ // a fresh ~70s hole with no repair path. See src/core/daemon-channel.js.
1533
+ const chan = getSyncChannel(accountDir);
1534
+
1535
+ if (opts.plan) {
1536
+ printPlan(
1537
+ planSyncRun({
1538
+ want,
1539
+ freshness,
1540
+ lockOk: !checkLock(accountDir).locked,
1541
+ daemonChannel: Boolean(chan),
1542
+ }),
1543
+ win,
1544
+ jsonMode,
1545
+ );
1546
+ process.exit(0);
1547
+ }
1548
+
1549
+ // Take the lock only if a socket stage could run HERE: REST stages need
1550
+ // neither the socket nor exclusivity, exactly as sync-boards and sync-media
1551
+ // never did, and a stage running on the daemon runs under the daemon's own
1552
+ // lock — taking it is neither possible nor wanted.
1553
+ const mightUseSocket = (want.messages && !freshness.skip) || want.reactions;
1554
+ const lockHeld = mightUseSocket && !chan ? acquireLock(accountDir) : false;
1555
+ // `lockOk` asks one thing: may THIS process open the socket? Moot when no
1556
+ // socket stage is wanted; no when a daemon is serving one (it holds the
1557
+ // lock, and `daemonChannel` is what turns that from a skip into a hand-off).
1558
+ const lockOk = !mightUseSocket ? true : chan ? false : lockHeld;
1559
+ const plan = planSyncRun({ want, freshness, lockOk, daemonChannel: Boolean(chan) });
1560
+ const runs = (name) => plan.stages.find((s) => s.name === name)?.run;
1561
+
1562
+ const results = [];
1563
+ const record = (stage, status, reason = "", stats = undefined) => results.push({ stage, status, reason, stats });
1564
+ for (const s of plan.stages) if (!s.run) record(s.name, "skipped", s.why);
1565
+
1566
+ // ---- socket stages on the running daemon's socket
1567
+ //
1568
+ // Nothing here opens a connection, takes the lock or stops anything. The
1569
+ // daemon runs each stage on the session it already holds and streams the
1570
+ // same progress callbacks back, so the run reads identically -- and it
1571
+ // keeps capturing live traffic throughout, which is the entire point:
1572
+ // the stop/sync/start recipe this replaces lost every message that
1573
+ // arrived in the ~70s the daemon was down.
1574
+ if (plan.viaDaemon) {
1575
+ info("A listen/mcp daemon holds this account's session — running the socket stages on it.");
1576
+ info("Nothing is stopped, so live capture continues while they run.");
1577
+
1578
+ if (runs("messages")) {
1579
+ info(`Restoring ${win.label}.`);
1580
+ if (win.clamped) info("(--days reaches past the oldest history this sync can request.)");
1581
+ // Unchanged by the hand-off. The daemon supplies the socket; only
1582
+ // the owner's phone can supply the history.
1583
+ warning("This sends ONE sync request to your phone — confirm the 'ĐỒNG BỘ NGAY' prompt when it appears.");
1584
+ const startedAt = Date.now();
1585
+ const r = await syncViaDaemon(accountDir, {
1586
+ stage: "messages",
1587
+ params: {
1588
+ days: opts.days ?? null,
1589
+ from: opts.from,
1590
+ shardSize: opts.shardSize,
1591
+ waitMs: Math.max(180, Number(opts.wait) || 0) * 1000,
1592
+ },
1593
+ onEvent: ({ phase, detail }) => {
1594
+ if (phase === "confirm") warning(detail);
1595
+ else if (detail) info(` ${detail}`);
1596
+ },
1597
+ });
1598
+ if (!r?.ok) {
1599
+ const why = daemonStageError(r);
1600
+ warning(`Message restore failed: ${why}`);
1601
+ record("messages", "failed", why);
1602
+ } else {
1603
+ const rep = reportRestore(r.result, win, { startedAt, keep: ownThreadIds(api, activeAcc.ownId) });
1604
+ record("messages", rep.status, rep.reason, {
1605
+ conversations: r.result.conversations,
1606
+ messagesSaved: r.result.messagesSaved,
1607
+ });
1608
+ }
1609
+ }
1610
+
1611
+ if (runs("reactions")) {
1612
+ info("Requesting the reaction backlog (cmd 610 for 1-1, 611 for groups)…");
1613
+ const r = await syncViaDaemon(accountDir, {
1614
+ stage: "reactions",
1615
+ params: { waitMs: DRAIN_WAIT_MS, maxPages: DRAIN_PAGES, applyRemovals: opts.removals !== false },
1616
+ onEvent: reactionProgress,
1617
+ });
1618
+ if (!r?.ok) {
1619
+ const why = daemonStageError(r);
1620
+ warning(`Reaction backlog failed: ${why}`);
1621
+ record("reactions", "failed", why);
1622
+ } else if (!r.result.received && r.result.socketAlive === false) {
1623
+ // Same rule as the local path: an empty drain on a dead socket
1624
+ // is a lost connection, not the caught-up queue it looks like.
1625
+ warning("Reaction backlog: the daemon's socket closed before it answered.");
1626
+ record("reactions", "failed", "socket closed before the backlog answered");
1627
+ } else {
1628
+ const rep = reportReactionStage(r.result, r.result.placed || 0, r.result.unresolvedLeft || 0);
1629
+ record("reactions", rep.status, rep.reason, rep.stats);
1630
+ }
1631
+ }
1632
+ }
1633
+
1634
+ // ---- socket window
1635
+ if (plan.openSocket) {
1636
+ let detachLive = () => {};
1637
+ // ONE heartbeat for the whole socket window, covering every socket
1638
+ // stage and the gaps between them.
1639
+ //
1640
+ // The socket is not unpinged without this -- zca-js sends Zalo's
1641
+ // `cmd 2/1` ping on the interval the server hands out at login, which
1642
+ // this account's login reports as 180000 ms, the same value a captured
1643
+ // Zalo Web session used. The problem is that 180 s is the entire width
1644
+ // of the phone wait: the restore sends nothing and receives nothing for
1645
+ // minutes, so the flow can sit silent right up against the server's own
1646
+ // liveness bound with no margin, and one late ping means six minutes of
1647
+ // silence. This pings at a third of that, and counts the echoes -- a
1648
+ // ping count running ahead of the echo count is the only trace a bare
1649
+ // 1006 (no close frame) ever leaves behind.
1650
+ //
1651
+ // It reads `listener.ws` fresh on every tick, so it keeps working
1652
+ // across the reconnect `reconnectListener` performs mid-restore.
1653
+ let heartbeat = null;
1654
+ try {
1655
+ info("Connecting…");
1656
+ const connected = await connectListener(api, 30000);
1657
+ if (!connected.ok) {
1658
+ const why =
1659
+ connected.reason === "duplicate"
1660
+ ? "another web session is open on this account (sign out of Zalo Web)"
1661
+ : `could not open a connection: ${connected.reason}`;
1662
+ warning(`Socket stages skipped — ${why}.`);
1663
+ for (const n of ["messages", "reactions"]) if (runs(n)) record(n, "failed", why);
1664
+ } else {
1665
+ syncManager.markConnected();
1666
+ heartbeat = startKeepAlive(api.listener);
1667
+
1668
+ // The restore runs FIRST and ALONE, exactly as `sync-mobile
1669
+ // --transfer` runs it -- its own live-store tap included. The
1670
+ // first version drained the reaction backlog concurrently, as
1671
+ // Zalo Web does on connect, and the restore then lost its socket
1672
+ // (close 1006) at batch 0 of 5 on both live attempts, right after
1673
+ // the phone confirmed. The same window on the same account
1674
+ // restored 11,324 messages through the old command minutes later.
1675
+ // Each half is proven alone, so they now run one after the other
1676
+ // on the same socket.
1677
+ if (runs("messages")) {
1678
+ info(`Restoring ${win.label}.`);
1679
+ if (win.clamped) info("(--days reaches past the oldest history this sync can request.)");
1680
+ warning(
1681
+ "This sends ONE sync request to your phone — confirm the 'ĐỒNG BỘ NGAY' prompt when it appears.",
1682
+ );
1683
+ try {
1684
+ const startedAt = Date.now();
1685
+ const res = await new SyncV2(api, activeAcc.ownId).restore({
1686
+ days: opts.days,
1687
+ from: opts.from,
1688
+ shardSize: opts.shardSize,
1689
+ waitMs: Math.max(180, Number(opts.wait) || 0) * 1000,
1690
+ // The window-level heartbeat above covers this stage.
1691
+ keepAlive: false,
1692
+ reconnect: () => reconnectListener(api),
1693
+ onStatus: ({ phase, detail }) => {
1694
+ if (phase === "confirm") warning(detail);
1695
+ else if (detail) info(` ${detail}`);
1696
+ },
1697
+ });
1698
+ const r = reportRestore(res, win, { startedAt, keep: ownThreadIds(api, activeAcc.ownId) });
1699
+ record("messages", r.status, r.reason, {
1700
+ conversations: res.conversations,
1701
+ messagesSaved: res.messagesSaved,
1702
+ });
1703
+ } catch (err) {
1704
+ warning(`Message restore failed: ${err.message}`);
1705
+ record("messages", "failed", err.message);
1706
+ }
1707
+ }
1708
+
1709
+ if (runs("reactions")) {
1710
+ // The restore detached its own tap; keep live traffic
1711
+ // captured for the rest of the socket window.
1712
+ detachLive = attachLiveStore(api.listener);
1713
+ const rx = await drainPass(api, {
1714
+ waitMs: DRAIN_WAIT_MS,
1715
+ pages: DRAIN_PAGES,
1716
+ removals: opts.removals,
1717
+ }).catch((e) => ({ error: e }));
1718
+ if (rx.error) {
1719
+ warning(`Reaction backlog failed: ${rx.error.message}`);
1720
+ record("reactions", "failed", rx.error.message);
1721
+ } else if (!rx.received && !socketAlive(api)) {
1722
+ // An empty drain on a dead socket is a lost connection,
1723
+ // not the "caught-up queue" an empty drain normally is.
1724
+ warning("Reaction backlog: the socket closed before it answered.");
1725
+ record("reactions", "failed", "socket closed before the backlog answered");
1726
+ } else {
1727
+ // A reaction naming only a client id is unresolvable until
1728
+ // its message is stored. The restore has run by now, but
1729
+ // the backlog reaches further back than a windowed one.
1730
+ const placed = placeUnresolvedReactions(rx.unresolved);
1731
+ const rep = reportReactionStage(rx, placed, (rx.unresolved?.length || 0) - placed);
1732
+ record("reactions", rep.status, rep.reason, rep.stats);
1733
+ }
1734
+ }
1735
+ }
1736
+ } catch (err) {
1737
+ warning(`Socket stages stopped: ${err.message}`);
1738
+ for (const n of ["messages", "reactions"]) {
1739
+ if (runs(n) && !results.some((r) => r.stage === n)) record(n, "failed", err.message);
1740
+ }
1741
+ } finally {
1742
+ try {
1743
+ heartbeat?.stop();
1744
+ } catch {
1745
+ /* already stopped */
1746
+ }
1747
+ try {
1748
+ detachLive();
1749
+ } catch {
1750
+ /* already detached */
1751
+ }
1752
+ await closeListener(api);
1753
+ if (lockHeld) releaseLock(accountDir);
1754
+ }
1755
+ } else if (lockHeld) {
1756
+ releaseLock(accountDir);
1757
+ }
1758
+
1759
+ // ---- REST stages, after the socket is closed and the lock released
1760
+ if (runs("convState")) {
1761
+ try {
1762
+ info("Reading pinned and unread-marked conversations…");
1763
+ const st = await syncConvState({ api });
1764
+ success(
1765
+ `Pinned: ${st.pinned}${st.unpinned ? ` (${st.unpinned} unpinned elsewhere)` : ""}; ` +
1766
+ `unread-marked: ${st.unread}${st.unmarked ? ` (${st.unmarked} cleared elsewhere)` : ""}.`,
1767
+ );
1768
+ if (st.unresolved || st.ambiguous) {
1769
+ info(
1770
+ `${st.unresolved} conversation(s) not in the local cache` +
1771
+ (st.ambiguous ? `, ${st.ambiguous} unread mark(s) matching more than one thread` : "") +
1772
+ " — left alone rather than guessed.",
1773
+ );
1774
+ }
1775
+ record(
1776
+ "convState",
1777
+ st.failures.length ? (st.failures.length === 2 ? "failed" : "partial") : "ok",
1778
+ st.failures.map((f) => `${f.what}: ${f.reason}`).join("; "),
1779
+ { pinned: st.pinned, unread: st.unread, unresolved: st.unresolved, ambiguous: st.ambiguous },
1780
+ );
1781
+ } catch (err) {
1782
+ warning(`Conversation state failed: ${err.message}`);
1783
+ record("convState", "failed", err.message);
1784
+ }
1785
+ }
1786
+
1787
+ if (runs("boards")) {
1788
+ try {
1789
+ const r = await boardPass(api, { limit: 200, concurrency: 3, boards: true, reminders: true });
1790
+ if (r.status === "skipped") record("boards", "skipped", r.reason);
1791
+ else {
1792
+ record("boards", r.stats.failed ? "partial" : "ok", `${r.stats.failed} request(s) failed`, {
1793
+ boardItems: r.stats.boardItems,
1794
+ reminders: r.stats.reminders,
1795
+ threads: r.stats.threads,
1796
+ });
1797
+ }
1798
+ } catch (err) {
1799
+ warning(`Boards failed: ${err.message}`);
1800
+ record("boards", "failed", err.message);
1801
+ }
1802
+ }
1803
+
1804
+ if (runs("cloud")) {
1805
+ try {
1806
+ const r = await cloudPass(api, { pages: 50, pageSize: 300 });
1807
+ if (r.status === "unavailable") {
1808
+ // Not a failure: an account without zCloud answers exactly like
1809
+ // this, and `sync` must not exit 1 on every such account.
1810
+ info("zCloud index unavailable (zCloud off, or the endpoint changed).");
1811
+ record("cloud", "unavailable", r.stats.failures[0]?.reason || "no items readable");
1812
+ } else {
1813
+ record(
1814
+ "cloud",
1815
+ r.stats.complete ? "ok" : "partial",
1816
+ r.stats.complete ? "" : "stopped at the page cap",
1817
+ {
1818
+ items: r.stats.items,
1819
+ },
1820
+ );
1821
+ }
1822
+ } catch (err) {
1823
+ warning(`Cloud index failed: ${err.message}`);
1824
+ record("cloud", "failed", err.message);
1825
+ }
1826
+ }
1827
+
1828
+ if (runs("media")) {
1829
+ try {
1830
+ const since = Number(getSyncState("lastSyncOkFrom"));
1831
+ const m = await fetchMediaAfterRestore(accountDir, api, since);
1832
+ if (!m) record("media", "ok", "nothing waiting to download");
1833
+ else {
1834
+ const short = m.expired || m.throttled || m.unknown || m.abortedEarly;
1835
+ record("media", short ? "partial" : "ok", "", {
1836
+ downloaded: m.downloaded,
1837
+ considered: m.considered,
1838
+ expired: m.expired,
1839
+ throttled: m.throttled,
1840
+ unknown: m.unknown,
1841
+ reasons: m.reasons,
1842
+ });
1843
+ }
1844
+ } catch (err) {
1845
+ warning(`Media download stopped: ${err.message}`);
1846
+ info("The messages are stored. Run `zalo-agent sync-media` to retry the files.");
1847
+ record("media", "failed", err.message);
1848
+ }
1849
+ }
1850
+
1851
+ // ---- one summary, one exit code
1852
+ const order = plan.stages.map((s) => s.name);
1853
+ results.sort((a, b) => order.indexOf(a.stage) - order.indexOf(b.stage));
1854
+ const exitCode = results.some((r) => r.status === "failed") ? 1 : 0;
1855
+ output({ window: win.label, stages: results, exitCode }, jsonMode, () => {
1856
+ info("Summary:");
1857
+ for (const r of results) {
1858
+ console.log(
1859
+ ` ${STATUS_MARK[r.status] || "·"} ${r.stage.padEnd(10)} ${r.status.padEnd(12)} ${r.reason || ""}`,
1860
+ );
1861
+ }
1862
+ });
1863
+ process.exit(exitCode);
1864
+ }
1865
+
1866
+ /**
1867
+ * Best-effort backfill: ask Zalo's servers for old messages over the WebSocket
1868
+ * (socket cmd 510 for DMs, 511 for groups) and write whatever comes back into
1869
+ * zalo.db.
1870
+ *
1871
+ * HONEST STATUS, measured 2026-09-20: on the account this was developed
1872
+ * against, Zalo answers both commands with an EMPTY set — including when given
1873
+ * the exact `lastId` anchors Zalo Web itself sends. Zalo Web gets the same
1874
+ * empty answer and then falls back to `transfer-sync-v2` (socket cmd 590/591,
1875
+ * libsignal-encrypted), which is the only path observed carrying real data and
1876
+ * is NOT implemented here.
1877
+ *
1878
+ * DO NOT read "no phone contact" as a feature. The phone IS the data source:
1879
+ * the account owner confirmed that a real Zalo Web sync makes their phone show
1880
+ * a request notification, which means cmd 590 causes the server to wake the
1881
+ * phone, and the phone encrypts the payload that comes back as cmd 601. A run
1882
+ * of this command that leaves the phone silent has not synced anything.
1883
+ *
1884
+ * So this is a probe that costs nothing and occasionally may return something,
1885
+ * not a restore. What it improves on is harm, not capability: the version it
1886
+ * replaced pinged the owner's phone ~24 times per run chasing a retired REST
1887
+ * endpoint that could never answer. See agent/work/transfer-sync-v2/NOTES.md § Mobile sync.
1888
+ *
1889
+ * @param {{ownId: string, name?: string}} activeAcc
1890
+ * @param {{wait?: number}} opts
1891
+ */
1892
+ async function runSocketBackfill(activeAcc, opts) {
1893
+ const accountDir = join(CONFIG_DIR, "accounts", activeAcc.ownId);
1894
+
1895
+ // Build the SyncManager first so we can consult the local sync-freshness
1896
+ // marker BEFORE touching the network. A redundant run should neither open
1897
+ // a socket (which would evict a live Zalo Web session) nor, once the
1898
+ // transfer-sync path lands, wake the owner's phone — the same debounce Zalo
1899
+ // Web applies to its own "Đồng bộ tin nhắn".
1900
+ let api;
1901
+ let syncManager;
1902
+ try {
1903
+ api = getApi();
1904
+ syncManager = new SyncManager(api, activeAcc.ownId);
1905
+ } catch (err) {
1906
+ error(`Failed: ${err.message}`);
1907
+ process.exit(1);
1908
+ }
1909
+
1910
+ const freshness = syncManager.checkSyncFreshness({ force: opts.force });
1911
+ if (freshness.skip) {
1912
+ success(`Already synced ${formatAge(freshness.ageMs)} ago — skipping to avoid re-pinging the server.`);
1913
+ info(
1914
+ "Nothing looks missing since then. Pass --force to sync anyway, or run `zalo-agent listen` to keep the cache live.",
1915
+ );
1916
+ process.exit(0);
1917
+ }
1918
+
1919
+ // The backfill opens a WebSocket and writes to zalo.db, which is exactly
1920
+ // what the `listen` daemon does. One socket and one db writer per account.
1921
+ //
1922
+ // This is the ONE socket path that is not routed through a running
1923
+ // daemon's channel, and deliberately: cmd 510/511 is measured to answer
1924
+ // empty (see the docblock above), so a hand-off would be a socket path
1925
+ // built for an endpoint that cannot answer -- relocating the defect, not
1926
+ // fixing it. The real restore IS routed, so say so rather than repeating
1927
+ // "stop the daemon", which is no longer the answer to anything.
1928
+ if (!acquireLock(accountDir)) {
1929
+ error(`A listen daemon is already running for account ${activeAcc.ownId}.`);
1930
+ if (getSyncChannel(accountDir)) {
1931
+ info("You do not need to stop it: `zalo-agent sync` runs the socket stages on that daemon's socket.");
1932
+ info("This default path only asks cmd 510/511, which Zalo answers empty. The real restore is:");
1933
+ info(" zalo-agent sync");
1934
+ } else {
1935
+ info("Stop it first, or let it keep the cache up to date on its own — it writes the same rows.");
1936
+ info("(A daemon started with a working sync channel would let `zalo-agent sync` run without stopping it.)");
1937
+ }
1938
+ process.exit(1);
1939
+ }
1940
+
1941
+ const waitMs = Math.max(1, Number(opts.wait) || 30) * 1000;
1942
+ let exitCode = 1;
1943
+
1944
+ try {
1945
+ info("Connecting…");
1946
+ const connected = await connectListener(api, waitMs);
1947
+
1948
+ if (!connected.ok) {
1949
+ if (connected.reason === "duplicate") {
1950
+ error("Zalo closed this connection: another web session is already open on this account.");
1951
+ info("Zalo allows one web session per account. Sign out of Zalo Web, then run this again.");
1952
+ } else {
1953
+ error(`Could not open a connection: ${connected.reason}`);
1954
+ }
1955
+ } else {
1956
+ syncManager.markConnected();
1957
+ info("Requesting recent history from the server…");
1958
+ const res = await syncManager.backfillOverSocket(api.listener, {
1959
+ timeoutMs: waitMs,
1960
+ onBatch: ({ count, threadType }) => {
1961
+ info(` received ${count} ${threadType === 0 ? "direct" : "group"} message(s)`);
1962
+ },
1963
+ });
1964
+
1965
+ if (res.total === 0) {
1966
+ warning("No history returned — and your phone was never asked.");
1967
+ info(
1968
+ "A real Zalo sync notifies your phone, because the phone is the data source: Zalo Web sends " +
1969
+ "socket cmd 590, the server wakes the phone, the phone encrypts and uploads, and the payload " +
1970
+ "comes back as cmd 601. That handshake (transfer-sync-v2) is what `--transfer` runs; this " +
1971
+ "default path does not, so the absence of a notification on your phone means no real sync took place.",
1972
+ );
1973
+ info("For the real restore run: zalo-agent sync (or sync-mobile --transfer for messages alone)");
1974
+ exitCode = 0;
1975
+ } else {
1976
+ success(`Backfilled ${res.saved}/${res.total} message(s) into the local cache.`);
1977
+ if (res.reason === "timeout") {
1978
+ warning("Stopped on the wait limit — re-run with a longer --wait if you expected more.");
1979
+ }
1980
+ exitCode = 0;
1981
+ }
1982
+ }
1983
+ } catch (err) {
1984
+ error(`Failed: ${err.message}`);
1985
+ } finally {
1986
+ try {
1987
+ api.listener.stop();
1988
+ } catch {
1989
+ // Already closed — nothing to clean up.
1990
+ }
1991
+ releaseLock(accountDir);
1992
+ }
1993
+
1994
+ process.exit(exitCode);
1995
+ }
1996
+
1997
+ /**
1998
+ * The retired path, kept behind --legacy so the behavior stays inspectable.
1999
+ *
2000
+ * `/api/message/pull_mobile_msg` and `/api/message/get_crossdb` are still
2001
+ * present in Zalo Web's own bundle but have ZERO call sites in it — the client
2002
+ * moved to a WebSocket protocol (cmd 590/591, "transfer-sync-v2"). The
2003
+ * endpoints answer with an empty payload rather than an error, which is why
2004
+ * this used to look like "the phone hasn't replied yet" and retry for two
2005
+ * minutes, putting a notification on the owner's phone each time.
2006
+ *
2007
+ * It runs exactly once now.
2008
+ *
2009
+ * @param {{ownId: string}} activeAcc
2010
+ * @param {{force?: boolean}} opts
2011
+ */
2012
+ async function runLegacySync(activeAcc, opts) {
2013
+ warning(
2014
+ "--legacy uses an endpoint Zalo Web no longer calls; it answers empty. This pings your mobile app " +
2015
+ "and will most likely find nothing.",
2016
+ );
2017
+ try {
2018
+ const syncManager = new SyncManager(getApi(), activeAcc.ownId);
2019
+ const res = await syncManager.pollSync(0, 0, { force: !!opts.force });
2020
+
2021
+ switch (res.status) {
2022
+ case "already-synced":
2023
+ success("Already synced — no known missed messages since the last successful sync.");
2024
+ info("Pass --force to check anyway.");
2025
+ process.exit(0);
2026
+ break;
2027
+ case "saved":
2028
+ success(`Synced ${res.saved}/${res.total} message(s) from mobile into the local cache.`);
2029
+ process.exit(0);
2030
+ break;
2031
+ case "empty-or-unrecognized":
2032
+ success("Sync round-trip completed — nothing new to save.");
2033
+ process.exit(0);
2034
+ break;
2035
+ case "legacy-retired":
2036
+ error("The legacy mobile-sync endpoint returned nothing, as it now always does.");
2037
+ info("Run `zalo-agent sync-mobile` without --legacy to backfill over the WebSocket instead.");
2038
+ process.exit(1);
2039
+ break;
2040
+ case "crossdb-error":
2041
+ error(`Sync failed: ${res.error}`);
2042
+ process.exit(1);
2043
+ break;
2044
+ default:
2045
+ error(`Unrecognized sync result: ${res.status}`);
2046
+ process.exit(1);
2047
+ }
2048
+ } catch (err) {
2049
+ error(`Failed: ${err.message}`);
2050
+ process.exit(1);
2051
+ }
2052
+ }