@ardennguyen/zalo-agent-cli 2.5.9 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1492) hide show
  1. package/.env.example +23 -2
  2. package/DISCLAIMER.md +3 -3
  3. package/LICENSE +2 -3
  4. package/NOTICE +14 -34
  5. package/README.md +166 -72
  6. package/package.json +37 -19
  7. package/src/commands/account.js +369 -40
  8. package/src/commands/auto-reply.js +8 -25
  9. package/src/commands/bank.js +25 -6
  10. package/src/commands/catalog.js +54 -11
  11. package/src/commands/cloud.js +459 -0
  12. package/src/commands/conv.js +470 -287
  13. package/src/commands/db.js +442 -0
  14. package/src/commands/fleet.js +449 -41
  15. package/src/commands/friend.js +198 -45
  16. package/src/commands/group.js +256 -43
  17. package/src/commands/label.js +16 -2
  18. package/src/commands/listen.js +495 -122
  19. package/src/commands/login.js +313 -117
  20. package/src/commands/mcp-approver.js +103 -0
  21. package/src/commands/mcp-webhook.js +13 -5
  22. package/src/commands/mcp.js +800 -104
  23. package/src/commands/msg-media.js +187 -0
  24. package/src/commands/msg-search.js +219 -0
  25. package/src/commands/msg.js +414 -110
  26. package/src/commands/oa/calls.js +134 -0
  27. package/src/commands/oa/content.js +266 -0
  28. package/src/commands/oa/gmf.js +429 -0
  29. package/src/commands/oa/messages.js +355 -0
  30. package/src/commands/oa/users.js +502 -0
  31. package/src/commands/oa-init.js +122 -123
  32. package/src/commands/oa-listen.js +374 -150
  33. package/src/commands/oa.js +83 -598
  34. package/src/commands/policy.js +224 -0
  35. package/src/commands/poll.js +3 -0
  36. package/src/commands/presence.js +175 -0
  37. package/src/commands/profile.js +45 -94
  38. package/src/commands/quick-msg.js +26 -0
  39. package/src/commands/read.js +172 -0
  40. package/src/commands/reminder.js +34 -4
  41. package/src/commands/social.js +223 -0
  42. package/src/commands/sync.js +482 -158
  43. package/src/commands/write.js +85 -0
  44. package/src/commands/zbs.js +502 -0
  45. package/src/core/account-devices.js +76 -0
  46. package/src/core/account-state.js +167 -0
  47. package/src/core/account-status.js +355 -0
  48. package/src/core/accounts.js +11 -4
  49. package/src/core/admin-api.js +392 -0
  50. package/src/core/approval.js +271 -0
  51. package/src/core/auto-reply.js +27 -0
  52. package/src/core/bank-accounts.js +1 -1
  53. package/src/core/block-sharing.js +43 -0
  54. package/src/core/board-pass.js +94 -0
  55. package/src/core/cached-message.js +78 -8
  56. package/src/core/cloud-plan.js +285 -0
  57. package/src/core/cloud-verify.js +305 -0
  58. package/src/core/confirm-guard.js +808 -0
  59. package/src/core/contact-names.js +504 -0
  60. package/src/core/control-events.js +525 -0
  61. package/src/core/control-replay.js +106 -0
  62. package/src/core/conversation-actions.js +214 -0
  63. package/src/core/credentials.js +112 -11
  64. package/src/core/current-user-names.js +60 -26
  65. package/src/core/daemon-channel.js +296 -15
  66. package/src/core/daemon-health.js +110 -7
  67. package/src/core/daemon-presence.js +455 -0
  68. package/src/core/daemon-sync.js +58 -18
  69. package/src/core/data-export.js +610 -0
  70. package/src/core/db-tools.js +473 -0
  71. package/src/core/db.js +1327 -83
  72. package/src/core/deploy-policy.js +560 -0
  73. package/src/core/device-since.js +123 -0
  74. package/src/core/e2ee-notice.js +41 -0
  75. package/src/core/exit-codes.js +7 -0
  76. package/src/core/export-crypt.js +290 -0
  77. package/src/core/fleet-controller.js +340 -0
  78. package/src/core/fleet-purge.js +144 -0
  79. package/src/core/fleet-qr.js +273 -0
  80. package/src/core/fleet-serve.js +292 -0
  81. package/src/core/fleet-supervisor.js +176 -0
  82. package/src/core/fleet-templates.js +568 -39
  83. package/src/core/fleet.js +232 -20
  84. package/src/core/friend-requests.js +80 -16
  85. package/src/core/friend-search.js +1 -1
  86. package/src/core/group-admin.js +2 -29
  87. package/src/core/group-departure.js +233 -0
  88. package/src/core/group-exit.js +621 -0
  89. package/src/core/group-members.js +21 -9
  90. package/src/core/group-settings.js +5 -207
  91. package/src/core/hidden-chat-actions.js +96 -0
  92. package/src/core/hidden-chats.js +425 -0
  93. package/src/core/history-fetch.js +81 -27
  94. package/src/core/keystore/config.js +163 -0
  95. package/src/core/keystore/container.js +208 -0
  96. package/src/core/keystore/index.js +483 -0
  97. package/src/core/keystore/keyring.js +588 -0
  98. package/src/core/keystore/kms.js +157 -0
  99. package/src/core/keystore/media-seal.js +711 -0
  100. package/src/core/keystore/providers.js +492 -0
  101. package/src/core/keystore/stores.js +177 -0
  102. package/src/core/keystore/worker.js +80 -0
  103. package/src/core/kick-marker.js +61 -0
  104. package/src/core/last-online.js +236 -0
  105. package/src/core/list-all.js +280 -0
  106. package/src/core/listener-lifecycle.js +101 -10
  107. package/src/core/live-api.js +1 -1
  108. package/src/core/live-store.js +111 -53
  109. package/src/core/local-reads.js +16 -0
  110. package/src/core/logout.js +102 -140
  111. package/src/core/media-deliver.js +732 -0
  112. package/src/core/media-route.js +347 -0
  113. package/src/core/media-store.js +408 -0
  114. package/src/core/mutual-groups.js +94 -0
  115. package/src/core/name-refresh.js +135 -0
  116. package/src/core/oa/calls.js +212 -0
  117. package/src/core/oa/content.js +390 -0
  118. package/src/core/oa/gmf.js +537 -0
  119. package/src/core/oa/messages.js +470 -0
  120. package/src/core/oa/oauth.js +422 -0
  121. package/src/core/oa/transport.js +645 -0
  122. package/src/core/oa/users.js +694 -0
  123. package/src/core/oa-client.js +49 -415
  124. package/src/core/overflow-repair.js +221 -0
  125. package/src/core/policy-layer.js +55 -0
  126. package/src/core/policy-schema.js +401 -0
  127. package/src/core/policy-store.js +1058 -0
  128. package/src/core/presence-config.js +100 -0
  129. package/src/core/presence-leases.js +211 -0
  130. package/src/core/presence.js +688 -0
  131. package/src/core/profile-settings.js +243 -0
  132. package/src/core/qr-login-flow.js +237 -0
  133. package/src/core/read-state.js +145 -22
  134. package/src/core/receipts.js +355 -548
  135. package/src/core/recent-conversations.js +28 -6
  136. package/src/core/row-mac.js +405 -0
  137. package/src/core/search.js +271 -0
  138. package/src/core/secure-page.js +771 -0
  139. package/src/core/self-heal.js +493 -34
  140. package/src/core/session-expiry.js +103 -0
  141. package/src/core/session-notice.js +249 -0
  142. package/src/core/social/client.js +296 -0
  143. package/src/core/social/dpop.js +54 -0
  144. package/src/core/socket-host.js +437 -0
  145. package/src/core/sqlite.js +520 -0
  146. package/src/core/startup-gate.js +49 -5
  147. package/src/core/storage-quota.js +796 -0
  148. package/src/core/sync-action.js +180 -0
  149. package/src/core/sync-v2/auto-sync.js +356 -0
  150. package/src/core/sync-v2/board.js +130 -92
  151. package/src/core/sync-v2/conv-state.js +21 -4
  152. package/src/core/sync-v2/gap-advice.js +2 -3
  153. package/src/core/sync-v2/index.js +739 -323
  154. package/src/core/sync-v2/media.js +116 -27
  155. package/src/core/sync-v2/plan.js +16 -2
  156. package/src/core/sync-v2/ranges.js +98 -0
  157. package/src/core/sync-v2/reactions.js +12 -196
  158. package/src/core/sync-v2/senders.js +32 -14
  159. package/src/core/sync-v2/zcloud.js +177 -579
  160. package/src/core/sync.js +23 -21
  161. package/src/core/test-fake-session.js +87 -0
  162. package/src/core/typing.js +78 -0
  163. package/src/core/unknown-acts.js +240 -0
  164. package/src/core/voice-text.js +171 -0
  165. package/src/core/webhook-outbox.js +110 -12
  166. package/src/core/zalo-client.js +147 -188
  167. package/src/core/zbs/api.js +505 -0
  168. package/src/core/zbs/image.js +85 -0
  169. package/src/core/zbs/phone.js +59 -0
  170. package/src/core/zbs/rsa.js +129 -0
  171. package/src/core/zbs/template-check.js +449 -0
  172. package/src/index.js +60 -10
  173. package/src/mcp/action-tool.js +188 -0
  174. package/src/mcp/actions-business.js +488 -0
  175. package/src/mcp/actions-conversation.js +633 -0
  176. package/src/mcp/actions-media.js +268 -0
  177. package/src/mcp/actions-profile.js +281 -0
  178. package/src/mcp/actions-social.js +518 -0
  179. package/src/mcp/instructions.js +19 -5
  180. package/src/mcp/mcp-config.js +112 -10
  181. package/src/mcp/mcp-http-transport.js +162 -25
  182. package/src/mcp/mcp-server.js +14 -3
  183. package/src/mcp/mcp-tools.js +1686 -384
  184. package/src/mcp/message-buffer.js +58 -12
  185. package/src/mcp/notifier.js +1 -1
  186. package/src/mcp/official-tool.js +298 -0
  187. package/src/mcp/sync-jobs.js +7 -1
  188. package/src/mcp/sync-stages.js +72 -0
  189. package/src/mcp/thread-name-cache.js +43 -5
  190. package/src/mcp/tool-presence.js +153 -0
  191. package/src/mcp/wait-batch.js +27 -0
  192. package/src/mcp/wait-result.js +19 -21
  193. package/src/utils/bank-helpers.js +52 -1
  194. package/src/utils/cli-args.js +12 -12
  195. package/src/utils/date-range.js +50 -0
  196. package/src/utils/hidden-access.js +141 -0
  197. package/src/utils/interrupt.js +37 -0
  198. package/src/utils/json-input.js +41 -0
  199. package/src/utils/list-replies.js +60 -0
  200. package/src/utils/my-documents.js +2 -3
  201. package/src/utils/output.js +66 -2
  202. package/src/utils/qr-display.js +14 -8
  203. package/src/utils/qr-http-server.js +674 -134
  204. package/src/utils/quote.js +8 -8
  205. package/src/utils/secret-input.js +57 -0
  206. package/src/utils/vn-text.js +72 -0
  207. package/src/zalo/README.md +46 -0
  208. package/src/zalo/anomaly-store.js +49 -0
  209. package/src/zalo/api/actions.js +670 -0
  210. package/src/zalo/api/boards.js +1036 -0
  211. package/src/zalo/api/business.js +662 -0
  212. package/src/zalo/api/conversations.js +329 -0
  213. package/src/zalo/api/groups.js +631 -0
  214. package/src/zalo/api/messages.js +695 -0
  215. package/src/zalo/api/people.js +711 -0
  216. package/src/zalo/api/profile.js +374 -0
  217. package/src/zalo/api/session.js +45 -0
  218. package/src/zalo/api/upload.js +976 -0
  219. package/src/zalo/api.js +117 -0
  220. package/src/zalo/client.js +206 -0
  221. package/src/zalo/custom/forward.js +199 -0
  222. package/src/zalo/custom/gid.js +123 -0
  223. package/src/zalo/custom/group-history.js +246 -0
  224. package/src/zalo/custom/group-invite.js +53 -0
  225. package/src/zalo/custom/group-settings.js +186 -0
  226. package/src/zalo/custom/group-visibility.js +71 -0
  227. package/src/zalo/custom/pin.js +220 -0
  228. package/src/zalo/custom/renewlink.js +115 -0
  229. package/src/zalo/device-fingerprint.js +33 -0
  230. package/src/zalo/download-fetch.js +45 -0
  231. package/src/zalo/enums.js +25 -0
  232. package/src/zalo/errors.js +195 -0
  233. package/src/zalo/format/mentions.js +140 -0
  234. package/src/zalo/format/split-message.js +222 -0
  235. package/src/zalo/format/urgency.js +29 -0
  236. package/src/zalo/headers.js +93 -0
  237. package/src/zalo/index.js +72 -0
  238. package/src/zalo/kernel/atomic-file.js +217 -0
  239. package/src/zalo/kernel/bound.js +46 -0
  240. package/src/zalo/kernel/cipher.js +88 -0
  241. package/src/zalo/kernel/cookies.js +125 -0
  242. package/src/zalo/kernel/endpoint.js +211 -0
  243. package/src/zalo/kernel/http.js +360 -0
  244. package/src/zalo/kernel/json-ids.js +118 -0
  245. package/src/zalo/kernel/login-cipher.js +165 -0
  246. package/src/zalo/kernel/secret-file.js +45 -0
  247. package/src/zalo/kernel/session.js +261 -0
  248. package/src/zalo/kernel/zcloud-cipher.js +83 -0
  249. package/src/zalo/kickout.js +136 -0
  250. package/src/zalo/listener/dispatch.js +404 -0
  251. package/src/zalo/listener/frames.js +222 -0
  252. package/src/zalo/listener/friend-events.js +113 -0
  253. package/src/zalo/listener/group-events.js +117 -0
  254. package/src/zalo/listener/keepalive.js +191 -0
  255. package/src/zalo/listener/listener.js +469 -0
  256. package/src/zalo/listener/models.js +220 -0
  257. package/src/zalo/listener/reactions.js +224 -0
  258. package/src/zalo/listener/socket-tap.js +228 -0
  259. package/src/zalo/login.js +387 -0
  260. package/src/zalo/logout.js +192 -0
  261. package/src/zalo/maintenance.js +183 -0
  262. package/src/zalo/official-logout.js +254 -0
  263. package/src/zalo/paging.js +114 -0
  264. package/src/zalo/profile.js +184 -0
  265. package/src/zalo/pulls.js +129 -0
  266. package/src/zalo/qr-image.js +90 -0
  267. package/src/zalo/qr-login.js +494 -0
  268. package/src/zalo/queues/control-queue.js +193 -0
  269. package/src/zalo/queues/offline-queue.js +275 -0
  270. package/src/zalo/queues/queue-verify.js +306 -0
  271. package/src/zalo/reads.js +723 -0
  272. package/src/zalo/receipts.js +550 -0
  273. package/src/zalo/req-id.js +24 -0
  274. package/src/zalo/retry.js +343 -0
  275. package/src/zalo/session-call.js +55 -0
  276. package/src/zalo/socket.js +762 -0
  277. package/src/zalo/transfer-sync/assets.js +181 -0
  278. package/src/zalo/transfer-sync/channel.js +459 -0
  279. package/src/zalo/transfer-sync/download.js +161 -0
  280. package/src/zalo/transfer-sync/message-types.js +520 -0
  281. package/src/zalo/transfer-sync/transfer.js +468 -0
  282. package/src/zalo/trust-store.js +99 -0
  283. package/src/zalo/trust-wasm.js +393 -0
  284. package/src/zalo/upkeep.js +127 -0
  285. package/src/zalo/web-call.js +103 -0
  286. package/src/zalo/writes.js +704 -0
  287. package/src/zalo/zcloud-e2ee.js +214 -0
  288. package/src/zalo/zcloud.js +802 -0
  289. package/node_modules/asynckit/LICENSE +0 -21
  290. package/node_modules/asynckit/README.md +0 -233
  291. package/node_modules/asynckit/bench.js +0 -76
  292. package/node_modules/asynckit/index.js +0 -6
  293. package/node_modules/asynckit/lib/abort.js +0 -29
  294. package/node_modules/asynckit/lib/async.js +0 -34
  295. package/node_modules/asynckit/lib/defer.js +0 -26
  296. package/node_modules/asynckit/lib/iterate.js +0 -75
  297. package/node_modules/asynckit/lib/readable_asynckit.js +0 -91
  298. package/node_modules/asynckit/lib/readable_parallel.js +0 -25
  299. package/node_modules/asynckit/lib/readable_serial.js +0 -25
  300. package/node_modules/asynckit/lib/readable_serial_ordered.js +0 -29
  301. package/node_modules/asynckit/lib/state.js +0 -37
  302. package/node_modules/asynckit/lib/streamify.js +0 -141
  303. package/node_modules/asynckit/lib/terminator.js +0 -29
  304. package/node_modules/asynckit/package.json +0 -63
  305. package/node_modules/asynckit/parallel.js +0 -43
  306. package/node_modules/asynckit/serial.js +0 -17
  307. package/node_modules/asynckit/serialOrdered.js +0 -75
  308. package/node_modules/asynckit/stream.js +0 -21
  309. package/node_modules/bignumber.js/CHANGELOG.md +0 -381
  310. package/node_modules/bignumber.js/LICENCE.md +0 -26
  311. package/node_modules/bignumber.js/README.md +0 -289
  312. package/node_modules/bignumber.js/bignumber.d.mts +0 -6
  313. package/node_modules/bignumber.js/bignumber.d.ts +0 -5
  314. package/node_modules/bignumber.js/bignumber.js +0 -2922
  315. package/node_modules/bignumber.js/bignumber.mjs +0 -2907
  316. package/node_modules/bignumber.js/doc/API.html +0 -2249
  317. package/node_modules/bignumber.js/package.json +0 -60
  318. package/node_modules/bignumber.js/types.d.ts +0 -1821
  319. package/node_modules/call-bind-apply-helpers/.eslintrc +0 -17
  320. package/node_modules/call-bind-apply-helpers/.github/FUNDING.yml +0 -12
  321. package/node_modules/call-bind-apply-helpers/.nycrc +0 -9
  322. package/node_modules/call-bind-apply-helpers/CHANGELOG.md +0 -30
  323. package/node_modules/call-bind-apply-helpers/LICENSE +0 -21
  324. package/node_modules/call-bind-apply-helpers/README.md +0 -62
  325. package/node_modules/call-bind-apply-helpers/actualApply.d.ts +0 -1
  326. package/node_modules/call-bind-apply-helpers/actualApply.js +0 -10
  327. package/node_modules/call-bind-apply-helpers/applyBind.d.ts +0 -19
  328. package/node_modules/call-bind-apply-helpers/applyBind.js +0 -10
  329. package/node_modules/call-bind-apply-helpers/functionApply.d.ts +0 -1
  330. package/node_modules/call-bind-apply-helpers/functionApply.js +0 -4
  331. package/node_modules/call-bind-apply-helpers/functionCall.d.ts +0 -1
  332. package/node_modules/call-bind-apply-helpers/functionCall.js +0 -4
  333. package/node_modules/call-bind-apply-helpers/index.d.ts +0 -64
  334. package/node_modules/call-bind-apply-helpers/index.js +0 -15
  335. package/node_modules/call-bind-apply-helpers/package.json +0 -85
  336. package/node_modules/call-bind-apply-helpers/reflectApply.d.ts +0 -3
  337. package/node_modules/call-bind-apply-helpers/reflectApply.js +0 -4
  338. package/node_modules/call-bind-apply-helpers/test/index.js +0 -63
  339. package/node_modules/call-bind-apply-helpers/tsconfig.json +0 -9
  340. package/node_modules/combined-stream/License +0 -19
  341. package/node_modules/combined-stream/Readme.md +0 -138
  342. package/node_modules/combined-stream/lib/combined_stream.js +0 -208
  343. package/node_modules/combined-stream/package.json +0 -25
  344. package/node_modules/crypto-js/CONTRIBUTING.md +0 -28
  345. package/node_modules/crypto-js/LICENSE +0 -24
  346. package/node_modules/crypto-js/README.md +0 -275
  347. package/node_modules/crypto-js/aes.js +0 -234
  348. package/node_modules/crypto-js/blowfish.js +0 -471
  349. package/node_modules/crypto-js/bower.json +0 -39
  350. package/node_modules/crypto-js/cipher-core.js +0 -895
  351. package/node_modules/crypto-js/core.js +0 -807
  352. package/node_modules/crypto-js/crypto-js.js +0 -6657
  353. package/node_modules/crypto-js/docs/QuickStartGuide.wiki +0 -470
  354. package/node_modules/crypto-js/enc-base64.js +0 -136
  355. package/node_modules/crypto-js/enc-base64url.js +0 -148
  356. package/node_modules/crypto-js/enc-hex.js +0 -18
  357. package/node_modules/crypto-js/enc-latin1.js +0 -18
  358. package/node_modules/crypto-js/enc-utf16.js +0 -149
  359. package/node_modules/crypto-js/enc-utf8.js +0 -18
  360. package/node_modules/crypto-js/evpkdf.js +0 -134
  361. package/node_modules/crypto-js/format-hex.js +0 -66
  362. package/node_modules/crypto-js/format-openssl.js +0 -18
  363. package/node_modules/crypto-js/hmac-md5.js +0 -18
  364. package/node_modules/crypto-js/hmac-ripemd160.js +0 -18
  365. package/node_modules/crypto-js/hmac-sha1.js +0 -18
  366. package/node_modules/crypto-js/hmac-sha224.js +0 -18
  367. package/node_modules/crypto-js/hmac-sha256.js +0 -18
  368. package/node_modules/crypto-js/hmac-sha3.js +0 -18
  369. package/node_modules/crypto-js/hmac-sha384.js +0 -18
  370. package/node_modules/crypto-js/hmac-sha512.js +0 -18
  371. package/node_modules/crypto-js/hmac.js +0 -143
  372. package/node_modules/crypto-js/index.js +0 -18
  373. package/node_modules/crypto-js/lib-typedarrays.js +0 -76
  374. package/node_modules/crypto-js/md5.js +0 -268
  375. package/node_modules/crypto-js/mode-cfb.js +0 -80
  376. package/node_modules/crypto-js/mode-ctr-gladman.js +0 -116
  377. package/node_modules/crypto-js/mode-ctr.js +0 -58
  378. package/node_modules/crypto-js/mode-ecb.js +0 -40
  379. package/node_modules/crypto-js/mode-ofb.js +0 -54
  380. package/node_modules/crypto-js/package.json +0 -42
  381. package/node_modules/crypto-js/pad-ansix923.js +0 -49
  382. package/node_modules/crypto-js/pad-iso10126.js +0 -44
  383. package/node_modules/crypto-js/pad-iso97971.js +0 -40
  384. package/node_modules/crypto-js/pad-nopadding.js +0 -30
  385. package/node_modules/crypto-js/pad-pkcs7.js +0 -18
  386. package/node_modules/crypto-js/pad-zeropadding.js +0 -47
  387. package/node_modules/crypto-js/pbkdf2.js +0 -145
  388. package/node_modules/crypto-js/rabbit-legacy.js +0 -190
  389. package/node_modules/crypto-js/rabbit.js +0 -192
  390. package/node_modules/crypto-js/rc4.js +0 -139
  391. package/node_modules/crypto-js/ripemd160.js +0 -267
  392. package/node_modules/crypto-js/sha1.js +0 -150
  393. package/node_modules/crypto-js/sha224.js +0 -80
  394. package/node_modules/crypto-js/sha256.js +0 -199
  395. package/node_modules/crypto-js/sha3.js +0 -326
  396. package/node_modules/crypto-js/sha384.js +0 -83
  397. package/node_modules/crypto-js/sha512.js +0 -326
  398. package/node_modules/crypto-js/tripledes.js +0 -779
  399. package/node_modules/crypto-js/x64-core.js +0 -304
  400. package/node_modules/delayed-stream/.npmignore +0 -1
  401. package/node_modules/delayed-stream/License +0 -19
  402. package/node_modules/delayed-stream/Makefile +0 -7
  403. package/node_modules/delayed-stream/Readme.md +0 -141
  404. package/node_modules/delayed-stream/lib/delayed_stream.js +0 -107
  405. package/node_modules/delayed-stream/package.json +0 -27
  406. package/node_modules/dunder-proto/.eslintrc +0 -5
  407. package/node_modules/dunder-proto/.github/FUNDING.yml +0 -12
  408. package/node_modules/dunder-proto/.nycrc +0 -13
  409. package/node_modules/dunder-proto/CHANGELOG.md +0 -24
  410. package/node_modules/dunder-proto/LICENSE +0 -21
  411. package/node_modules/dunder-proto/README.md +0 -54
  412. package/node_modules/dunder-proto/get.d.ts +0 -5
  413. package/node_modules/dunder-proto/get.js +0 -30
  414. package/node_modules/dunder-proto/package.json +0 -76
  415. package/node_modules/dunder-proto/set.d.ts +0 -5
  416. package/node_modules/dunder-proto/set.js +0 -35
  417. package/node_modules/dunder-proto/test/get.js +0 -34
  418. package/node_modules/dunder-proto/test/index.js +0 -4
  419. package/node_modules/dunder-proto/test/set.js +0 -50
  420. package/node_modules/dunder-proto/tsconfig.json +0 -9
  421. package/node_modules/es-define-property/.eslintrc +0 -13
  422. package/node_modules/es-define-property/.github/FUNDING.yml +0 -12
  423. package/node_modules/es-define-property/.nycrc +0 -9
  424. package/node_modules/es-define-property/CHANGELOG.md +0 -29
  425. package/node_modules/es-define-property/LICENSE +0 -21
  426. package/node_modules/es-define-property/README.md +0 -49
  427. package/node_modules/es-define-property/index.d.ts +0 -3
  428. package/node_modules/es-define-property/index.js +0 -14
  429. package/node_modules/es-define-property/package.json +0 -81
  430. package/node_modules/es-define-property/test/index.js +0 -56
  431. package/node_modules/es-define-property/tsconfig.json +0 -10
  432. package/node_modules/es-errors/.eslintrc +0 -5
  433. package/node_modules/es-errors/.github/FUNDING.yml +0 -12
  434. package/node_modules/es-errors/CHANGELOG.md +0 -40
  435. package/node_modules/es-errors/LICENSE +0 -21
  436. package/node_modules/es-errors/README.md +0 -55
  437. package/node_modules/es-errors/eval.d.ts +0 -3
  438. package/node_modules/es-errors/eval.js +0 -4
  439. package/node_modules/es-errors/index.d.ts +0 -3
  440. package/node_modules/es-errors/index.js +0 -4
  441. package/node_modules/es-errors/package.json +0 -80
  442. package/node_modules/es-errors/range.d.ts +0 -3
  443. package/node_modules/es-errors/range.js +0 -4
  444. package/node_modules/es-errors/ref.d.ts +0 -3
  445. package/node_modules/es-errors/ref.js +0 -4
  446. package/node_modules/es-errors/syntax.d.ts +0 -3
  447. package/node_modules/es-errors/syntax.js +0 -4
  448. package/node_modules/es-errors/test/index.js +0 -19
  449. package/node_modules/es-errors/tsconfig.json +0 -49
  450. package/node_modules/es-errors/type.d.ts +0 -3
  451. package/node_modules/es-errors/type.js +0 -4
  452. package/node_modules/es-errors/uri.d.ts +0 -3
  453. package/node_modules/es-errors/uri.js +0 -4
  454. package/node_modules/es-object-atoms/.eslintrc +0 -16
  455. package/node_modules/es-object-atoms/.github/FUNDING.yml +0 -12
  456. package/node_modules/es-object-atoms/CHANGELOG.md +0 -44
  457. package/node_modules/es-object-atoms/LICENSE +0 -21
  458. package/node_modules/es-object-atoms/README.md +0 -63
  459. package/node_modules/es-object-atoms/RequireObjectCoercible.d.ts +0 -3
  460. package/node_modules/es-object-atoms/RequireObjectCoercible.js +0 -11
  461. package/node_modules/es-object-atoms/ToObject.d.ts +0 -7
  462. package/node_modules/es-object-atoms/ToObject.js +0 -10
  463. package/node_modules/es-object-atoms/index.d.ts +0 -3
  464. package/node_modules/es-object-atoms/index.js +0 -4
  465. package/node_modules/es-object-atoms/isObject.d.ts +0 -3
  466. package/node_modules/es-object-atoms/isObject.js +0 -6
  467. package/node_modules/es-object-atoms/package.json +0 -79
  468. package/node_modules/es-object-atoms/test/index.js +0 -38
  469. package/node_modules/es-object-atoms/tsconfig.json +0 -7
  470. package/node_modules/es-set-tostringtag/.eslintrc +0 -13
  471. package/node_modules/es-set-tostringtag/.nycrc +0 -9
  472. package/node_modules/es-set-tostringtag/CHANGELOG.md +0 -67
  473. package/node_modules/es-set-tostringtag/LICENSE +0 -21
  474. package/node_modules/es-set-tostringtag/README.md +0 -53
  475. package/node_modules/es-set-tostringtag/index.d.ts +0 -10
  476. package/node_modules/es-set-tostringtag/index.js +0 -35
  477. package/node_modules/es-set-tostringtag/package.json +0 -78
  478. package/node_modules/es-set-tostringtag/test/index.js +0 -85
  479. package/node_modules/es-set-tostringtag/tsconfig.json +0 -9
  480. package/node_modules/form-data/CHANGELOG.md +0 -686
  481. package/node_modules/form-data/License +0 -19
  482. package/node_modules/form-data/README.md +0 -355
  483. package/node_modules/form-data/index.d.ts +0 -62
  484. package/node_modules/form-data/lib/browser.js +0 -4
  485. package/node_modules/form-data/lib/form_data.js +0 -506
  486. package/node_modules/form-data/lib/populate.js +0 -10
  487. package/node_modules/form-data/node_modules/mime-db/HISTORY.md +0 -507
  488. package/node_modules/form-data/node_modules/mime-db/LICENSE +0 -23
  489. package/node_modules/form-data/node_modules/mime-db/README.md +0 -100
  490. package/node_modules/form-data/node_modules/mime-db/db.json +0 -8519
  491. package/node_modules/form-data/node_modules/mime-db/index.js +0 -12
  492. package/node_modules/form-data/node_modules/mime-db/package.json +0 -60
  493. package/node_modules/form-data/node_modules/mime-types/HISTORY.md +0 -397
  494. package/node_modules/form-data/node_modules/mime-types/LICENSE +0 -23
  495. package/node_modules/form-data/node_modules/mime-types/README.md +0 -113
  496. package/node_modules/form-data/node_modules/mime-types/index.js +0 -188
  497. package/node_modules/form-data/node_modules/mime-types/package.json +0 -44
  498. package/node_modules/form-data/package.json +0 -82
  499. package/node_modules/function-bind/.eslintrc +0 -21
  500. package/node_modules/function-bind/.github/FUNDING.yml +0 -12
  501. package/node_modules/function-bind/.github/SECURITY.md +0 -3
  502. package/node_modules/function-bind/.nycrc +0 -13
  503. package/node_modules/function-bind/CHANGELOG.md +0 -136
  504. package/node_modules/function-bind/LICENSE +0 -20
  505. package/node_modules/function-bind/README.md +0 -46
  506. package/node_modules/function-bind/implementation.js +0 -84
  507. package/node_modules/function-bind/index.js +0 -5
  508. package/node_modules/function-bind/package.json +0 -87
  509. package/node_modules/function-bind/test/.eslintrc +0 -9
  510. package/node_modules/function-bind/test/index.js +0 -252
  511. package/node_modules/get-intrinsic/.eslintrc +0 -42
  512. package/node_modules/get-intrinsic/.github/FUNDING.yml +0 -12
  513. package/node_modules/get-intrinsic/.nycrc +0 -9
  514. package/node_modules/get-intrinsic/CHANGELOG.md +0 -186
  515. package/node_modules/get-intrinsic/LICENSE +0 -21
  516. package/node_modules/get-intrinsic/README.md +0 -71
  517. package/node_modules/get-intrinsic/index.js +0 -378
  518. package/node_modules/get-intrinsic/package.json +0 -97
  519. package/node_modules/get-intrinsic/test/GetIntrinsic.js +0 -274
  520. package/node_modules/get-proto/.eslintrc +0 -10
  521. package/node_modules/get-proto/.github/FUNDING.yml +0 -12
  522. package/node_modules/get-proto/.nycrc +0 -9
  523. package/node_modules/get-proto/CHANGELOG.md +0 -21
  524. package/node_modules/get-proto/LICENSE +0 -21
  525. package/node_modules/get-proto/Object.getPrototypeOf.d.ts +0 -5
  526. package/node_modules/get-proto/Object.getPrototypeOf.js +0 -6
  527. package/node_modules/get-proto/README.md +0 -50
  528. package/node_modules/get-proto/Reflect.getPrototypeOf.d.ts +0 -3
  529. package/node_modules/get-proto/Reflect.getPrototypeOf.js +0 -4
  530. package/node_modules/get-proto/index.d.ts +0 -5
  531. package/node_modules/get-proto/index.js +0 -27
  532. package/node_modules/get-proto/package.json +0 -81
  533. package/node_modules/get-proto/test/index.js +0 -68
  534. package/node_modules/get-proto/tsconfig.json +0 -9
  535. package/node_modules/gopd/.eslintrc +0 -16
  536. package/node_modules/gopd/.github/FUNDING.yml +0 -12
  537. package/node_modules/gopd/CHANGELOG.md +0 -45
  538. package/node_modules/gopd/LICENSE +0 -21
  539. package/node_modules/gopd/README.md +0 -40
  540. package/node_modules/gopd/gOPD.d.ts +0 -1
  541. package/node_modules/gopd/gOPD.js +0 -4
  542. package/node_modules/gopd/index.d.ts +0 -5
  543. package/node_modules/gopd/index.js +0 -15
  544. package/node_modules/gopd/package.json +0 -77
  545. package/node_modules/gopd/test/index.js +0 -36
  546. package/node_modules/gopd/tsconfig.json +0 -9
  547. package/node_modules/has-symbols/.eslintrc +0 -11
  548. package/node_modules/has-symbols/.github/FUNDING.yml +0 -12
  549. package/node_modules/has-symbols/.nycrc +0 -9
  550. package/node_modules/has-symbols/CHANGELOG.md +0 -91
  551. package/node_modules/has-symbols/LICENSE +0 -21
  552. package/node_modules/has-symbols/README.md +0 -46
  553. package/node_modules/has-symbols/index.d.ts +0 -3
  554. package/node_modules/has-symbols/index.js +0 -14
  555. package/node_modules/has-symbols/package.json +0 -111
  556. package/node_modules/has-symbols/shams.d.ts +0 -3
  557. package/node_modules/has-symbols/shams.js +0 -45
  558. package/node_modules/has-symbols/test/index.js +0 -22
  559. package/node_modules/has-symbols/test/shams/core-js.js +0 -29
  560. package/node_modules/has-symbols/test/shams/get-own-property-symbols.js +0 -29
  561. package/node_modules/has-symbols/test/tests.js +0 -58
  562. package/node_modules/has-symbols/tsconfig.json +0 -10
  563. package/node_modules/has-tostringtag/.eslintrc +0 -5
  564. package/node_modules/has-tostringtag/.github/FUNDING.yml +0 -12
  565. package/node_modules/has-tostringtag/.nycrc +0 -13
  566. package/node_modules/has-tostringtag/CHANGELOG.md +0 -42
  567. package/node_modules/has-tostringtag/LICENSE +0 -21
  568. package/node_modules/has-tostringtag/README.md +0 -46
  569. package/node_modules/has-tostringtag/index.d.ts +0 -3
  570. package/node_modules/has-tostringtag/index.js +0 -8
  571. package/node_modules/has-tostringtag/package.json +0 -108
  572. package/node_modules/has-tostringtag/shams.d.ts +0 -3
  573. package/node_modules/has-tostringtag/shams.js +0 -8
  574. package/node_modules/has-tostringtag/test/index.js +0 -21
  575. package/node_modules/has-tostringtag/test/shams/core-js.js +0 -31
  576. package/node_modules/has-tostringtag/test/shams/get-own-property-symbols.js +0 -30
  577. package/node_modules/has-tostringtag/test/tests.js +0 -15
  578. package/node_modules/has-tostringtag/tsconfig.json +0 -49
  579. package/node_modules/hasown/.github/FUNDING.yml +0 -12
  580. package/node_modules/hasown/.nycrc +0 -13
  581. package/node_modules/hasown/CHANGELOG.md +0 -58
  582. package/node_modules/hasown/LICENSE +0 -21
  583. package/node_modules/hasown/README.md +0 -40
  584. package/node_modules/hasown/eslint.config.mjs +0 -6
  585. package/node_modules/hasown/index.d.ts +0 -3
  586. package/node_modules/hasown/index.js +0 -8
  587. package/node_modules/hasown/package.json +0 -91
  588. package/node_modules/hasown/tsconfig.json +0 -6
  589. package/node_modules/json-bigint/LICENSE +0 -20
  590. package/node_modules/json-bigint/README.md +0 -240
  591. package/node_modules/json-bigint/index.js +0 -12
  592. package/node_modules/json-bigint/lib/parse.js +0 -443
  593. package/node_modules/json-bigint/lib/stringify.js +0 -384
  594. package/node_modules/json-bigint/package.json +0 -34
  595. package/node_modules/math-intrinsics/.eslintrc +0 -16
  596. package/node_modules/math-intrinsics/.github/FUNDING.yml +0 -12
  597. package/node_modules/math-intrinsics/CHANGELOG.md +0 -24
  598. package/node_modules/math-intrinsics/LICENSE +0 -21
  599. package/node_modules/math-intrinsics/README.md +0 -50
  600. package/node_modules/math-intrinsics/abs.d.ts +0 -1
  601. package/node_modules/math-intrinsics/abs.js +0 -4
  602. package/node_modules/math-intrinsics/constants/maxArrayLength.d.ts +0 -3
  603. package/node_modules/math-intrinsics/constants/maxArrayLength.js +0 -4
  604. package/node_modules/math-intrinsics/constants/maxSafeInteger.d.ts +0 -3
  605. package/node_modules/math-intrinsics/constants/maxSafeInteger.js +0 -5
  606. package/node_modules/math-intrinsics/constants/maxValue.d.ts +0 -3
  607. package/node_modules/math-intrinsics/constants/maxValue.js +0 -5
  608. package/node_modules/math-intrinsics/floor.d.ts +0 -1
  609. package/node_modules/math-intrinsics/floor.js +0 -4
  610. package/node_modules/math-intrinsics/isFinite.d.ts +0 -3
  611. package/node_modules/math-intrinsics/isFinite.js +0 -12
  612. package/node_modules/math-intrinsics/isInteger.d.ts +0 -3
  613. package/node_modules/math-intrinsics/isInteger.js +0 -16
  614. package/node_modules/math-intrinsics/isNaN.d.ts +0 -1
  615. package/node_modules/math-intrinsics/isNaN.js +0 -6
  616. package/node_modules/math-intrinsics/isNegativeZero.d.ts +0 -3
  617. package/node_modules/math-intrinsics/isNegativeZero.js +0 -6
  618. package/node_modules/math-intrinsics/max.d.ts +0 -1
  619. package/node_modules/math-intrinsics/max.js +0 -4
  620. package/node_modules/math-intrinsics/min.d.ts +0 -1
  621. package/node_modules/math-intrinsics/min.js +0 -4
  622. package/node_modules/math-intrinsics/mod.d.ts +0 -3
  623. package/node_modules/math-intrinsics/mod.js +0 -9
  624. package/node_modules/math-intrinsics/package.json +0 -86
  625. package/node_modules/math-intrinsics/pow.d.ts +0 -1
  626. package/node_modules/math-intrinsics/pow.js +0 -4
  627. package/node_modules/math-intrinsics/round.d.ts +0 -1
  628. package/node_modules/math-intrinsics/round.js +0 -4
  629. package/node_modules/math-intrinsics/sign.d.ts +0 -3
  630. package/node_modules/math-intrinsics/sign.js +0 -11
  631. package/node_modules/math-intrinsics/test/index.js +0 -192
  632. package/node_modules/math-intrinsics/tsconfig.json +0 -3
  633. package/node_modules/pako/LICENSE +0 -21
  634. package/node_modules/pako/README.md +0 -155
  635. package/node_modules/pako/dist/pako.es5.js +0 -6760
  636. package/node_modules/pako/dist/pako.es5.min.js +0 -2
  637. package/node_modules/pako/dist/pako.esm.mjs +0 -6945
  638. package/node_modules/pako/dist/pako.js +0 -6964
  639. package/node_modules/pako/dist/pako.min.js +0 -2
  640. package/node_modules/pako/dist/pako_deflate.es5.js +0 -3953
  641. package/node_modules/pako/dist/pako_deflate.es5.min.js +0 -2
  642. package/node_modules/pako/dist/pako_deflate.js +0 -4154
  643. package/node_modules/pako/dist/pako_deflate.min.js +0 -2
  644. package/node_modules/pako/dist/pako_inflate.es5.js +0 -3272
  645. package/node_modules/pako/dist/pako_inflate.es5.min.js +0 -2
  646. package/node_modules/pako/dist/pako_inflate.js +0 -3279
  647. package/node_modules/pako/dist/pako_inflate.min.js +0 -2
  648. package/node_modules/pako/index.js +0 -18
  649. package/node_modules/pako/lib/deflate.js +0 -387
  650. package/node_modules/pako/lib/inflate.js +0 -456
  651. package/node_modules/pako/lib/utils/common.js +0 -48
  652. package/node_modules/pako/lib/utils/strings.js +0 -174
  653. package/node_modules/pako/lib/zlib/README +0 -59
  654. package/node_modules/pako/lib/zlib/adler32.js +0 -51
  655. package/node_modules/pako/lib/zlib/constants.js +0 -68
  656. package/node_modules/pako/lib/zlib/crc32.js +0 -59
  657. package/node_modules/pako/lib/zlib/deflate.js +0 -2069
  658. package/node_modules/pako/lib/zlib/gzheader.js +0 -58
  659. package/node_modules/pako/lib/zlib/inffast.js +0 -344
  660. package/node_modules/pako/lib/zlib/inflate.js +0 -1575
  661. package/node_modules/pako/lib/zlib/inftrees.js +0 -340
  662. package/node_modules/pako/lib/zlib/messages.js +0 -32
  663. package/node_modules/pako/lib/zlib/trees.js +0 -1179
  664. package/node_modules/pako/lib/zlib/zstream.js +0 -47
  665. package/node_modules/pako/package.json +0 -73
  666. package/node_modules/semver/LICENSE +0 -15
  667. package/node_modules/semver/README.md +0 -680
  668. package/node_modules/semver/bin/semver.js +0 -195
  669. package/node_modules/semver/classes/comparator.js +0 -143
  670. package/node_modules/semver/classes/index.js +0 -7
  671. package/node_modules/semver/classes/range.js +0 -577
  672. package/node_modules/semver/classes/semver.js +0 -350
  673. package/node_modules/semver/functions/clean.js +0 -8
  674. package/node_modules/semver/functions/cmp.js +0 -54
  675. package/node_modules/semver/functions/coerce.js +0 -62
  676. package/node_modules/semver/functions/compare-build.js +0 -9
  677. package/node_modules/semver/functions/compare-loose.js +0 -5
  678. package/node_modules/semver/functions/compare.js +0 -7
  679. package/node_modules/semver/functions/diff.js +0 -60
  680. package/node_modules/semver/functions/eq.js +0 -5
  681. package/node_modules/semver/functions/gt.js +0 -5
  682. package/node_modules/semver/functions/gte.js +0 -5
  683. package/node_modules/semver/functions/inc.js +0 -21
  684. package/node_modules/semver/functions/lt.js +0 -5
  685. package/node_modules/semver/functions/lte.js +0 -5
  686. package/node_modules/semver/functions/major.js +0 -5
  687. package/node_modules/semver/functions/minor.js +0 -5
  688. package/node_modules/semver/functions/neq.js +0 -5
  689. package/node_modules/semver/functions/parse.js +0 -18
  690. package/node_modules/semver/functions/patch.js +0 -5
  691. package/node_modules/semver/functions/prerelease.js +0 -8
  692. package/node_modules/semver/functions/rcompare.js +0 -5
  693. package/node_modules/semver/functions/rsort.js +0 -5
  694. package/node_modules/semver/functions/satisfies.js +0 -12
  695. package/node_modules/semver/functions/sort.js +0 -5
  696. package/node_modules/semver/functions/truncate.js +0 -48
  697. package/node_modules/semver/functions/valid.js +0 -8
  698. package/node_modules/semver/index.js +0 -93
  699. package/node_modules/semver/internal/constants.js +0 -37
  700. package/node_modules/semver/internal/debug.js +0 -11
  701. package/node_modules/semver/internal/identifiers.js +0 -29
  702. package/node_modules/semver/internal/lrucache.js +0 -42
  703. package/node_modules/semver/internal/parse-options.js +0 -17
  704. package/node_modules/semver/internal/re.js +0 -223
  705. package/node_modules/semver/package.json +0 -78
  706. package/node_modules/semver/preload.js +0 -4
  707. package/node_modules/semver/range.bnf +0 -17
  708. package/node_modules/semver/ranges/gtr.js +0 -6
  709. package/node_modules/semver/ranges/intersects.js +0 -9
  710. package/node_modules/semver/ranges/ltr.js +0 -6
  711. package/node_modules/semver/ranges/max-satisfying.js +0 -27
  712. package/node_modules/semver/ranges/min-satisfying.js +0 -26
  713. package/node_modules/semver/ranges/min-version.js +0 -63
  714. package/node_modules/semver/ranges/outside.js +0 -82
  715. package/node_modules/semver/ranges/simplify.js +0 -49
  716. package/node_modules/semver/ranges/subset.js +0 -249
  717. package/node_modules/semver/ranges/to-comparators.js +0 -10
  718. package/node_modules/semver/ranges/valid.js +0 -13
  719. package/node_modules/spark-md5/LICENSE +0 -13
  720. package/node_modules/spark-md5/README.md +0 -191
  721. package/node_modules/spark-md5/package.json +0 -35
  722. package/node_modules/spark-md5/spark-md5.js +0 -751
  723. package/node_modules/spark-md5/spark-md5.min.js +0 -1
  724. package/node_modules/tldts/LICENSE +0 -13
  725. package/node_modules/tldts/README.md +0 -327
  726. package/node_modules/tldts/bin/cli.js +0 -21
  727. package/node_modules/tldts/dist/cjs/index.js +0 -666
  728. package/node_modules/tldts/dist/cjs/index.js.map +0 -1
  729. package/node_modules/tldts/dist/cjs/src/data/trie.js +0 -14
  730. package/node_modules/tldts/dist/cjs/src/data/trie.js.map +0 -1
  731. package/node_modules/tldts/dist/cjs/src/suffix-trie.js +0 -67
  732. package/node_modules/tldts/dist/cjs/src/suffix-trie.js.map +0 -1
  733. package/node_modules/tldts/dist/cjs/tsconfig.tsbuildinfo +0 -1
  734. package/node_modules/tldts/dist/es6/index.js +0 -33
  735. package/node_modules/tldts/dist/es6/index.js.map +0 -1
  736. package/node_modules/tldts/dist/es6/src/data/trie.js +0 -11
  737. package/node_modules/tldts/dist/es6/src/data/trie.js.map +0 -1
  738. package/node_modules/tldts/dist/es6/src/suffix-trie.js +0 -64
  739. package/node_modules/tldts/dist/es6/src/suffix-trie.js.map +0 -1
  740. package/node_modules/tldts/dist/es6/tsconfig.bundle.tsbuildinfo +0 -1
  741. package/node_modules/tldts/dist/index.cjs.min.js +0 -2
  742. package/node_modules/tldts/dist/index.cjs.min.js.map +0 -1
  743. package/node_modules/tldts/dist/index.esm.min.js +0 -2
  744. package/node_modules/tldts/dist/index.esm.min.js.map +0 -1
  745. package/node_modules/tldts/dist/index.umd.min.js +0 -2
  746. package/node_modules/tldts/dist/index.umd.min.js.map +0 -1
  747. package/node_modules/tldts/dist/types/index.d.ts +0 -7
  748. package/node_modules/tldts/dist/types/src/data/trie.d.ts +0 -5
  749. package/node_modules/tldts/dist/types/src/suffix-trie.d.ts +0 -5
  750. package/node_modules/tldts/index.ts +0 -62
  751. package/node_modules/tldts/package.json +0 -91
  752. package/node_modules/tldts/src/data/trie.ts +0 -14
  753. package/node_modules/tldts/src/suffix-trie.ts +0 -110
  754. package/node_modules/tldts-core/LICENSE +0 -13
  755. package/node_modules/tldts-core/README.md +0 -3
  756. package/node_modules/tldts-core/dist/cjs/index.js +0 -561
  757. package/node_modules/tldts-core/dist/cjs/index.js.map +0 -1
  758. package/node_modules/tldts-core/dist/cjs/src/domain-without-suffix.js +0 -15
  759. package/node_modules/tldts-core/dist/cjs/src/domain-without-suffix.js.map +0 -1
  760. package/node_modules/tldts-core/dist/cjs/src/domain.js +0 -83
  761. package/node_modules/tldts-core/dist/cjs/src/domain.js.map +0 -1
  762. package/node_modules/tldts-core/dist/cjs/src/extract-hostname.js +0 -149
  763. package/node_modules/tldts-core/dist/cjs/src/extract-hostname.js.map +0 -1
  764. package/node_modules/tldts-core/dist/cjs/src/factory.js +0 -104
  765. package/node_modules/tldts-core/dist/cjs/src/factory.js.map +0 -1
  766. package/node_modules/tldts-core/dist/cjs/src/is-ip.js +0 -72
  767. package/node_modules/tldts-core/dist/cjs/src/is-ip.js.map +0 -1
  768. package/node_modules/tldts-core/dist/cjs/src/is-valid.js +0 -69
  769. package/node_modules/tldts-core/dist/cjs/src/is-valid.js.map +0 -1
  770. package/node_modules/tldts-core/dist/cjs/src/lookup/fast-path.js +0 -69
  771. package/node_modules/tldts-core/dist/cjs/src/lookup/fast-path.js.map +0 -1
  772. package/node_modules/tldts-core/dist/cjs/src/lookup/interface.js +0 -3
  773. package/node_modules/tldts-core/dist/cjs/src/lookup/interface.js.map +0 -1
  774. package/node_modules/tldts-core/dist/cjs/src/options.js +0 -22
  775. package/node_modules/tldts-core/dist/cjs/src/options.js.map +0 -1
  776. package/node_modules/tldts-core/dist/cjs/src/subdomain.js +0 -14
  777. package/node_modules/tldts-core/dist/cjs/src/subdomain.js.map +0 -1
  778. package/node_modules/tldts-core/dist/cjs/tsconfig.tsbuildinfo +0 -1
  779. package/node_modules/tldts-core/dist/es6/index.js +0 -4
  780. package/node_modules/tldts-core/dist/es6/index.js.map +0 -1
  781. package/node_modules/tldts-core/dist/es6/src/domain-without-suffix.js +0 -12
  782. package/node_modules/tldts-core/dist/es6/src/domain-without-suffix.js.map +0 -1
  783. package/node_modules/tldts-core/dist/es6/src/domain.js +0 -80
  784. package/node_modules/tldts-core/dist/es6/src/domain.js.map +0 -1
  785. package/node_modules/tldts-core/dist/es6/src/extract-hostname.js +0 -146
  786. package/node_modules/tldts-core/dist/es6/src/extract-hostname.js.map +0 -1
  787. package/node_modules/tldts-core/dist/es6/src/factory.js +0 -99
  788. package/node_modules/tldts-core/dist/es6/src/factory.js.map +0 -1
  789. package/node_modules/tldts-core/dist/es6/src/is-ip.js +0 -69
  790. package/node_modules/tldts-core/dist/es6/src/is-ip.js.map +0 -1
  791. package/node_modules/tldts-core/dist/es6/src/is-valid.js +0 -66
  792. package/node_modules/tldts-core/dist/es6/src/is-valid.js.map +0 -1
  793. package/node_modules/tldts-core/dist/es6/src/lookup/fast-path.js +0 -66
  794. package/node_modules/tldts-core/dist/es6/src/lookup/fast-path.js.map +0 -1
  795. package/node_modules/tldts-core/dist/es6/src/lookup/interface.js +0 -2
  796. package/node_modules/tldts-core/dist/es6/src/lookup/interface.js.map +0 -1
  797. package/node_modules/tldts-core/dist/es6/src/options.js +0 -19
  798. package/node_modules/tldts-core/dist/es6/src/options.js.map +0 -1
  799. package/node_modules/tldts-core/dist/es6/src/subdomain.js +0 -11
  800. package/node_modules/tldts-core/dist/es6/src/subdomain.js.map +0 -1
  801. package/node_modules/tldts-core/dist/es6/tsconfig.bundle.tsbuildinfo +0 -1
  802. package/node_modules/tldts-core/dist/types/index.d.ts +0 -4
  803. package/node_modules/tldts-core/dist/types/src/domain-without-suffix.d.ts +0 -6
  804. package/node_modules/tldts-core/dist/types/src/domain.d.ts +0 -5
  805. package/node_modules/tldts-core/dist/types/src/extract-hostname.d.ts +0 -5
  806. package/node_modules/tldts-core/dist/types/src/factory.d.ts +0 -28
  807. package/node_modules/tldts-core/dist/types/src/is-ip.d.ts +0 -6
  808. package/node_modules/tldts-core/dist/types/src/is-valid.d.ts +0 -15
  809. package/node_modules/tldts-core/dist/types/src/lookup/fast-path.d.ts +0 -2
  810. package/node_modules/tldts-core/dist/types/src/lookup/interface.d.ts +0 -9
  811. package/node_modules/tldts-core/dist/types/src/options.d.ts +0 -10
  812. package/node_modules/tldts-core/dist/types/src/subdomain.d.ts +0 -4
  813. package/node_modules/tldts-core/index.ts +0 -10
  814. package/node_modules/tldts-core/package.json +0 -68
  815. package/node_modules/tldts-core/src/domain-without-suffix.ts +0 -14
  816. package/node_modules/tldts-core/src/domain.ts +0 -100
  817. package/node_modules/tldts-core/src/extract-hostname.ts +0 -170
  818. package/node_modules/tldts-core/src/factory.ts +0 -160
  819. package/node_modules/tldts-core/src/is-ip.ts +0 -87
  820. package/node_modules/tldts-core/src/is-valid.ts +0 -79
  821. package/node_modules/tldts-core/src/lookup/fast-path.ts +0 -80
  822. package/node_modules/tldts-core/src/lookup/interface.ts +0 -10
  823. package/node_modules/tldts-core/src/options.ts +0 -39
  824. package/node_modules/tldts-core/src/subdomain.ts +0 -11
  825. package/node_modules/tough-cookie/LICENSE +0 -12
  826. package/node_modules/tough-cookie/README.md +0 -154
  827. package/node_modules/tough-cookie/dist/cookie/canonicalDomain.d.ts +0 -33
  828. package/node_modules/tough-cookie/dist/cookie/canonicalDomain.js +0 -65
  829. package/node_modules/tough-cookie/dist/cookie/constants.d.ts +0 -54
  830. package/node_modules/tough-cookie/dist/cookie/constants.js +0 -38
  831. package/node_modules/tough-cookie/dist/cookie/cookie.d.ts +0 -326
  832. package/node_modules/tough-cookie/dist/cookie/cookie.js +0 -831
  833. package/node_modules/tough-cookie/dist/cookie/cookieCompare.d.ts +0 -58
  834. package/node_modules/tough-cookie/dist/cookie/cookieCompare.js +0 -84
  835. package/node_modules/tough-cookie/dist/cookie/cookieJar.d.ts +0 -621
  836. package/node_modules/tough-cookie/dist/cookie/cookieJar.js +0 -1000
  837. package/node_modules/tough-cookie/dist/cookie/defaultPath.d.ts +0 -40
  838. package/node_modules/tough-cookie/dist/cookie/defaultPath.js +0 -60
  839. package/node_modules/tough-cookie/dist/cookie/domainMatch.d.ts +0 -38
  840. package/node_modules/tough-cookie/dist/cookie/domainMatch.js +0 -94
  841. package/node_modules/tough-cookie/dist/cookie/formatDate.d.ts +0 -15
  842. package/node_modules/tough-cookie/dist/cookie/formatDate.js +0 -20
  843. package/node_modules/tough-cookie/dist/cookie/index.d.ts +0 -29
  844. package/node_modules/tough-cookie/dist/cookie/index.js +0 -54
  845. package/node_modules/tough-cookie/dist/cookie/parseDate.d.ts +0 -103
  846. package/node_modules/tough-cookie/dist/cookie/parseDate.js +0 -323
  847. package/node_modules/tough-cookie/dist/cookie/permutePath.d.ts +0 -14
  848. package/node_modules/tough-cookie/dist/cookie/permutePath.js +0 -32
  849. package/node_modules/tough-cookie/dist/getPublicSuffix.d.ts +0 -55
  850. package/node_modules/tough-cookie/dist/getPublicSuffix.js +0 -71
  851. package/node_modules/tough-cookie/dist/memstore.d.ts +0 -220
  852. package/node_modules/tough-cookie/dist/memstore.js +0 -187
  853. package/node_modules/tough-cookie/dist/pathMatch.d.ts +0 -17
  854. package/node_modules/tough-cookie/dist/pathMatch.js +0 -40
  855. package/node_modules/tough-cookie/dist/permuteDomain.d.ts +0 -15
  856. package/node_modules/tough-cookie/dist/permuteDomain.js +0 -44
  857. package/node_modules/tough-cookie/dist/store.d.ts +0 -211
  858. package/node_modules/tough-cookie/dist/store.js +0 -76
  859. package/node_modules/tough-cookie/dist/utils.d.ts +0 -34
  860. package/node_modules/tough-cookie/dist/utils.js +0 -99
  861. package/node_modules/tough-cookie/dist/validators.d.ts +0 -24
  862. package/node_modules/tough-cookie/dist/validators.js +0 -90
  863. package/node_modules/tough-cookie/dist/version.d.ts +0 -5
  864. package/node_modules/tough-cookie/dist/version.js +0 -8
  865. package/node_modules/tough-cookie/package.json +0 -144
  866. package/node_modules/ws/LICENSE +0 -20
  867. package/node_modules/ws/README.md +0 -548
  868. package/node_modules/ws/browser.js +0 -8
  869. package/node_modules/ws/index.js +0 -22
  870. package/node_modules/ws/lib/buffer-util.js +0 -131
  871. package/node_modules/ws/lib/constants.js +0 -19
  872. package/node_modules/ws/lib/event-target.js +0 -292
  873. package/node_modules/ws/lib/extension.js +0 -203
  874. package/node_modules/ws/lib/limiter.js +0 -55
  875. package/node_modules/ws/lib/permessage-deflate.js +0 -530
  876. package/node_modules/ws/lib/receiver.js +0 -743
  877. package/node_modules/ws/lib/sender.js +0 -607
  878. package/node_modules/ws/lib/stream.js +0 -161
  879. package/node_modules/ws/lib/subprotocol.js +0 -62
  880. package/node_modules/ws/lib/validation.js +0 -152
  881. package/node_modules/ws/lib/websocket-server.js +0 -562
  882. package/node_modules/ws/lib/websocket.js +0 -1407
  883. package/node_modules/ws/package.json +0 -74
  884. package/node_modules/ws/wrapper.mjs +0 -21
  885. package/node_modules/zca-js/.prettierrc +0 -5
  886. package/node_modules/zca-js/CODE_OF_CONDUCT.md +0 -163
  887. package/node_modules/zca-js/CONTRIBUTING.md +0 -470
  888. package/node_modules/zca-js/LICENSE +0 -21
  889. package/node_modules/zca-js/README.md +0 -225
  890. package/node_modules/zca-js/SECURITY.md +0 -83
  891. package/node_modules/zca-js/dist/Errors/ZaloApiError.d.ts +0 -4
  892. package/node_modules/zca-js/dist/Errors/ZaloApiError.js +0 -7
  893. package/node_modules/zca-js/dist/Errors/ZaloApiLoginQRAborted.d.ts +0 -4
  894. package/node_modules/zca-js/dist/Errors/ZaloApiLoginQRAborted.js +0 -7
  895. package/node_modules/zca-js/dist/Errors/ZaloApiLoginQRDeclined.d.ts +0 -4
  896. package/node_modules/zca-js/dist/Errors/ZaloApiLoginQRDeclined.js +0 -7
  897. package/node_modules/zca-js/dist/Errors/ZaloApiMissingImageMetadataGetter.d.ts +0 -4
  898. package/node_modules/zca-js/dist/Errors/ZaloApiMissingImageMetadataGetter.js +0 -7
  899. package/node_modules/zca-js/dist/Errors/index.d.ts +0 -4
  900. package/node_modules/zca-js/dist/Errors/index.js +0 -4
  901. package/node_modules/zca-js/dist/apis/acceptFriendRequest.d.ts +0 -2
  902. package/node_modules/zca-js/dist/apis/acceptFriendRequest.js +0 -28
  903. package/node_modules/zca-js/dist/apis/addGroupBlockedMember.d.ts +0 -2
  904. package/node_modules/zca-js/dist/apis/addGroupBlockedMember.js +0 -28
  905. package/node_modules/zca-js/dist/apis/addGroupDeputy.d.ts +0 -2
  906. package/node_modules/zca-js/dist/apis/addGroupDeputy.js +0 -30
  907. package/node_modules/zca-js/dist/apis/addPollOptions.d.ts +0 -14
  908. package/node_modules/zca-js/dist/apis/addPollOptions.js +0 -26
  909. package/node_modules/zca-js/dist/apis/addQuickMessage.d.ts +0 -11
  910. package/node_modules/zca-js/dist/apis/addQuickMessage.js +0 -60
  911. package/node_modules/zca-js/dist/apis/addReaction.d.ts +0 -18
  912. package/node_modules/zca-js/dist/apis/addReaction.js +0 -294
  913. package/node_modules/zca-js/dist/apis/addUnreadMark.d.ts +0 -8
  914. package/node_modules/zca-js/dist/apis/addUnreadMark.js +0 -52
  915. package/node_modules/zca-js/dist/apis/addUserToGroup.d.ts +0 -5
  916. package/node_modules/zca-js/dist/apis/addUserToGroup.js +0 -34
  917. package/node_modules/zca-js/dist/apis/blockUser.d.ts +0 -2
  918. package/node_modules/zca-js/dist/apis/blockUser.js +0 -28
  919. package/node_modules/zca-js/dist/apis/blockViewFeed.d.ts +0 -2
  920. package/node_modules/zca-js/dist/apis/blockViewFeed.js +0 -30
  921. package/node_modules/zca-js/dist/apis/changeAccountAvatar.d.ts +0 -3
  922. package/node_modules/zca-js/dist/apis/changeAccountAvatar.js +0 -52
  923. package/node_modules/zca-js/dist/apis/changeFriendAlias.d.ts +0 -2
  924. package/node_modules/zca-js/dist/apis/changeFriendAlias.js +0 -27
  925. package/node_modules/zca-js/dist/apis/changeGroupAvatar.d.ts +0 -3
  926. package/node_modules/zca-js/dist/apis/changeGroupAvatar.js +0 -44
  927. package/node_modules/zca-js/dist/apis/changeGroupName.d.ts +0 -4
  928. package/node_modules/zca-js/dist/apis/changeGroupName.js +0 -32
  929. package/node_modules/zca-js/dist/apis/changeGroupOwner.d.ts +0 -4
  930. package/node_modules/zca-js/dist/apis/changeGroupOwner.js +0 -30
  931. package/node_modules/zca-js/dist/apis/createAutoReply.d.ts +0 -14
  932. package/node_modules/zca-js/dist/apis/createAutoReply.js +0 -37
  933. package/node_modules/zca-js/dist/apis/createBankAccount.d.ts +0 -8
  934. package/node_modules/zca-js/dist/apis/createBankAccount.js +0 -32
  935. package/node_modules/zca-js/dist/apis/createCatalog.d.ts +0 -7
  936. package/node_modules/zca-js/dist/apis/createCatalog.js +0 -29
  937. package/node_modules/zca-js/dist/apis/createGroup.d.ts +0 -28
  938. package/node_modules/zca-js/dist/apis/createGroup.js +0 -43
  939. package/node_modules/zca-js/dist/apis/createNote.d.ts +0 -7
  940. package/node_modules/zca-js/dist/apis/createNote.js +0 -47
  941. package/node_modules/zca-js/dist/apis/createPoll.d.ts +0 -36
  942. package/node_modules/zca-js/dist/apis/createPoll.js +0 -40
  943. package/node_modules/zca-js/dist/apis/createProductCatalog.d.ts +0 -23
  944. package/node_modules/zca-js/dist/apis/createProductCatalog.js +0 -50
  945. package/node_modules/zca-js/dist/apis/createReminder.d.ts +0 -12
  946. package/node_modules/zca-js/dist/apis/createReminder.js +0 -63
  947. package/node_modules/zca-js/dist/apis/custom.d.ts +0 -9
  948. package/node_modules/zca-js/dist/apis/custom.js +0 -15
  949. package/node_modules/zca-js/dist/apis/deleteAutoReply.d.ts +0 -5
  950. package/node_modules/zca-js/dist/apis/deleteAutoReply.js +0 -29
  951. package/node_modules/zca-js/dist/apis/deleteAvatar.d.ts +0 -9
  952. package/node_modules/zca-js/dist/apis/deleteAvatar.js +0 -27
  953. package/node_modules/zca-js/dist/apis/deleteBankAccount.d.ts +0 -11
  954. package/node_modules/zca-js/dist/apis/deleteBankAccount.js +0 -32
  955. package/node_modules/zca-js/dist/apis/deleteCatalog.d.ts +0 -2
  956. package/node_modules/zca-js/dist/apis/deleteCatalog.js +0 -28
  957. package/node_modules/zca-js/dist/apis/deleteChat.d.ts +0 -19
  958. package/node_modules/zca-js/dist/apis/deleteChat.js +0 -50
  959. package/node_modules/zca-js/dist/apis/deleteGroupInviteBox.d.ts +0 -9
  960. package/node_modules/zca-js/dist/apis/deleteGroupInviteBox.js +0 -27
  961. package/node_modules/zca-js/dist/apis/deleteMessage.d.ts +0 -14
  962. package/node_modules/zca-js/dist/apis/deleteMessage.js +0 -52
  963. package/node_modules/zca-js/dist/apis/deleteProductCatalog.d.ts +0 -10
  964. package/node_modules/zca-js/dist/apis/deleteProductCatalog.js +0 -31
  965. package/node_modules/zca-js/dist/apis/disableGroupLink.d.ts +0 -2
  966. package/node_modules/zca-js/dist/apis/disableGroupLink.js +0 -24
  967. package/node_modules/zca-js/dist/apis/disperseGroup.d.ts +0 -2
  968. package/node_modules/zca-js/dist/apis/disperseGroup.js +0 -28
  969. package/node_modules/zca-js/dist/apis/editNote.d.ts +0 -17
  970. package/node_modules/zca-js/dist/apis/editNote.js +0 -46
  971. package/node_modules/zca-js/dist/apis/editReminder.d.ts +0 -13
  972. package/node_modules/zca-js/dist/apis/editReminder.js +0 -61
  973. package/node_modules/zca-js/dist/apis/enableGroupLink.d.ts +0 -6
  974. package/node_modules/zca-js/dist/apis/enableGroupLink.js +0 -25
  975. package/node_modules/zca-js/dist/apis/fetchAccountInfo.d.ts +0 -5
  976. package/node_modules/zca-js/dist/apis/fetchAccountInfo.js +0 -10
  977. package/node_modules/zca-js/dist/apis/findUser.d.ts +0 -3
  978. package/node_modules/zca-js/dist/apis/findUser.js +0 -42
  979. package/node_modules/zca-js/dist/apis/findUserByUsername.d.ts +0 -3
  980. package/node_modules/zca-js/dist/apis/findUserByUsername.js +0 -27
  981. package/node_modules/zca-js/dist/apis/forwardMessage.d.ts +0 -24
  982. package/node_modules/zca-js/dist/apis/forwardMessage.js +0 -114
  983. package/node_modules/zca-js/dist/apis/getAliasList.d.ts +0 -8
  984. package/node_modules/zca-js/dist/apis/getAliasList.js +0 -27
  985. package/node_modules/zca-js/dist/apis/getAllFriends.d.ts +0 -3
  986. package/node_modules/zca-js/dist/apis/getAllFriends.js +0 -34
  987. package/node_modules/zca-js/dist/apis/getAllGroups.d.ts +0 -7
  988. package/node_modules/zca-js/dist/apis/getAllGroups.js +0 -10
  989. package/node_modules/zca-js/dist/apis/getArchivedChatList.d.ts +0 -5
  990. package/node_modules/zca-js/dist/apis/getArchivedChatList.js +0 -23
  991. package/node_modules/zca-js/dist/apis/getAutoDeleteChat.d.ts +0 -9
  992. package/node_modules/zca-js/dist/apis/getAutoDeleteChat.js +0 -21
  993. package/node_modules/zca-js/dist/apis/getAutoReplyList.d.ts +0 -6
  994. package/node_modules/zca-js/dist/apis/getAutoReplyList.js +0 -24
  995. package/node_modules/zca-js/dist/apis/getAvatarList.d.ts +0 -12
  996. package/node_modules/zca-js/dist/apis/getAvatarList.js +0 -28
  997. package/node_modules/zca-js/dist/apis/getAvatarUrlProfile.d.ts +0 -7
  998. package/node_modules/zca-js/dist/apis/getAvatarUrlProfile.js +0 -30
  999. package/node_modules/zca-js/dist/apis/getBizAccount.d.ts +0 -24
  1000. package/node_modules/zca-js/dist/apis/getBizAccount.js +0 -27
  1001. package/node_modules/zca-js/dist/apis/getCatalogList.d.ts +0 -18
  1002. package/node_modules/zca-js/dist/apis/getCatalogList.js +0 -32
  1003. package/node_modules/zca-js/dist/apis/getCloseFriends.d.ts +0 -3
  1004. package/node_modules/zca-js/dist/apis/getCloseFriends.js +0 -20
  1005. package/node_modules/zca-js/dist/apis/getContext.d.ts +0 -1
  1006. package/node_modules/zca-js/dist/apis/getContext.js +0 -4
  1007. package/node_modules/zca-js/dist/apis/getCookie.d.ts +0 -1
  1008. package/node_modules/zca-js/dist/apis/getCookie.js +0 -9
  1009. package/node_modules/zca-js/dist/apis/getFriendBoardList.d.ts +0 -5
  1010. package/node_modules/zca-js/dist/apis/getFriendBoardList.js +0 -26
  1011. package/node_modules/zca-js/dist/apis/getFriendOnlines.d.ts +0 -10
  1012. package/node_modules/zca-js/dist/apis/getFriendOnlines.js +0 -35
  1013. package/node_modules/zca-js/dist/apis/getFriendRecommendations.d.ts +0 -42
  1014. package/node_modules/zca-js/dist/apis/getFriendRecommendations.js +0 -27
  1015. package/node_modules/zca-js/dist/apis/getFriendRequestStatus.d.ts +0 -8
  1016. package/node_modules/zca-js/dist/apis/getFriendRequestStatus.js +0 -25
  1017. package/node_modules/zca-js/dist/apis/getFullAvatar.d.ts +0 -5
  1018. package/node_modules/zca-js/dist/apis/getFullAvatar.js +0 -25
  1019. package/node_modules/zca-js/dist/apis/getGroupBlockedMember.d.ts +0 -23
  1020. package/node_modules/zca-js/dist/apis/getGroupBlockedMember.js +0 -29
  1021. package/node_modules/zca-js/dist/apis/getGroupChatHistory.d.ts +0 -8
  1022. package/node_modules/zca-js/dist/apis/getGroupChatHistory.js +0 -36
  1023. package/node_modules/zca-js/dist/apis/getGroupInfo.d.ts +0 -16
  1024. package/node_modules/zca-js/dist/apis/getGroupInfo.js +0 -32
  1025. package/node_modules/zca-js/dist/apis/getGroupInviteBoxInfo.d.ts +0 -32
  1026. package/node_modules/zca-js/dist/apis/getGroupInviteBoxInfo.js +0 -38
  1027. package/node_modules/zca-js/dist/apis/getGroupInviteBoxList.d.ts +0 -38
  1028. package/node_modules/zca-js/dist/apis/getGroupInviteBoxList.js +0 -31
  1029. package/node_modules/zca-js/dist/apis/getGroupLinkDetail.d.ts +0 -9
  1030. package/node_modules/zca-js/dist/apis/getGroupLinkDetail.js +0 -25
  1031. package/node_modules/zca-js/dist/apis/getGroupLinkInfo.d.ts +0 -34
  1032. package/node_modules/zca-js/dist/apis/getGroupLinkInfo.js +0 -28
  1033. package/node_modules/zca-js/dist/apis/getGroupMembersInfo.d.ts +0 -17
  1034. package/node_modules/zca-js/dist/apis/getGroupMembersInfo.js +0 -24
  1035. package/node_modules/zca-js/dist/apis/getHiddenConversations.d.ts +0 -11
  1036. package/node_modules/zca-js/dist/apis/getHiddenConversations.js +0 -23
  1037. package/node_modules/zca-js/dist/apis/getLabels.d.ts +0 -7
  1038. package/node_modules/zca-js/dist/apis/getLabels.js +0 -28
  1039. package/node_modules/zca-js/dist/apis/getListBank.d.ts +0 -5
  1040. package/node_modules/zca-js/dist/apis/getListBank.js +0 -20
  1041. package/node_modules/zca-js/dist/apis/getListBankAccount.d.ts +0 -7
  1042. package/node_modules/zca-js/dist/apis/getListBankAccount.js +0 -27
  1043. package/node_modules/zca-js/dist/apis/getListBoard.d.ts +0 -21
  1044. package/node_modules/zca-js/dist/apis/getListBoard.js +0 -45
  1045. package/node_modules/zca-js/dist/apis/getListDevice.d.ts +0 -10
  1046. package/node_modules/zca-js/dist/apis/getListDevice.js +0 -22
  1047. package/node_modules/zca-js/dist/apis/getListReminder.d.ts +0 -28
  1048. package/node_modules/zca-js/dist/apis/getListReminder.js +0 -47
  1049. package/node_modules/zca-js/dist/apis/getMultiUsersByPhones.d.ts +0 -5
  1050. package/node_modules/zca-js/dist/apis/getMultiUsersByPhones.js +0 -39
  1051. package/node_modules/zca-js/dist/apis/getMute.d.ts +0 -13
  1052. package/node_modules/zca-js/dist/apis/getMute.js +0 -22
  1053. package/node_modules/zca-js/dist/apis/getOwnId.d.ts +0 -1
  1054. package/node_modules/zca-js/dist/apis/getOwnId.js +0 -4
  1055. package/node_modules/zca-js/dist/apis/getPendingGroupMembers.d.ts +0 -11
  1056. package/node_modules/zca-js/dist/apis/getPendingGroupMembers.js +0 -27
  1057. package/node_modules/zca-js/dist/apis/getPinConversations.d.ts +0 -5
  1058. package/node_modules/zca-js/dist/apis/getPinConversations.js +0 -22
  1059. package/node_modules/zca-js/dist/apis/getPollDetail.d.ts +0 -3
  1060. package/node_modules/zca-js/dist/apis/getPollDetail.js +0 -30
  1061. package/node_modules/zca-js/dist/apis/getProductCatalogList.d.ts +0 -20
  1062. package/node_modules/zca-js/dist/apis/getProductCatalogList.js +0 -33
  1063. package/node_modules/zca-js/dist/apis/getQR.d.ts +0 -4
  1064. package/node_modules/zca-js/dist/apis/getQR.js +0 -29
  1065. package/node_modules/zca-js/dist/apis/getQuickMessageList.d.ts +0 -7
  1066. package/node_modules/zca-js/dist/apis/getQuickMessageList.js +0 -24
  1067. package/node_modules/zca-js/dist/apis/getRelatedFriendGroup.d.ts +0 -6
  1068. package/node_modules/zca-js/dist/apis/getRelatedFriendGroup.js +0 -30
  1069. package/node_modules/zca-js/dist/apis/getReminder.d.ts +0 -3
  1070. package/node_modules/zca-js/dist/apis/getReminder.js +0 -25
  1071. package/node_modules/zca-js/dist/apis/getReminderResponses.d.ts +0 -5
  1072. package/node_modules/zca-js/dist/apis/getReminderResponses.js +0 -24
  1073. package/node_modules/zca-js/dist/apis/getSentFriendRequest.d.ts +0 -18
  1074. package/node_modules/zca-js/dist/apis/getSentFriendRequest.js +0 -24
  1075. package/node_modules/zca-js/dist/apis/getSettings.d.ts +0 -3
  1076. package/node_modules/zca-js/dist/apis/getSettings.js +0 -20
  1077. package/node_modules/zca-js/dist/apis/getStickerCategoryDetail.d.ts +0 -3
  1078. package/node_modules/zca-js/dist/apis/getStickerCategoryDetail.js +0 -24
  1079. package/node_modules/zca-js/dist/apis/getStickers.d.ts +0 -1
  1080. package/node_modules/zca-js/dist/apis/getStickers.js +0 -40
  1081. package/node_modules/zca-js/dist/apis/getStickersDetail.d.ts +0 -3
  1082. package/node_modules/zca-js/dist/apis/getStickersDetail.js +0 -40
  1083. package/node_modules/zca-js/dist/apis/getUnreadMark.d.ts +0 -14
  1084. package/node_modules/zca-js/dist/apis/getUnreadMark.js +0 -30
  1085. package/node_modules/zca-js/dist/apis/getUserInfo.d.ts +0 -8
  1086. package/node_modules/zca-js/dist/apis/getUserInfo.js +0 -44
  1087. package/node_modules/zca-js/dist/apis/inviteUserToGroups.d.ts +0 -10
  1088. package/node_modules/zca-js/dist/apis/inviteUserToGroups.js +0 -30
  1089. package/node_modules/zca-js/dist/apis/joinGroupInviteBox.d.ts +0 -2
  1090. package/node_modules/zca-js/dist/apis/joinGroupInviteBox.js +0 -25
  1091. package/node_modules/zca-js/dist/apis/joinGroupLink.d.ts +0 -2
  1092. package/node_modules/zca-js/dist/apis/joinGroupLink.js +0 -27
  1093. package/node_modules/zca-js/dist/apis/keepAlive.d.ts +0 -4
  1094. package/node_modules/zca-js/dist/apis/keepAlive.js +0 -22
  1095. package/node_modules/zca-js/dist/apis/lastOnline.d.ts +0 -7
  1096. package/node_modules/zca-js/dist/apis/lastOnline.js +0 -26
  1097. package/node_modules/zca-js/dist/apis/leaveGroup.d.ts +0 -4
  1098. package/node_modules/zca-js/dist/apis/leaveGroup.js +0 -33
  1099. package/node_modules/zca-js/dist/apis/listen.d.ts +0 -102
  1100. package/node_modules/zca-js/dist/apis/listen.js +0 -425
  1101. package/node_modules/zca-js/dist/apis/lockPoll.d.ts +0 -2
  1102. package/node_modules/zca-js/dist/apis/lockPoll.js +0 -28
  1103. package/node_modules/zca-js/dist/apis/login.d.ts +0 -3
  1104. package/node_modules/zca-js/dist/apis/login.js +0 -96
  1105. package/node_modules/zca-js/dist/apis/loginQR.d.ts +0 -71
  1106. package/node_modules/zca-js/dist/apis/loginQR.js +0 -376
  1107. package/node_modules/zca-js/dist/apis/logoutV2.js +0 -79
  1108. package/node_modules/zca-js/dist/apis/lostFocus.d.ts +0 -4
  1109. package/node_modules/zca-js/dist/apis/lostFocus.js +0 -23
  1110. package/node_modules/zca-js/dist/apis/parseLink.d.ts +0 -21
  1111. package/node_modules/zca-js/dist/apis/parseLink.js +0 -27
  1112. package/node_modules/zca-js/dist/apis/registerCatalog.d.ts +0 -2
  1113. package/node_modules/zca-js/dist/apis/registerCatalog.js +0 -27
  1114. package/node_modules/zca-js/dist/apis/rejectFriendRequest.d.ts +0 -2
  1115. package/node_modules/zca-js/dist/apis/rejectFriendRequest.js +0 -27
  1116. package/node_modules/zca-js/dist/apis/removeFriend.d.ts +0 -2
  1117. package/node_modules/zca-js/dist/apis/removeFriend.js +0 -28
  1118. package/node_modules/zca-js/dist/apis/removeFriendAlias.d.ts +0 -2
  1119. package/node_modules/zca-js/dist/apis/removeFriendAlias.js +0 -24
  1120. package/node_modules/zca-js/dist/apis/removeGroupBlockedMember.d.ts +0 -2
  1121. package/node_modules/zca-js/dist/apis/removeGroupBlockedMember.js +0 -28
  1122. package/node_modules/zca-js/dist/apis/removeGroupDeputy.d.ts +0 -2
  1123. package/node_modules/zca-js/dist/apis/removeGroupDeputy.js +0 -30
  1124. package/node_modules/zca-js/dist/apis/removeQuickMessage.d.ts +0 -5
  1125. package/node_modules/zca-js/dist/apis/removeQuickMessage.js +0 -27
  1126. package/node_modules/zca-js/dist/apis/removeReminder.d.ts +0 -3
  1127. package/node_modules/zca-js/dist/apis/removeReminder.js +0 -40
  1128. package/node_modules/zca-js/dist/apis/removeUnreadMark.d.ts +0 -8
  1129. package/node_modules/zca-js/dist/apis/removeUnreadMark.js +0 -50
  1130. package/node_modules/zca-js/dist/apis/removeUserFromGroup.d.ts +0 -4
  1131. package/node_modules/zca-js/dist/apis/removeUserFromGroup.js +0 -34
  1132. package/node_modules/zca-js/dist/apis/resetHiddenConversPin.d.ts +0 -2
  1133. package/node_modules/zca-js/dist/apis/resetHiddenConversPin.js +0 -20
  1134. package/node_modules/zca-js/dist/apis/reuseAvatar.d.ts +0 -2
  1135. package/node_modules/zca-js/dist/apis/reuseAvatar.js +0 -26
  1136. package/node_modules/zca-js/dist/apis/reviewPendingMemberRequest.d.ts +0 -14
  1137. package/node_modules/zca-js/dist/apis/reviewPendingMemberRequest.js +0 -38
  1138. package/node_modules/zca-js/dist/apis/scanURL.d.ts +0 -4
  1139. package/node_modules/zca-js/dist/apis/scanURL.js +0 -28
  1140. package/node_modules/zca-js/dist/apis/searchSticker.d.ts +0 -3
  1141. package/node_modules/zca-js/dist/apis/searchSticker.js +0 -28
  1142. package/node_modules/zca-js/dist/apis/sendBankCard.d.ts +0 -9
  1143. package/node_modules/zca-js/dist/apis/sendBankCard.js +0 -53
  1144. package/node_modules/zca-js/dist/apis/sendCard.d.ts +0 -10
  1145. package/node_modules/zca-js/dist/apis/sendCard.js +0 -75
  1146. package/node_modules/zca-js/dist/apis/sendDeliveredEvent.d.ts +0 -16
  1147. package/node_modules/zca-js/dist/apis/sendDeliveredEvent.js +0 -55
  1148. package/node_modules/zca-js/dist/apis/sendFriendRequest.d.ts +0 -2
  1149. package/node_modules/zca-js/dist/apis/sendFriendRequest.js +0 -39
  1150. package/node_modules/zca-js/dist/apis/sendLink.d.ts +0 -10
  1151. package/node_modules/zca-js/dist/apis/sendLink.js +0 -78
  1152. package/node_modules/zca-js/dist/apis/sendMessage.d.ts +0 -105
  1153. package/node_modules/zca-js/dist/apis/sendMessage.js +0 -486
  1154. package/node_modules/zca-js/dist/apis/sendReport.d.ts +0 -17
  1155. package/node_modules/zca-js/dist/apis/sendReport.js +0 -53
  1156. package/node_modules/zca-js/dist/apis/sendSeenEvent.d.ts +0 -16
  1157. package/node_modules/zca-js/dist/apis/sendSeenEvent.js +0 -63
  1158. package/node_modules/zca-js/dist/apis/sendSticker.d.ts +0 -10
  1159. package/node_modules/zca-js/dist/apis/sendSticker.js +0 -74
  1160. package/node_modules/zca-js/dist/apis/sendTypingEvent.d.ts +0 -5
  1161. package/node_modules/zca-js/dist/apis/sendTypingEvent.js +0 -33
  1162. package/node_modules/zca-js/dist/apis/sendVideo.d.ts +0 -35
  1163. package/node_modules/zca-js/dist/apis/sendVideo.js +0 -134
  1164. package/node_modules/zca-js/dist/apis/sendVoice.d.ts +0 -12
  1165. package/node_modules/zca-js/dist/apis/sendVoice.js +0 -89
  1166. package/node_modules/zca-js/dist/apis/setHiddenConversations.d.ts +0 -3
  1167. package/node_modules/zca-js/dist/apis/setHiddenConversations.js +0 -39
  1168. package/node_modules/zca-js/dist/apis/setMute.d.ts +0 -20
  1169. package/node_modules/zca-js/dist/apis/setMute.js +0 -67
  1170. package/node_modules/zca-js/dist/apis/setPinnedConversations.d.ts +0 -3
  1171. package/node_modules/zca-js/dist/apis/setPinnedConversations.js +0 -34
  1172. package/node_modules/zca-js/dist/apis/sharePoll.d.ts +0 -2
  1173. package/node_modules/zca-js/dist/apis/sharePoll.js +0 -28
  1174. package/node_modules/zca-js/dist/apis/unblockUser.d.ts +0 -2
  1175. package/node_modules/zca-js/dist/apis/unblockUser.js +0 -28
  1176. package/node_modules/zca-js/dist/apis/undo.d.ts +0 -9
  1177. package/node_modules/zca-js/dist/apis/undo.js +0 -42
  1178. package/node_modules/zca-js/dist/apis/undoFriendRequest.d.ts +0 -2
  1179. package/node_modules/zca-js/dist/apis/undoFriendRequest.js +0 -27
  1180. package/node_modules/zca-js/dist/apis/updateActiveStatus.d.ts +0 -4
  1181. package/node_modules/zca-js/dist/apis/updateActiveStatus.js +0 -27
  1182. package/node_modules/zca-js/dist/apis/updateArchivedChatList.d.ts +0 -10
  1183. package/node_modules/zca-js/dist/apis/updateArchivedChatList.js +0 -34
  1184. package/node_modules/zca-js/dist/apis/updateAutoDeleteChat.d.ts +0 -9
  1185. package/node_modules/zca-js/dist/apis/updateAutoDeleteChat.js +0 -40
  1186. package/node_modules/zca-js/dist/apis/updateAutoReply.d.ts +0 -15
  1187. package/node_modules/zca-js/dist/apis/updateAutoReply.js +0 -38
  1188. package/node_modules/zca-js/dist/apis/updateBankAccount.d.ts +0 -9
  1189. package/node_modules/zca-js/dist/apis/updateBankAccount.js +0 -31
  1190. package/node_modules/zca-js/dist/apis/updateCatalog.d.ts +0 -11
  1191. package/node_modules/zca-js/dist/apis/updateCatalog.js +0 -30
  1192. package/node_modules/zca-js/dist/apis/updateGroupSettings.d.ts +0 -40
  1193. package/node_modules/zca-js/dist/apis/updateGroupSettings.js +0 -43
  1194. package/node_modules/zca-js/dist/apis/updateHiddenConversPin.d.ts +0 -2
  1195. package/node_modules/zca-js/dist/apis/updateHiddenConversPin.js +0 -30
  1196. package/node_modules/zca-js/dist/apis/updateLabels.d.ts +0 -15
  1197. package/node_modules/zca-js/dist/apis/updateLabels.js +0 -34
  1198. package/node_modules/zca-js/dist/apis/updateLang.d.ts +0 -6
  1199. package/node_modules/zca-js/dist/apis/updateLang.js +0 -30
  1200. package/node_modules/zca-js/dist/apis/updateProductCatalog.d.ts +0 -25
  1201. package/node_modules/zca-js/dist/apis/updateProductCatalog.js +0 -51
  1202. package/node_modules/zca-js/dist/apis/updateProfile.d.ts +0 -20
  1203. package/node_modules/zca-js/dist/apis/updateProfile.js +0 -43
  1204. package/node_modules/zca-js/dist/apis/updateProfileBio.d.ts +0 -2
  1205. package/node_modules/zca-js/dist/apis/updateProfileBio.js +0 -27
  1206. package/node_modules/zca-js/dist/apis/updateQuickMessage.d.ts +0 -11
  1207. package/node_modules/zca-js/dist/apis/updateQuickMessage.js +0 -61
  1208. package/node_modules/zca-js/dist/apis/updateSettings.d.ts +0 -16
  1209. package/node_modules/zca-js/dist/apis/updateSettings.js +0 -90
  1210. package/node_modules/zca-js/dist/apis/upgradeGroupToCommunity.d.ts +0 -2
  1211. package/node_modules/zca-js/dist/apis/upgradeGroupToCommunity.js +0 -27
  1212. package/node_modules/zca-js/dist/apis/uploadAttachment.d.ts +0 -50
  1213. package/node_modules/zca-js/dist/apis/uploadAttachment.js +0 -197
  1214. package/node_modules/zca-js/dist/apis/uploadProductPhoto.d.ts +0 -14
  1215. package/node_modules/zca-js/dist/apis/uploadProductPhoto.js +0 -50
  1216. package/node_modules/zca-js/dist/apis/votePoll.d.ts +0 -5
  1217. package/node_modules/zca-js/dist/apis/votePoll.js +0 -29
  1218. package/node_modules/zca-js/dist/apis.d.ts +0 -317
  1219. package/node_modules/zca-js/dist/apis.js +0 -319
  1220. package/node_modules/zca-js/dist/cjs/Errors/ZaloApiError.cjs +0 -11
  1221. package/node_modules/zca-js/dist/cjs/Errors/ZaloApiLoginQRAborted.cjs +0 -12
  1222. package/node_modules/zca-js/dist/cjs/Errors/ZaloApiLoginQRDeclined.cjs +0 -12
  1223. package/node_modules/zca-js/dist/cjs/Errors/ZaloApiMissingImageMetadataGetter.cjs +0 -12
  1224. package/node_modules/zca-js/dist/cjs/apis/acceptFriendRequest.cjs +0 -33
  1225. package/node_modules/zca-js/dist/cjs/apis/addGroupBlockedMember.cjs +0 -33
  1226. package/node_modules/zca-js/dist/cjs/apis/addGroupDeputy.cjs +0 -35
  1227. package/node_modules/zca-js/dist/cjs/apis/addPollOptions.cjs +0 -31
  1228. package/node_modules/zca-js/dist/cjs/apis/addQuickMessage.cjs +0 -65
  1229. package/node_modules/zca-js/dist/cjs/apis/addReaction.cjs +0 -308
  1230. package/node_modules/zca-js/dist/cjs/apis/addUnreadMark.cjs +0 -66
  1231. package/node_modules/zca-js/dist/cjs/apis/addUserToGroup.cjs +0 -39
  1232. package/node_modules/zca-js/dist/cjs/apis/blockUser.cjs +0 -33
  1233. package/node_modules/zca-js/dist/cjs/apis/blockViewFeed.cjs +0 -35
  1234. package/node_modules/zca-js/dist/cjs/apis/changeAccountAvatar.cjs +0 -57
  1235. package/node_modules/zca-js/dist/cjs/apis/changeFriendAlias.cjs +0 -32
  1236. package/node_modules/zca-js/dist/cjs/apis/changeGroupAvatar.cjs +0 -49
  1237. package/node_modules/zca-js/dist/cjs/apis/changeGroupName.cjs +0 -37
  1238. package/node_modules/zca-js/dist/cjs/apis/changeGroupOwner.cjs +0 -35
  1239. package/node_modules/zca-js/dist/cjs/apis/createAutoReply.cjs +0 -42
  1240. package/node_modules/zca-js/dist/cjs/apis/createBankAccount.cjs +0 -37
  1241. package/node_modules/zca-js/dist/cjs/apis/createCatalog.cjs +0 -34
  1242. package/node_modules/zca-js/dist/cjs/apis/createGroup.cjs +0 -48
  1243. package/node_modules/zca-js/dist/cjs/apis/createNote.cjs +0 -52
  1244. package/node_modules/zca-js/dist/cjs/apis/createPoll.cjs +0 -45
  1245. package/node_modules/zca-js/dist/cjs/apis/createProductCatalog.cjs +0 -55
  1246. package/node_modules/zca-js/dist/cjs/apis/createReminder.cjs +0 -77
  1247. package/node_modules/zca-js/dist/cjs/apis/custom.cjs +0 -19
  1248. package/node_modules/zca-js/dist/cjs/apis/deleteAutoReply.cjs +0 -34
  1249. package/node_modules/zca-js/dist/cjs/apis/deleteAvatar.cjs +0 -32
  1250. package/node_modules/zca-js/dist/cjs/apis/deleteBankAccount.cjs +0 -37
  1251. package/node_modules/zca-js/dist/cjs/apis/deleteCatalog.cjs +0 -33
  1252. package/node_modules/zca-js/dist/cjs/apis/deleteChat.cjs +0 -64
  1253. package/node_modules/zca-js/dist/cjs/apis/deleteGroupInviteBox.cjs +0 -32
  1254. package/node_modules/zca-js/dist/cjs/apis/deleteMessage.cjs +0 -66
  1255. package/node_modules/zca-js/dist/cjs/apis/deleteProductCatalog.cjs +0 -36
  1256. package/node_modules/zca-js/dist/cjs/apis/disableGroupLink.cjs +0 -29
  1257. package/node_modules/zca-js/dist/cjs/apis/disperseGroup.cjs +0 -33
  1258. package/node_modules/zca-js/dist/cjs/apis/editNote.cjs +0 -51
  1259. package/node_modules/zca-js/dist/cjs/apis/editReminder.cjs +0 -75
  1260. package/node_modules/zca-js/dist/cjs/apis/enableGroupLink.cjs +0 -30
  1261. package/node_modules/zca-js/dist/cjs/apis/fetchAccountInfo.cjs +0 -15
  1262. package/node_modules/zca-js/dist/cjs/apis/findUser.cjs +0 -56
  1263. package/node_modules/zca-js/dist/cjs/apis/findUserByUsername.cjs +0 -41
  1264. package/node_modules/zca-js/dist/cjs/apis/forwardMessage.cjs +0 -129
  1265. package/node_modules/zca-js/dist/cjs/apis/getAliasList.cjs +0 -32
  1266. package/node_modules/zca-js/dist/cjs/apis/getAllFriends.cjs +0 -48
  1267. package/node_modules/zca-js/dist/cjs/apis/getAllGroups.cjs +0 -15
  1268. package/node_modules/zca-js/dist/cjs/apis/getArchivedChatList.cjs +0 -28
  1269. package/node_modules/zca-js/dist/cjs/apis/getAutoDeleteChat.cjs +0 -26
  1270. package/node_modules/zca-js/dist/cjs/apis/getAutoReplyList.cjs +0 -29
  1271. package/node_modules/zca-js/dist/cjs/apis/getAvatarList.cjs +0 -33
  1272. package/node_modules/zca-js/dist/cjs/apis/getAvatarUrlProfile.cjs +0 -44
  1273. package/node_modules/zca-js/dist/cjs/apis/getBizAccount.cjs +0 -32
  1274. package/node_modules/zca-js/dist/cjs/apis/getCatalogList.cjs +0 -37
  1275. package/node_modules/zca-js/dist/cjs/apis/getCloseFriends.cjs +0 -25
  1276. package/node_modules/zca-js/dist/cjs/apis/getContext.cjs +0 -9
  1277. package/node_modules/zca-js/dist/cjs/apis/getCookie.cjs +0 -14
  1278. package/node_modules/zca-js/dist/cjs/apis/getFriendBoardList.cjs +0 -31
  1279. package/node_modules/zca-js/dist/cjs/apis/getFriendOnlines.cjs +0 -40
  1280. package/node_modules/zca-js/dist/cjs/apis/getFriendRecommendations.cjs +0 -32
  1281. package/node_modules/zca-js/dist/cjs/apis/getFriendRequestStatus.cjs +0 -30
  1282. package/node_modules/zca-js/dist/cjs/apis/getFullAvatar.cjs +0 -30
  1283. package/node_modules/zca-js/dist/cjs/apis/getGroupBlockedMember.cjs +0 -34
  1284. package/node_modules/zca-js/dist/cjs/apis/getGroupChatHistory.cjs +0 -51
  1285. package/node_modules/zca-js/dist/cjs/apis/getGroupInfo.cjs +0 -37
  1286. package/node_modules/zca-js/dist/cjs/apis/getGroupInviteBoxInfo.cjs +0 -43
  1287. package/node_modules/zca-js/dist/cjs/apis/getGroupInviteBoxList.cjs +0 -36
  1288. package/node_modules/zca-js/dist/cjs/apis/getGroupLinkDetail.cjs +0 -30
  1289. package/node_modules/zca-js/dist/cjs/apis/getGroupLinkInfo.cjs +0 -33
  1290. package/node_modules/zca-js/dist/cjs/apis/getGroupMembersInfo.cjs +0 -29
  1291. package/node_modules/zca-js/dist/cjs/apis/getHiddenConversations.cjs +0 -28
  1292. package/node_modules/zca-js/dist/cjs/apis/getLabels.cjs +0 -33
  1293. package/node_modules/zca-js/dist/cjs/apis/getListBank.cjs +0 -25
  1294. package/node_modules/zca-js/dist/cjs/apis/getListBankAccount.cjs +0 -32
  1295. package/node_modules/zca-js/dist/cjs/apis/getListBoard.cjs +0 -59
  1296. package/node_modules/zca-js/dist/cjs/apis/getListDevice.cjs +0 -27
  1297. package/node_modules/zca-js/dist/cjs/apis/getListReminder.cjs +0 -61
  1298. package/node_modules/zca-js/dist/cjs/apis/getMultiUsersByPhones.cjs +0 -53
  1299. package/node_modules/zca-js/dist/cjs/apis/getMute.cjs +0 -27
  1300. package/node_modules/zca-js/dist/cjs/apis/getOwnId.cjs +0 -9
  1301. package/node_modules/zca-js/dist/cjs/apis/getPendingGroupMembers.cjs +0 -32
  1302. package/node_modules/zca-js/dist/cjs/apis/getPinConversations.cjs +0 -27
  1303. package/node_modules/zca-js/dist/cjs/apis/getPollDetail.cjs +0 -35
  1304. package/node_modules/zca-js/dist/cjs/apis/getProductCatalogList.cjs +0 -38
  1305. package/node_modules/zca-js/dist/cjs/apis/getQR.cjs +0 -34
  1306. package/node_modules/zca-js/dist/cjs/apis/getQuickMessageList.cjs +0 -29
  1307. package/node_modules/zca-js/dist/cjs/apis/getRelatedFriendGroup.cjs +0 -35
  1308. package/node_modules/zca-js/dist/cjs/apis/getReminder.cjs +0 -30
  1309. package/node_modules/zca-js/dist/cjs/apis/getReminderResponses.cjs +0 -29
  1310. package/node_modules/zca-js/dist/cjs/apis/getSentFriendRequest.cjs +0 -29
  1311. package/node_modules/zca-js/dist/cjs/apis/getSettings.cjs +0 -25
  1312. package/node_modules/zca-js/dist/cjs/apis/getStickerCategoryDetail.cjs +0 -29
  1313. package/node_modules/zca-js/dist/cjs/apis/getStickers.cjs +0 -45
  1314. package/node_modules/zca-js/dist/cjs/apis/getStickersDetail.cjs +0 -45
  1315. package/node_modules/zca-js/dist/cjs/apis/getUnreadMark.cjs +0 -35
  1316. package/node_modules/zca-js/dist/cjs/apis/getUserInfo.cjs +0 -58
  1317. package/node_modules/zca-js/dist/cjs/apis/inviteUserToGroups.cjs +0 -35
  1318. package/node_modules/zca-js/dist/cjs/apis/joinGroupInviteBox.cjs +0 -30
  1319. package/node_modules/zca-js/dist/cjs/apis/joinGroupLink.cjs +0 -32
  1320. package/node_modules/zca-js/dist/cjs/apis/keepAlive.cjs +0 -27
  1321. package/node_modules/zca-js/dist/cjs/apis/lastOnline.cjs +0 -31
  1322. package/node_modules/zca-js/dist/cjs/apis/leaveGroup.cjs +0 -38
  1323. package/node_modules/zca-js/dist/cjs/apis/listen.cjs +0 -440
  1324. package/node_modules/zca-js/dist/cjs/apis/lockPoll.cjs +0 -33
  1325. package/node_modules/zca-js/dist/cjs/apis/login.cjs +0 -102
  1326. package/node_modules/zca-js/dist/cjs/apis/loginQR.cjs +0 -368
  1327. package/node_modules/zca-js/dist/cjs/apis/logoutV2.cjs +0 -83
  1328. package/node_modules/zca-js/dist/cjs/apis/lostFocus.cjs +0 -28
  1329. package/node_modules/zca-js/dist/cjs/apis/parseLink.cjs +0 -32
  1330. package/node_modules/zca-js/dist/cjs/apis/registerCatalog.cjs +0 -32
  1331. package/node_modules/zca-js/dist/cjs/apis/rejectFriendRequest.cjs +0 -32
  1332. package/node_modules/zca-js/dist/cjs/apis/removeFriend.cjs +0 -33
  1333. package/node_modules/zca-js/dist/cjs/apis/removeFriendAlias.cjs +0 -29
  1334. package/node_modules/zca-js/dist/cjs/apis/removeGroupBlockedMember.cjs +0 -33
  1335. package/node_modules/zca-js/dist/cjs/apis/removeGroupDeputy.cjs +0 -35
  1336. package/node_modules/zca-js/dist/cjs/apis/removeQuickMessage.cjs +0 -32
  1337. package/node_modules/zca-js/dist/cjs/apis/removeReminder.cjs +0 -54
  1338. package/node_modules/zca-js/dist/cjs/apis/removeUnreadMark.cjs +0 -64
  1339. package/node_modules/zca-js/dist/cjs/apis/removeUserFromGroup.cjs +0 -39
  1340. package/node_modules/zca-js/dist/cjs/apis/resetHiddenConversPin.cjs +0 -25
  1341. package/node_modules/zca-js/dist/cjs/apis/reuseAvatar.cjs +0 -31
  1342. package/node_modules/zca-js/dist/cjs/apis/reviewPendingMemberRequest.cjs +0 -43
  1343. package/node_modules/zca-js/dist/cjs/apis/scanURL.cjs +0 -33
  1344. package/node_modules/zca-js/dist/cjs/apis/searchSticker.cjs +0 -33
  1345. package/node_modules/zca-js/dist/cjs/apis/sendBankCard.cjs +0 -68
  1346. package/node_modules/zca-js/dist/cjs/apis/sendCard.cjs +0 -89
  1347. package/node_modules/zca-js/dist/cjs/apis/sendDeliveredEvent.cjs +0 -69
  1348. package/node_modules/zca-js/dist/cjs/apis/sendFriendRequest.cjs +0 -44
  1349. package/node_modules/zca-js/dist/cjs/apis/sendLink.cjs +0 -92
  1350. package/node_modules/zca-js/dist/cjs/apis/sendMessage.cjs +0 -500
  1351. package/node_modules/zca-js/dist/cjs/apis/sendReport.cjs +0 -67
  1352. package/node_modules/zca-js/dist/cjs/apis/sendSeenEvent.cjs +0 -77
  1353. package/node_modules/zca-js/dist/cjs/apis/sendSticker.cjs +0 -88
  1354. package/node_modules/zca-js/dist/cjs/apis/sendTypingEvent.cjs +0 -47
  1355. package/node_modules/zca-js/dist/cjs/apis/sendVideo.cjs +0 -148
  1356. package/node_modules/zca-js/dist/cjs/apis/sendVoice.cjs +0 -103
  1357. package/node_modules/zca-js/dist/cjs/apis/setHiddenConversations.cjs +0 -53
  1358. package/node_modules/zca-js/dist/cjs/apis/setMute.cjs +0 -81
  1359. package/node_modules/zca-js/dist/cjs/apis/setPinnedConversations.cjs +0 -48
  1360. package/node_modules/zca-js/dist/cjs/apis/sharePoll.cjs +0 -33
  1361. package/node_modules/zca-js/dist/cjs/apis/unblockUser.cjs +0 -33
  1362. package/node_modules/zca-js/dist/cjs/apis/undo.cjs +0 -56
  1363. package/node_modules/zca-js/dist/cjs/apis/undoFriendRequest.cjs +0 -32
  1364. package/node_modules/zca-js/dist/cjs/apis/updateActiveStatus.cjs +0 -32
  1365. package/node_modules/zca-js/dist/cjs/apis/updateArchivedChatList.cjs +0 -39
  1366. package/node_modules/zca-js/dist/cjs/apis/updateAutoDeleteChat.cjs +0 -54
  1367. package/node_modules/zca-js/dist/cjs/apis/updateAutoReply.cjs +0 -43
  1368. package/node_modules/zca-js/dist/cjs/apis/updateBankAccount.cjs +0 -36
  1369. package/node_modules/zca-js/dist/cjs/apis/updateCatalog.cjs +0 -35
  1370. package/node_modules/zca-js/dist/cjs/apis/updateGroupSettings.cjs +0 -48
  1371. package/node_modules/zca-js/dist/cjs/apis/updateHiddenConversPin.cjs +0 -35
  1372. package/node_modules/zca-js/dist/cjs/apis/updateLabels.cjs +0 -39
  1373. package/node_modules/zca-js/dist/cjs/apis/updateLang.cjs +0 -35
  1374. package/node_modules/zca-js/dist/cjs/apis/updateProductCatalog.cjs +0 -56
  1375. package/node_modules/zca-js/dist/cjs/apis/updateProfile.cjs +0 -48
  1376. package/node_modules/zca-js/dist/cjs/apis/updateProfileBio.cjs +0 -32
  1377. package/node_modules/zca-js/dist/cjs/apis/updateQuickMessage.cjs +0 -66
  1378. package/node_modules/zca-js/dist/cjs/apis/updateSettings.cjs +0 -95
  1379. package/node_modules/zca-js/dist/cjs/apis/upgradeGroupToCommunity.cjs +0 -32
  1380. package/node_modules/zca-js/dist/cjs/apis/uploadAttachment.cjs +0 -211
  1381. package/node_modules/zca-js/dist/cjs/apis/uploadProductPhoto.cjs +0 -55
  1382. package/node_modules/zca-js/dist/cjs/apis/votePoll.cjs +0 -34
  1383. package/node_modules/zca-js/dist/cjs/apis.cjs +0 -324
  1384. package/node_modules/zca-js/dist/cjs/context.cjs +0 -34
  1385. package/node_modules/zca-js/dist/cjs/index.cjs +0 -159
  1386. package/node_modules/zca-js/dist/cjs/models/AutoReply.cjs +0 -9
  1387. package/node_modules/zca-js/dist/cjs/models/Bank.cjs +0 -263
  1388. package/node_modules/zca-js/dist/cjs/models/Board.cjs +0 -8
  1389. package/node_modules/zca-js/dist/cjs/models/DeliveredMessage.cjs +0 -23
  1390. package/node_modules/zca-js/dist/cjs/models/Enum.cjs +0 -27
  1391. package/node_modules/zca-js/dist/cjs/models/FriendEvent.cjs +0 -87
  1392. package/node_modules/zca-js/dist/cjs/models/Group.cjs +0 -13
  1393. package/node_modules/zca-js/dist/cjs/models/GroupEvent.cjs +0 -94
  1394. package/node_modules/zca-js/dist/cjs/models/Message.cjs +0 -35
  1395. package/node_modules/zca-js/dist/cjs/models/Reaction.cjs +0 -74
  1396. package/node_modules/zca-js/dist/cjs/models/Reminder.cjs +0 -9
  1397. package/node_modules/zca-js/dist/cjs/models/SeenMessage.cjs +0 -23
  1398. package/node_modules/zca-js/dist/cjs/models/Typing.cjs +0 -23
  1399. package/node_modules/zca-js/dist/cjs/models/Undo.cjs +0 -16
  1400. package/node_modules/zca-js/dist/cjs/models/ZBusiness.cjs +0 -39
  1401. package/node_modules/zca-js/dist/cjs/update.cjs +0 -34
  1402. package/node_modules/zca-js/dist/cjs/utils.cjs +0 -703
  1403. package/node_modules/zca-js/dist/cjs/zalo.cjs +0 -112
  1404. package/node_modules/zca-js/dist/context.d.ts +0 -179
  1405. package/node_modules/zca-js/dist/context.js +0 -28
  1406. package/node_modules/zca-js/dist/index.d.ts +0 -166
  1407. package/node_modules/zca-js/dist/index.js +0 -14
  1408. package/node_modules/zca-js/dist/models/Attachment.d.ts +0 -9
  1409. package/node_modules/zca-js/dist/models/Attachment.js +0 -1
  1410. package/node_modules/zca-js/dist/models/AutoReply.d.ts +0 -20
  1411. package/node_modules/zca-js/dist/models/AutoReply.js +0 -7
  1412. package/node_modules/zca-js/dist/models/Bank.d.ts +0 -291
  1413. package/node_modules/zca-js/dist/models/Bank.js +0 -262
  1414. package/node_modules/zca-js/dist/models/Board.d.ts +0 -60
  1415. package/node_modules/zca-js/dist/models/Board.js +0 -6
  1416. package/node_modules/zca-js/dist/models/Catalog.d.ts +0 -16
  1417. package/node_modules/zca-js/dist/models/Catalog.js +0 -1
  1418. package/node_modules/zca-js/dist/models/DeliveredMessage.d.ts +0 -27
  1419. package/node_modules/zca-js/dist/models/DeliveredMessage.js +0 -17
  1420. package/node_modules/zca-js/dist/models/Enum.d.ts +0 -21
  1421. package/node_modules/zca-js/dist/models/Enum.js +0 -25
  1422. package/node_modules/zca-js/dist/models/FriendEvent.d.ts +0 -107
  1423. package/node_modules/zca-js/dist/models/FriendEvent.js +0 -83
  1424. package/node_modules/zca-js/dist/models/Group.d.ts +0 -125
  1425. package/node_modules/zca-js/dist/models/Group.js +0 -11
  1426. package/node_modules/zca-js/dist/models/GroupEvent.d.ts +0 -178
  1427. package/node_modules/zca-js/dist/models/GroupEvent.js +0 -90
  1428. package/node_modules/zca-js/dist/models/Label.d.ts +0 -10
  1429. package/node_modules/zca-js/dist/models/Label.js +0 -1
  1430. package/node_modules/zca-js/dist/models/Message.d.ts +0 -91
  1431. package/node_modules/zca-js/dist/models/Message.js +0 -29
  1432. package/node_modules/zca-js/dist/models/ProductCatalog.d.ts +0 -17
  1433. package/node_modules/zca-js/dist/models/ProductCatalog.js +0 -1
  1434. package/node_modules/zca-js/dist/models/QuickMessage.d.ts +0 -25
  1435. package/node_modules/zca-js/dist/models/QuickMessage.js +0 -1
  1436. package/node_modules/zca-js/dist/models/Reaction.d.ts +0 -85
  1437. package/node_modules/zca-js/dist/models/Reaction.js +0 -70
  1438. package/node_modules/zca-js/dist/models/Reminder.d.ts +0 -51
  1439. package/node_modules/zca-js/dist/models/Reminder.js +0 -7
  1440. package/node_modules/zca-js/dist/models/SeenMessage.d.ts +0 -26
  1441. package/node_modules/zca-js/dist/models/SeenMessage.js +0 -17
  1442. package/node_modules/zca-js/dist/models/Sticker.d.ts +0 -27
  1443. package/node_modules/zca-js/dist/models/Sticker.js +0 -1
  1444. package/node_modules/zca-js/dist/models/Typing.d.ts +0 -24
  1445. package/node_modules/zca-js/dist/models/Typing.js +0 -17
  1446. package/node_modules/zca-js/dist/models/Undo.d.ts +0 -34
  1447. package/node_modules/zca-js/dist/models/Undo.js +0 -12
  1448. package/node_modules/zca-js/dist/models/User.d.ts +0 -70
  1449. package/node_modules/zca-js/dist/models/User.js +0 -1
  1450. package/node_modules/zca-js/dist/models/ZBusiness.d.ts +0 -22
  1451. package/node_modules/zca-js/dist/models/ZBusiness.js +0 -35
  1452. package/node_modules/zca-js/dist/models/index.d.ts +0 -22
  1453. package/node_modules/zca-js/dist/models/index.js +0 -22
  1454. package/node_modules/zca-js/dist/update.d.ts +0 -2
  1455. package/node_modules/zca-js/dist/update.js +0 -29
  1456. package/node_modules/zca-js/dist/utils.d.ts +0 -167
  1457. package/node_modules/zca-js/dist/utils.js +0 -719
  1458. package/node_modules/zca-js/dist/zalo.d.ts +0 -41
  1459. package/node_modules/zca-js/dist/zalo.js +0 -107
  1460. package/node_modules/zca-js/eslint.config.js +0 -21
  1461. package/node_modules/zca-js/index.d.ts +0 -2
  1462. package/node_modules/zca-js/package.json +0 -78
  1463. package/node_modules/zca-js/rollup.config.js +0 -28
  1464. package/patches/zca-js+2.2.0.patch +0 -1445
  1465. package/src/cli.test.js +0 -127
  1466. package/src/core/forward.js +0 -112
  1467. package/src/core/group-history.js +0 -248
  1468. package/src/core/group-invite.js +0 -53
  1469. package/src/core/offline-queue.js +0 -194
  1470. package/src/core/pin.js +0 -222
  1471. package/src/core/socket-tap.js +0 -154
  1472. package/src/core/sync-v2/assets.js +0 -181
  1473. package/src/core/sync-v2/gid.js +0 -106
  1474. package/src/core/sync-v2/keepalive.js +0 -177
  1475. package/src/core/sync-v2/message-types.js +0 -522
  1476. package/src/core/sync-v2/renewlink.js +0 -124
  1477. package/src/core/sync-v2/zcloud-cipher.js +0 -88
  1478. package/src/core/zca-custom.js +0 -78
  1479. package/src/mcp/message-buffer.test.js +0 -360
  1480. package/src/mcp/notifier.test.js +0 -275
  1481. package/src/mcp/thread-filter.test.js +0 -206
  1482. package/src/mcp/thread-name-cache.test.js +0 -142
  1483. package/src/utils/atomic-file.js +0 -209
  1484. package/src/utils/bank-helpers.test.js +0 -66
  1485. package/src/utils/device-fingerprint.js +0 -72
  1486. package/src/utils/mentions.js +0 -140
  1487. package/src/utils/proxy-helpers.test.js +0 -36
  1488. package/src/utils/split-message.js +0 -222
  1489. package/src/utils/urgency.js +0 -29
  1490. /package/src/{core → zalo/custom}/user-info.js +0 -0
  1491. /package/src/{utils → zalo/format}/extract-message-text.js +0 -0
  1492. /package/src/{utils → zalo/format}/markdown.js +0 -0
package/src/core/db.js CHANGED
@@ -1,19 +1,84 @@
1
1
  import { mkdirSync } from "node:fs";
2
2
  import { dirname } from "node:path";
3
- import Database from "better-sqlite3";
3
+ import { openDatabase } from "./sqlite.js";
4
+ import { stripVietnamese } from "../utils/vn-text.js";
5
+ import { aliasFor, dmTitle } from "./contact-names.js";
6
+ import { deriveDataKey, readKeyring, scopeOfDir } from "./keystore/keyring.js";
7
+ import { readStorageFile } from "./keystore/config.js";
8
+ import {
9
+ RowIntegrityError,
10
+ checkRow,
11
+ ephemeralRowMacKey,
12
+ installRowMac,
13
+ registerRowMacFunction,
14
+ verifyOnReadMode,
15
+ verifyRows,
16
+ } from "./row-mac.js";
4
17
 
5
18
  let db;
19
+ /** The open database's row-MAC keys (./row-mac.js): the current one, and how to get retired ones. */
20
+ let rowMacKeys = null;
21
+ /** Is the search index of the open database complete? Reset by {@link initDb}. */
22
+ let searchReady = false;
23
+ /**
24
+ * The retention floor (`sync_state.retentionFloor`, epoch ms): the quota/retention purge (./storage-quota.js) deleted
25
+ * every message at or before it, and no writer may store one there again: a re-sync or a history fetch would
26
+ * otherwise bring back what was purged.
27
+ */
28
+ let retentionFloor = 0;
29
+ /** Bumped whenever a database is opened or closed, so per-account caches elsewhere know to reload. */
30
+ let dbGeneration = 0;
31
+ /** How long one search may spend building the index before it answers by scanning. */
32
+ let searchBudgetMs = 2000;
33
+ /** Told how the first search's preparation is going (a command shows it; nothing else needs to). */
34
+ let searchProgress;
35
+
36
+ /**
37
+ * Change how a search prepares its index: how much it may build per search (default 2 s; 0 builds nothing, so every
38
+ * search scans), and who is told of progress.
39
+ *
40
+ * @param {{budgetMs?: number, onProgress?: ((p: {phase: string, done: number, total: number|null}) => void)|null}} opts
41
+ */
42
+ export function configureSearchIndex({ budgetMs, onProgress } = {}) {
43
+ if (Number.isFinite(budgetMs)) searchBudgetMs = budgetMs;
44
+ if (onProgress !== undefined) searchProgress = onProgress ?? undefined;
45
+ }
46
+
47
+ /**
48
+ * The client-side id a message's sender generated, read out of raw_data. Guarded with json_valid() because an older
49
+ * writer stored the bare content string in raw_data on six figures of rows, and an unguarded json_extract over this
50
+ * table raises "malformed JSON". Indexed (idx_messages_cli): a lookup by this expression must be written exactly
51
+ * this way to use the index.
52
+ */
53
+ const CLIENT_ID_EXPR = "CASE WHEN json_valid(raw_data) THEN json_extract(raw_data, '$.cliMsgId') END";
54
+
55
+ /** A message text as the `text_norm` column holds it: folded, or null when the message has no text. */
56
+ function foldedText(text) {
57
+ return text === undefined || text === null ? null : stripVietnamese(text);
58
+ }
6
59
 
60
+ /**
61
+ * Open (creating if needed) the account's message cache and bring its schema up to date. The account is the folder
62
+ * the file is in (`accounts/<ownId>/zalo.db`): its key comes from that account's keyring.
63
+ *
64
+ * @param {string} dbPath
65
+ * @returns {import("better-sqlite3-multiple-ciphers").Database}
66
+ * @throws {import("./keystore/container.js").KeystoreError} when the database's key cannot be had (fail closed)
67
+ */
7
68
  export function initDb(dbPath) {
8
69
  // A fresh login has no accounts/<ownId>/ yet: only a daemon taking its
9
70
  // lock (lock.js) used to create it, so every command that opened the
10
71
  // cache before a listener had ever run crashed (sync-cloud, live
11
72
  // 2026-09-30: "Cannot open database because the directory does not exist").
12
73
  mkdirSync(dirname(dbPath), { recursive: true });
13
- db = new Database(dbPath);
14
-
15
- // Enable WAL mode for better performance
16
- db.pragma("journal_mode = WAL");
74
+ // Encrypted at rest (SQLCipher, keyed from the account's data key; src/core/sqlite.js). A plaintext database from
75
+ // 2.x is encrypted here, once, before anything reads it. WAL and secure_delete are set by the opener.
76
+ db = openDatabase(dbPath);
77
+ dbGeneration++;
78
+ // Row MACs (./row-mac.js): the triggers that keep them call this function, so it is registered before any
79
+ // statement below that could fire one.
80
+ rowMacKeys = rowMacKeysFor(dbPath);
81
+ registerRowMacFunction(db, rowMacKeys.current);
17
82
 
18
83
  // Create tables
19
84
  db.exec(`
@@ -60,10 +125,8 @@ export function initDb(dbPath) {
60
125
  );
61
126
 
62
127
  -- Tracks time windows where we know (or suspect) messages may have been
63
- -- missed — mirrors Zalo Web's own client-side "MissingMessageRange" table
64
- -- (confirmed live via its IndexedDB schema: id/convId/fromTs/toTs/reason/status)
65
- -- but kept account-wide rather than per-conversation, since pullMobileMsg/
66
- -- getCrossDB operate on the whole account, not a single thread.
128
+ -- missed (id/convId/fromTs/toTs/reason/status), kept account-wide rather than per-conversation, since
129
+ -- pullMobileMsg/getCrossDB operate on the whole account, not a single thread.
67
130
  CREATE TABLE IF NOT EXISTS sync_gaps (
68
131
  id INTEGER PRIMARY KEY AUTOINCREMENT,
69
132
  fromTs INTEGER,
@@ -74,10 +137,25 @@ export function initDb(dbPath) {
74
137
  resolvedAt INTEGER
75
138
  );
76
139
 
140
+ -- What the phone-backed restore has settled, per conversation partition (oneone/<id> or group/<id>):
141
+ -- the window [fromTs, toTs] it asked for, and whether that is done, failed or still pending. This is
142
+ -- what lets a run that was killed pick up where it stopped, lets a later run ask only for what came
143
+ -- after the last one, and keeps a partly failed run from counting as a success. The ids are the phone's
144
+ -- opaque conversation ids, never a real thread id.
145
+ CREATE TABLE IF NOT EXISTS sync_ranges (
146
+ partition TEXT PRIMARY KEY,
147
+ fromTs INTEGER NOT NULL,
148
+ toTs INTEGER NOT NULL,
149
+ status TEXT NOT NULL,
150
+ reason TEXT,
151
+ attempts INTEGER NOT NULL DEFAULT 0,
152
+ updatedAt INTEGER NOT NULL
153
+ );
154
+
77
155
  -- Board items: notes ("Ghi chú"), pinned messages and polls. These are NOT
78
156
  -- in the transfer-sync message stream at all — Zalo keeps them behind
79
157
  -- /api/board/list, one call per thread — so they are synced separately and
80
- -- stored here. boardType mirrors zca-js BoardType: 1=Note, 2=PinnedMessage,
158
+ -- stored here. boardType mirrors Zalo's board types: 1=Note, 2=PinnedMessage,
81
159
  -- 3=Poll. The id column is scoped by thread because item ids repeat across
82
160
  -- threads. (No backticks anywhere in this SQL: it sits inside a JS template
83
161
  -- literal, so one would close it and break the whole module.)
@@ -146,7 +224,7 @@ export function initDb(dbPath) {
146
224
 
147
225
  -- Reactions. NOT in the mobile sync payload at all -- the Sync2 protobuf
148
226
  -- has no reaction field. They are NOT unrecoverable, though: the socket
149
- -- serves them on cmd 610 (1-1) and 611 (group), which is how Zalo Web shows
227
+ -- serves them on cmd 610 (1-1) and 611 (group), which is how a client shows
150
228
  -- them after a fresh login, so they arrive either live (cmd 612) or from
151
229
  -- the sync-reactions command. (No backticks in this SQL: it sits inside a
152
230
  -- JS template literal, so one would close it and break the module.)
@@ -186,6 +264,14 @@ export function initDb(dbPath) {
186
264
  CREATE INDEX IF NOT EXISTS idx_cloud_msg ON cloud_items(msgId);
187
265
  CREATE INDEX IF NOT EXISTS idx_messages_thread_ts ON messages(threadId, timestamp DESC);
188
266
  CREATE INDEX IF NOT EXISTS idx_messages_attach ON messages(has_attachment) WHERE has_attachment = 1;
267
+ -- The repairs below run on every open. With the cache encrypted (SQLCipher) a full scan of messages decrypts every
268
+ -- page, about 0.7 s per 100,000 messages, and there were four of them: these two indexes answer all four.
269
+ CREATE INDEX IF NOT EXISTS idx_messages_type ON messages(type);
270
+ CREATE INDEX IF NOT EXISTS idx_messages_sender_thread ON messages(senderId, threadId);
271
+ -- Without this, every lookup by client id read and parsed the JSON of every row of the thread: 190 ms per
272
+ -- message on a 42,000-row thread, which stalled the event loop for minutes during a restore and got the
273
+ -- socket closed (1006).
274
+ CREATE INDEX IF NOT EXISTS idx_messages_cli ON messages((${CLIENT_ID_EXPR}), threadId);
189
275
  CREATE INDEX IF NOT EXISTS idx_board_thread ON board_items(threadId, boardType);
190
276
  CREATE INDEX IF NOT EXISTS idx_reminders_thread ON reminders(threadId);
191
277
  `);
@@ -227,6 +313,35 @@ export function initDb(dbPath) {
227
313
  try {
228
314
  db.exec("ALTER TABLE messages ADD COLUMN mediaPrunedAt INTEGER");
229
315
  } catch {}
316
+ // The rows that point at a downloaded file, a few hundred of several hundred thousand: what the media migration
317
+ // (media-store.js referencedMedia) and the retention purge (getDownloadedMediaBefore) read, on a daemon's own
318
+ // thread. Without it each was a walk of the whole table, which on the encrypted database (every page decrypted and
319
+ // checked) MEASURED 1.8 s and 2.5 s on 436,000 rows: an event-loop stall the socket felt. Built once (about 2 s on
320
+ // that database, here at the start, before any socket is open).
321
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_localpath ON messages(timestamp) WHERE localPath IS NOT NULL");
322
+ // The text a search matches: `text` folded the way Zalo's own clients fold it (lowercase, Vietnamese vowels to
323
+ // bare letters, đ to d; src/utils/vn-text.js). Kept by the message writers below. Rows written before the column
324
+ // existed are filled in, and the indexes a search wants are built, the first time a search runs
325
+ // ({@link ensureSearchIndex}): adding a column is instant, building an index on 400,000 messages is not, and no
326
+ // other command should pay for it.
327
+ try {
328
+ db.exec("ALTER TABLE messages ADD COLUMN text_norm TEXT");
329
+ } catch {}
330
+ // What the zCloud queue needs to apply a removal: `zKey` (`cliMsgId_conversation_sender`, the key a remove entry
331
+ // names its victims by), `seenAt` (the start time of the last walk that listed the item, for a full walk's sweep)
332
+ // and the key/algorithm versions the item's `encryptInfo` carries. All nullable; `sync-cloud` fills the first two
333
+ // for rows written before they existed.
334
+ for (const col of ["zKey TEXT", "seenAt INTEGER", "keyVersion INTEGER", "algoVersion INTEGER"]) {
335
+ try {
336
+ db.exec(`ALTER TABLE cloud_items ADD COLUMN ${col}`);
337
+ } catch {}
338
+ }
339
+ db.exec("CREATE INDEX IF NOT EXISTS idx_cloud_zkey ON cloud_items(zKey)");
340
+ // The fold as an SQL function, for the rows that have none yet.
341
+ db.function("vn_strip", { deterministic: true }, (s) =>
342
+ s === null || s === undefined ? null : stripVietnamese(s),
343
+ );
344
+ searchReady = false;
230
345
  // An older listener stored the raw live msgType as the row type, so
231
346
  // removals landed as 'chat.undo'/'chat.delete' and media as
232
347
  // 'chat.photo'/'share.file'/... Every query keyed on the shared vocabulary
@@ -302,9 +417,10 @@ export function initDb(dbPath) {
302
417
  // lines are excluded: their sender is whoever acted.
303
418
  try {
304
419
  db.prepare(
305
- "UPDATE threads SET type = 'dm' WHERE type = 'group' AND threadId IN " +
306
- "(SELECT threadId FROM messages WHERE senderId = threadId AND msgId NOT LIKE 'ge:%' " +
307
- "AND COALESCE(type, '') NOT IN ('group_event', 'event', 'poll_event', 'deleted'))",
420
+ // EXISTS per group thread (by idx_messages_sender_thread), not IN over a scan of every message.
421
+ "UPDATE threads SET type = 'dm' WHERE type = 'group' AND EXISTS " +
422
+ "(SELECT 1 FROM messages m WHERE m.senderId = threads.threadId AND m.threadId = threads.threadId " +
423
+ "AND m.msgId NOT LIKE 'ge:%' AND COALESCE(m.type, '') NOT IN ('group_event', 'event', 'poll_event', 'deleted'))",
308
424
  ).run();
309
425
  } catch {
310
426
  /* no messages table yet, or nothing to heal */
@@ -329,6 +445,12 @@ export function initDb(dbPath) {
329
445
  db.exec("UPDATE threads SET deleteMarkerAt = leftAt WHERE leftAt IS NOT NULL");
330
446
  })();
331
447
  }
448
+ // Why a group stopped being ours (./group-exit.js): leave, removed, blocked or disbanded. Set with leftAt by a
449
+ // group exit only; a conversation list or `conv delete` leaves it null. While it is set, only a `join` naming us
450
+ // (or a message dated after leftAt) brings the group back.
451
+ try {
452
+ db.exec("ALTER TABLE threads ADD COLUMN goneReason TEXT");
453
+ } catch {}
332
454
  // The read watermark: the newest message this account has read in the
333
455
  // conversation, on any device, as the server reports it (./read-state.js).
334
456
  // Nullable: nothing is known until the listener sees a report.
@@ -338,10 +460,230 @@ export function initDb(dbPath) {
338
460
  try {
339
461
  db.exec("ALTER TABLE conv_state ADD COLUMN lastReadTs INTEGER");
340
462
  } catch {}
463
+ // Unread reactions (./read-state.js): the newest reaction someone else made in the conversation (its own msgId,
464
+ // from the reaction pushes) and the newest one reported seen (cmd 613 clearUnreads). `conv read` sends
465
+ // react_seen when the first is newer than the second.
466
+ try {
467
+ db.exec("ALTER TABLE conv_state ADD COLUMN reactUnreadId TEXT");
468
+ } catch {}
469
+ try {
470
+ db.exec("ALTER TABLE conv_state ADD COLUMN reactSeenId TEXT");
471
+ } catch {}
472
+ // When each user was last online, as the listener hears it (602 online_status) (./last-online.js). Read by
473
+ // `friend last-online --cached` and zalo_friend `last_online` with `cached`, without a request.
474
+ db.exec(
475
+ "CREATE TABLE IF NOT EXISTS last_online (userId TEXT PRIMARY KEY, lastOnline INTEGER, updatedAt INTEGER, source TEXT)",
476
+ );
477
+ // The account owner's aliases for other users, as the last complete alias-list read gave them
478
+ // (./contact-names.js). A snapshot: a row absent from it means no alias. Read by every command that names a person.
479
+ db.exec(
480
+ "CREATE TABLE IF NOT EXISTS user_aliases (userId TEXT PRIMARY KEY, alias TEXT NOT NULL, updatedAt INTEGER)",
481
+ );
482
+ // Last, after the repairs above: the MAC table and triggers, and (once per database) the MACs of the rows written
483
+ // before they existed.
484
+ installRowMac(db, rowMacKeys.current, { log: (l) => console.error(l) });
485
+ retentionFloor = Number(db.prepare("SELECT value FROM sync_state WHERE key = 'retentionFloor'").get()?.value) || 0;
341
486
 
342
487
  return db;
343
488
  }
344
489
 
490
+ /** True when a message at this time is at or before the retention floor: a purge removed it and it stays removed. */
491
+ function belowFloor(msg) {
492
+ const ts = Number(msg?.timestamp);
493
+ return retentionFloor > 0 && Number.isFinite(ts) && ts > 0 && ts <= retentionFloor;
494
+ }
495
+
496
+ /**
497
+ * True when a message is at or before its conversation's delete marker (threads.deleteMarkerAt): `conv delete` or a
498
+ * group exit removed everything up to it, and no writer -- the listener, a phone restore, a history or cloud fetch --
499
+ * stores one there again (Zalo's per-conversation `deleteAllPrior` tombstone). Read from the table on every write, not
500
+ * cached: another process (`group leave` beside a daemon) may have just set it.
501
+ */
502
+ function belowDeleteMarker(threadId, timestamp) {
503
+ const ts = Number(timestamp);
504
+ if (threadId === undefined || threadId === null || !Number.isFinite(ts) || ts <= 0) return false;
505
+ const at = Number(
506
+ db.prepare("SELECT deleteMarkerAt FROM threads WHERE threadId = ?").get(String(threadId))?.deleteMarkerAt,
507
+ );
508
+ return Number.isFinite(at) && at > 0 && ts <= at;
509
+ }
510
+
511
+ /**
512
+ * The retention floor (epoch ms), 0 when nothing was ever purged.
513
+ *
514
+ * @returns {number}
515
+ */
516
+ export function getRetentionFloor() {
517
+ return retentionFloor;
518
+ }
519
+
520
+ /**
521
+ * The bytes the database's pages in use take (page count less the free pages, times the page size). A purge lowers it
522
+ * at once; the file keeps its size until a VACUUM, and SQLite reuses the free pages first.
523
+ *
524
+ * @returns {number}
525
+ */
526
+ export function dbUsedBytes() {
527
+ if (!db) throw new Error("Database not initialized");
528
+ const pages = Number(db.pragma("page_count", { simple: true })) || 0;
529
+ const free = Number(db.pragma("freelist_count", { simple: true })) || 0;
530
+ const size = Number(db.pragma("page_size", { simple: true })) || 0;
531
+ return Math.max(0, pages - free) * size;
532
+ }
533
+
534
+ /**
535
+ * The timestamp of the n-th oldest cached message (1-based), or null when there are fewer.
536
+ *
537
+ * @param {number} n
538
+ * @returns {number|null}
539
+ */
540
+ export function nthOldestMessageTimestamp(n) {
541
+ if (!db) throw new Error("Database not initialized");
542
+ const row = db
543
+ .prepare("SELECT timestamp FROM messages WHERE timestamp > 0 ORDER BY timestamp ASC LIMIT 1 OFFSET ?")
544
+ .get(Math.max(0, Math.floor(n) - 1));
545
+ return row ? Number(row.timestamp) : null;
546
+ }
547
+
548
+ /**
549
+ * Count what a purge through `cutoff` would remove: the messages at or before it and the media files they hold.
550
+ *
551
+ * @param {number} cutoff - epoch ms
552
+ * @returns {{rows: number, files: number}}
553
+ */
554
+ export function countMessagesThrough(cutoff) {
555
+ if (!db) throw new Error("Database not initialized");
556
+ const r = db
557
+ .prepare(
558
+ "SELECT count(*) AS rows, count(localPath) AS files FROM messages WHERE timestamp > 0 AND timestamp <= ?",
559
+ )
560
+ .get(Number(cutoff));
561
+ return { rows: Number(r.rows) || 0, files: Number(r.files) || 0 };
562
+ }
563
+
564
+ /**
565
+ * Delete every message at or before `cutoff` (and its reactions; its row MAC and search entry go with it through
566
+ * their triggers), and raise the retention floor to `cutoff` so no writer stores one there again. Delete-only: the
567
+ * quota/retention purge, run by the daemon holding daemon.lock (./storage-quota.js). With `secure_delete` on, the
568
+ * freed pages are zeroed.
569
+ *
570
+ * @param {number} cutoff - epoch ms
571
+ * @returns {{rows: number, reactions: number, files: string[], floor: number}} `files`: the media files those
572
+ * messages held, for the caller to delete
573
+ */
574
+ export function purgeMessagesThrough(cutoff) {
575
+ if (!db) throw new Error("Database not initialized");
576
+ const at = Number(cutoff);
577
+ if (!Number.isFinite(at) || at <= 0) throw new Error("a purge needs a cutoff time");
578
+ return db.transaction(() => {
579
+ const files = db
580
+ .prepare("SELECT localPath FROM messages WHERE timestamp > 0 AND timestamp <= ? AND localPath IS NOT NULL")
581
+ .all(at)
582
+ .map((r) => r.localPath);
583
+ const reactions = db
584
+ .prepare(
585
+ "DELETE FROM reactions WHERE msgId IN (SELECT msgId FROM messages WHERE timestamp > 0 AND timestamp <= ?)",
586
+ )
587
+ .run(at).changes;
588
+ const rows = db.prepare("DELETE FROM messages WHERE timestamp > 0 AND timestamp <= ?").run(at).changes;
589
+ if (at > retentionFloor) {
590
+ retentionFloor = at;
591
+ db.prepare(
592
+ "INSERT INTO sync_state (key, value) VALUES ('retentionFloor', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value",
593
+ ).run(String(at));
594
+ }
595
+ return { rows, reactions, files, floor: retentionFloor };
596
+ })();
597
+ }
598
+
599
+ /**
600
+ * Write the WAL back into the database file and truncate it, after a purge (the deleted rows' old pages leave the WAL).
601
+ */
602
+ export function checkpointDb() {
603
+ if (!db) throw new Error("Database not initialized");
604
+ db.pragma("wal_checkpoint(TRUNCATE)");
605
+ }
606
+
607
+ /**
608
+ * The row-MAC keys of the database at `dbPath`: the account's `row-mac` data key, and its retired ones on demand (a
609
+ * rekey that has not finished). A database that belongs to no account (`:memory:`) gets a key for this process only.
610
+ */
611
+ function rowMacKeysFor(dbPath) {
612
+ if (!dbPath || dbPath === ":memory:" || String(dbPath).startsWith("file::memory:")) {
613
+ return { current: ephemeralRowMacKey().key, retired: () => [] };
614
+ }
615
+ const scope = scopeOfDir(dirname(dbPath));
616
+ const { key, keyId } = deriveDataKey(scope, "row-mac");
617
+ let retired;
618
+ return {
619
+ current: key,
620
+ keyId,
621
+ retired: () =>
622
+ (retired ??= (readKeyring(scope.dir)?.retired ?? [])
623
+ .filter((k) => k.use === "data" && k.id !== keyId)
624
+ .flatMap((k) => {
625
+ try {
626
+ return [deriveDataKey(scope, "row-mac", { keyId: k.id }).key];
627
+ } catch {
628
+ return [];
629
+ }
630
+ })),
631
+ };
632
+ }
633
+
634
+ /** Close the open cache, if any (tests; a process that is done with the account). */
635
+ export function closeDb() {
636
+ if (db?.open) db.close();
637
+ db = undefined;
638
+ dbGeneration++;
639
+ rowMacKeys = null;
640
+ searchReady = false;
641
+ retentionFloor = 0;
642
+ }
643
+
644
+ /**
645
+ * Check one cached message row against its row MAC (./row-mac.js).
646
+ *
647
+ * @param {object} row - a `SELECT *` row of messages
648
+ * @returns {"ok"|"bad"|"missing"}
649
+ */
650
+ export function checkMessageRow(row) {
651
+ if (!db) throw new Error("Database not initialized");
652
+ const state = checkRow(db, [rowMacKeys.current], row);
653
+ if (state !== "bad") return state;
654
+ // An unfinished rekey leaves rows under the old key: still the account's own writes.
655
+ return checkRow(db, rowMacKeys.retired(), row) === "ok" ? "ok" : "bad";
656
+ }
657
+
658
+ /**
659
+ * One cached message for an action that acts on it (quote, forward, delete, recall, pin, media), checked against its
660
+ * row MAC unless storage.json's `rowMac.verifyOnRead` is `off`. Null when it is not cached.
661
+ *
662
+ * @param {string} msgId
663
+ * @returns {object|null}
664
+ * @throws {RowIntegrityError} (`code` ROW_MAC) when the row fails its check: the action must not go ahead
665
+ */
666
+ export function getMessageForAction(msgId) {
667
+ const row = getMessageById(msgId);
668
+ if (!row || verifyOnReadMode(readStorageFile()) === "off") return row;
669
+ const state = checkMessageRow(row);
670
+ if (state !== "ok") throw new RowIntegrityError(String(msgId), state);
671
+ return row;
672
+ }
673
+
674
+ /**
675
+ * Check the row MAC of every cached message, or one thread's, or those since a time (`db verify`).
676
+ *
677
+ * @param {{threadId?: string, since?: number, listMax?: number}} [opts]
678
+ * @returns {ReturnType<typeof verifyRows>}
679
+ */
680
+ export function verifyMessageRows(opts = {}) {
681
+ if (!db) throw new Error("Database not initialized");
682
+ return verifyRows(db, [rowMacKeys.current, ...rowMacKeys.retired()], opts);
683
+ }
684
+
685
+ export { RowIntegrityError };
686
+
345
687
  /** Get a bookkeeping value (e.g. "lastConnectedAt"). Returns null if unset. */
346
688
  export function getSyncState(key) {
347
689
  if (!db) throw new Error("Database not initialized");
@@ -426,6 +768,79 @@ export function countSyncGaps() {
426
768
  return { pending: Number(row?.pending) || 0, resolved: Number(row?.resolved) || 0 };
427
769
  }
428
770
 
771
+ /**
772
+ * Record the ranges a restore is about to ask for, as pending. An existing row for the partition is replaced and
773
+ * its attempt count goes up by one.
774
+ *
775
+ * @param {Array<{partition: string, fromTs: number, toTs: number}>} ranges
776
+ */
777
+ export function markSyncRangesPending(ranges) {
778
+ if (!db) throw new Error("Database not initialized");
779
+ const stmt = db.prepare(`
780
+ INSERT INTO sync_ranges (partition, fromTs, toTs, status, reason, attempts, updatedAt)
781
+ VALUES (@partition, @fromTs, @toTs, 'pending', NULL, 1, @now)
782
+ ON CONFLICT(partition) DO UPDATE SET
783
+ fromTs = excluded.fromTs, toTs = excluded.toTs, status = 'pending', reason = NULL,
784
+ attempts = sync_ranges.attempts + 1, updatedAt = excluded.updatedAt
785
+ `);
786
+ const now = Date.now();
787
+ db.transaction(() => {
788
+ for (const r of ranges) stmt.run({ partition: r.partition, fromTs: r.fromTs, toTs: r.toTs, now });
789
+ })();
790
+ }
791
+
792
+ /**
793
+ * Settle one range: done (the window it covers), failed (with why), or back to pending.
794
+ *
795
+ * @param {string} partition
796
+ * @param {"done"|"failed"|"pending"} status
797
+ * @param {{fromTs?: number, toTs?: number, reason?: string|null}} [extra] - for `done`, the window now covered
798
+ */
799
+ export function setSyncRangeStatus(partition, status, { fromTs, toTs, reason = null } = {}) {
800
+ if (!db) throw new Error("Database not initialized");
801
+ db.prepare(
802
+ `INSERT INTO sync_ranges (partition, fromTs, toTs, status, reason, attempts, updatedAt)
803
+ VALUES (@partition, COALESCE(@fromTs, 0), COALESCE(@toTs, 0), @status, @reason, 1, @now)
804
+ ON CONFLICT(partition) DO UPDATE SET
805
+ fromTs = COALESCE(@fromTs, sync_ranges.fromTs), toTs = COALESCE(@toTs, sync_ranges.toTs),
806
+ status = @status, reason = @reason, updatedAt = @now`,
807
+ ).run({ partition, fromTs: fromTs ?? null, toTs: toTs ?? null, status, reason, now: Date.now() });
808
+ }
809
+
810
+ /**
811
+ * The recorded ranges, optionally of one status.
812
+ *
813
+ * @param {"done"|"failed"|"pending"} [status]
814
+ * @returns {Array<{partition: string, fromTs: number, toTs: number, status: string, reason: string|null, attempts: number, updatedAt: number}>}
815
+ */
816
+ export function getSyncRanges(status) {
817
+ if (!db) throw new Error("Database not initialized");
818
+ return status
819
+ ? db.prepare("SELECT * FROM sync_ranges WHERE status = ? ORDER BY partition").all(status)
820
+ : db.prepare("SELECT * FROM sync_ranges ORDER BY partition").all();
821
+ }
822
+
823
+ /** How many ranges are in each state. */
824
+ export function countSyncRanges() {
825
+ if (!db) throw new Error("Database not initialized");
826
+ const row = db
827
+ .prepare(
828
+ "SELECT SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) AS pending, " +
829
+ "SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) AS failed, " +
830
+ "SUM(CASE WHEN status = 'done' THEN 1 ELSE 0 END) AS done FROM sync_ranges",
831
+ )
832
+ .get();
833
+ return { pending: Number(row?.pending) || 0, failed: Number(row?.failed) || 0, done: Number(row?.done) || 0 };
834
+ }
835
+
836
+ /** Forget the given ranges (or every range, with no argument). */
837
+ export function deleteSyncRanges(partitions) {
838
+ if (!db) throw new Error("Database not initialized");
839
+ if (partitions === undefined) return db.prepare("DELETE FROM sync_ranges").run().changes;
840
+ const stmt = db.prepare("DELETE FROM sync_ranges WHERE partition = ?");
841
+ return db.transaction(() => partitions.reduce((n, p) => n + stmt.run(p).changes, 0))();
842
+ }
843
+
429
844
  /**
430
845
  * Run `fn` inside a single SQLite transaction.
431
846
  *
@@ -445,6 +860,10 @@ export function runInTransaction(fn) {
445
860
 
446
861
  export function insertMessage(msg) {
447
862
  if (!db) throw new Error("Database not initialized");
863
+ // Purged by quota or retention: never stored again (the listener, sync and history alike).
864
+ if (belowFloor(msg)) return { changes: 0, belowRetentionFloor: true };
865
+ // Deleted or left: nothing up to the conversation's delete marker comes back.
866
+ if (belowDeleteMarker(msg?.threadId, msg?.timestamp)) return { changes: 0, belowDeleteMarker: true };
448
867
 
449
868
  // A replay may resolve an opaque sender from an older sync. Never let an
450
869
  // unresolved replay replace a canonical live UID, or a different numeric
@@ -456,8 +875,8 @@ export function insertMessage(msg) {
456
875
  excluded.senderId NOT GLOB '*[^0-9]*')
457
876
  )`;
458
877
  const stmt = db.prepare(`
459
- INSERT INTO messages (msgId, threadId, senderId, senderName, text, timestamp, type, raw_data, localPath, has_attachment, msgStatus)
460
- VALUES (@msgId, @threadId, @senderId, @senderName, @text, @timestamp, @type, @raw_data, @localPath, @has_attachment, @msgStatus)
878
+ INSERT INTO messages (msgId, threadId, senderId, senderName, text, text_norm, timestamp, type, raw_data, localPath, has_attachment, msgStatus)
879
+ VALUES (@msgId, @threadId, @senderId, @senderName, @text, @text_norm, @timestamp, @type, @raw_data, @localPath, @has_attachment, @msgStatus)
461
880
  ON CONFLICT(msgId) DO UPDATE SET
462
881
  senderId = CASE WHEN ${canResolveSender} THEN excluded.senderId ELSE messages.senderId END,
463
882
  senderName = CASE
@@ -472,6 +891,7 @@ export function insertMessage(msg) {
472
891
  -- The phone keeps its own tombstone, so a sync arriving after a live
473
892
  -- recall used to overwrite ours with a poorer one.
474
893
  text = CASE WHEN messages.type = 'deleted' THEN messages.text ELSE excluded.text END,
894
+ text_norm = CASE WHEN messages.type = 'deleted' THEN messages.text_norm ELSE excluded.text_norm END,
475
895
  timestamp = excluded.timestamp,
476
896
  type = CASE WHEN messages.type = 'deleted' THEN messages.type ELSE excluded.type END,
477
897
  raw_data = CASE WHEN messages.type = 'deleted' THEN messages.raw_data ELSE excluded.raw_data END,
@@ -540,6 +960,7 @@ export function insertMessage(msg) {
540
960
  senderId: msg.senderId,
541
961
  senderName: msg.senderName,
542
962
  text: msg.text,
963
+ text_norm: foldedText(msg.text),
543
964
  timestamp: msg.timestamp,
544
965
  type: msg.type,
545
966
  raw_data: raw_data,
@@ -552,13 +973,10 @@ export function insertMessage(msg) {
552
973
  /**
553
974
  * Insert a message only if its msgId is not stored yet -- never update one.
554
975
  *
555
- * msg history's write-back (storeHistoryMessage in ./live-store.js). Zalo Web
556
- * writes the history it fetches the same way, ZStorage.setMessage with
557
- * replace:false. A stored row keeps every column, which is the point: the
558
- * listener and later events put things on it that a re-fetch cannot know --
559
- * the media downloader's localPath, a receipt's msgStatus, a recall's
560
- * tombstone, the st/at/cmd a seen receipt echoes back. {@link insertMessage},
561
- * the listener's upsert, would replace most of them.
976
+ * msg history's write-back (storeHistoryMessage in ./live-store.js). A stored
977
+ * row keeps every column, which is the point: the listener and later events put things on it that a re-fetch cannot
978
+ * know -- the media downloader's localPath, a receipt's msgStatus, a recall's tombstone, the st/at/cmd a seen receipt
979
+ * echoes back. {@link insertMessage}, the listener's upsert, would replace most of them.
562
980
  *
563
981
  * Same columns and value mapping as insertMessage.
564
982
  *
@@ -567,10 +985,12 @@ export function insertMessage(msg) {
567
985
  */
568
986
  export function insertMessageIfAbsent(msg) {
569
987
  if (!db) throw new Error("Database not initialized");
988
+ if (belowFloor(msg)) return { changes: 0, belowRetentionFloor: true };
989
+ if (belowDeleteMarker(msg?.threadId, msg?.timestamp)) return { changes: 0, belowDeleteMarker: true };
570
990
 
571
991
  const stmt = db.prepare(`
572
- INSERT INTO messages (msgId, threadId, senderId, senderName, text, timestamp, type, raw_data, localPath, has_attachment, msgStatus)
573
- VALUES (@msgId, @threadId, @senderId, @senderName, @text, @timestamp, @type, @raw_data, @localPath, @has_attachment, @msgStatus)
992
+ INSERT INTO messages (msgId, threadId, senderId, senderName, text, text_norm, timestamp, type, raw_data, localPath, has_attachment, msgStatus)
993
+ VALUES (@msgId, @threadId, @senderId, @senderName, @text, @text_norm, @timestamp, @type, @raw_data, @localPath, @has_attachment, @msgStatus)
574
994
  ON CONFLICT(msgId) DO NOTHING
575
995
  `);
576
996
 
@@ -583,6 +1003,7 @@ export function insertMessageIfAbsent(msg) {
583
1003
  senderId: msg.senderId,
584
1004
  senderName: msg.senderName,
585
1005
  text: msg.text,
1006
+ text_norm: foldedText(msg.text),
586
1007
  timestamp: msg.timestamp,
587
1008
  type: msg.type,
588
1009
  raw_data: raw_data,
@@ -619,9 +1040,8 @@ export function getThreadLeftAt(threadId) {
619
1040
  * The conversation's delete marker: nothing at or before this time may come
620
1041
  * back from fetched history. Null when there is none.
621
1042
  *
622
- * The nearest thing this cache has to Zalo Web's per-conversation delete
623
- * marker. Set with the gone marker by `conv delete` and by our own leave,
624
- * removal or block ({@link markThreadGone}), and kept when the account comes
1043
+ * This cache's per-conversation delete marker. Set with the gone marker by
1044
+ * `conv delete` and by our own leave, removal or block ({@link markThreadGone}), and kept when the account comes
625
1045
  * back -- a deleted DM's old messages stay deleted after the contact writes
626
1046
  * again, while the conversation itself stops being an orphan.
627
1047
  *
@@ -652,6 +1072,70 @@ export function getMessages(threadId, limit = 50, fromTimestamp = null) {
652
1072
  return db.prepare(query).all(...params);
653
1073
  }
654
1074
 
1075
+ /**
1076
+ * A thread's cached messages in a time window, oldest first, one page at a time (bug-reports #5: a date range instead
1077
+ * of paging back 200 at a time to reach one day).
1078
+ *
1079
+ * A page never ends inside a run of messages that share one millisecond, so `nextSince` (the last timestamp + 1) starts
1080
+ * the next page without skipping or repeating any. A page whose every row shares one millisecond takes that whole run,
1081
+ * even past `limit`.
1082
+ *
1083
+ * @param {string} threadId
1084
+ * @param {{since?: number|null, until?: number|null, limit?: number}} [o] - epoch-ms bounds, both inclusive
1085
+ * @returns {{rows: object[], nextSince: number|null}} `nextSince` is null when nothing is left in the window
1086
+ */
1087
+ export function getMessagesInRange(threadId, { since = null, until = null, limit = 200 } = {}) {
1088
+ if (!db) throw new Error("Database not initialized");
1089
+ const where = ["threadId = ?"];
1090
+ const params = [String(threadId)];
1091
+ if (since !== null && since !== undefined) {
1092
+ where.push("timestamp >= ?");
1093
+ params.push(Number(since));
1094
+ }
1095
+ if (until !== null && until !== undefined) {
1096
+ where.push("timestamp <= ?");
1097
+ params.push(Number(until));
1098
+ }
1099
+ const sql = `SELECT * FROM messages WHERE ${where.join(" AND ")} ORDER BY timestamp ASC, msgId ASC`;
1100
+ const rows = db.prepare(`${sql} LIMIT ?`).all(...params, limit + 1);
1101
+ if (rows.length <= limit) return { rows, nextSince: null };
1102
+
1103
+ let page = rows.slice(0, limit);
1104
+ const lastTs = Number(page[page.length - 1].timestamp);
1105
+ if (Number(rows[limit].timestamp) === lastTs) {
1106
+ const before = page.filter((r) => Number(r.timestamp) !== lastTs);
1107
+ page = before.length
1108
+ ? before
1109
+ : db
1110
+ .prepare("SELECT * FROM messages WHERE threadId = ? AND timestamp = ? ORDER BY msgId ASC")
1111
+ .all(String(threadId), lastTs);
1112
+ }
1113
+ const next = Number(page[page.length - 1].timestamp) + 1;
1114
+ const more = until === null || until === undefined || next <= Number(until);
1115
+ return { rows: page, nextSince: more ? next : null };
1116
+ }
1117
+
1118
+ /**
1119
+ * Every cached message of a thread in a time window, oldest first, read in pages of 1000 (`getMessagesInRange`), up
1120
+ * to `cap` messages.
1121
+ *
1122
+ * @param {string} threadId
1123
+ * @param {{since?: number|null, until?: number|null, cap?: number}} [o]
1124
+ * @returns {{rows: object[], hasMore: boolean}} `hasMore`: the cap left messages of the window out
1125
+ */
1126
+ export function getAllMessagesInRange(threadId, { since = null, until = null, cap = Infinity } = {}) {
1127
+ const rows = [];
1128
+ let next = since;
1129
+ for (;;) {
1130
+ const page = getMessagesInRange(threadId, { since: next, until, limit: Math.min(1000, cap - rows.length) });
1131
+ rows.push(...page.rows);
1132
+ if (rows.length >= cap)
1133
+ return { rows: rows.slice(0, cap), hasMore: rows.length > cap || page.nextSince !== null };
1134
+ if (page.nextSince === null) return { rows, hasMore: false };
1135
+ next = page.nextSince;
1136
+ }
1137
+ }
1138
+
655
1139
  /**
656
1140
  * One message by its global id, or null.
657
1141
  *
@@ -667,27 +1151,152 @@ export function getMessageById(msgId) {
667
1151
  }
668
1152
 
669
1153
  /**
670
- * Search cached messages by text substring across one or all conversations, newest first.
1154
+ * Fill in `text_norm` for the rows that have a `text` and no fold yet (rows written before the column existed).
671
1155
  *
672
- * Purely local SQLite query — never touches the Zalo network. Excludes recalled/deleted
673
- * tombstones (`type = 'deleted'`) and escapes SQLite LIKE wildcards (`%`, `_`, `\`) so literal
674
- * characters in `query` match as literals.
1156
+ * One way only: the fold comes from `text` and never from `raw_data`, and a row that already has one is not
1157
+ * touched, so running it again, or beside a live writer, changes nothing it should not. It is derived data, not a
1158
+ * message write: no `text`, `type` or any other column changes.
675
1159
  *
676
- * @param {object} opts
677
- * @param {string} opts.query - Substring to match in message text (case-insensitive for ASCII)
678
- * @param {string} [opts.threadId] - Restrict to one conversation
679
- * @param {string} [opts.senderId] - Restrict to one sender UID
680
- * @param {number} [opts.since] - Only messages at or after this epoch-ms timestamp
681
- * @param {number} [opts.until] - Only messages at or before this epoch-ms timestamp
682
- * @param {number} [opts.limit=50] - Max messages to return
683
- * @returns {Array<object>}
1160
+ * @param {object} [opts]
1161
+ * @param {number} [opts.chunk=5000] - rows per transaction (a live writer waits at most one chunk)
1162
+ * @param {number} [opts.maxRows=Infinity] - stop after this many rows
1163
+ * @param {(done: number) => void} [opts.onProgress]
1164
+ * @returns {{updated: number, remaining: boolean}}
684
1165
  */
685
- export function searchMessages(opts = {}) {
1166
+ export function backfillTextNorm({ chunk = 5000, maxRows = Infinity, onProgress } = {}) {
686
1167
  if (!db) throw new Error("Database not initialized");
687
- const { query, threadId, senderId, since, until, limit = 50 } = opts;
688
- const escaped = String(query ?? "").replace(/[\\%_]/g, "\\$&");
689
- const where = ["COALESCE(type, '') != 'deleted'", "text IS NOT NULL", "text LIKE ? ESCAPE '\\'"];
690
- const params = [`%${escaped}%`];
1168
+ // Lists exactly the rows still to fill, so "any left?" and "the next chunk" cost nothing once most are done.
1169
+ db.exec(
1170
+ "CREATE INDEX IF NOT EXISTS idx_messages_norm_todo ON messages(msgId) WHERE text_norm IS NULL AND text IS NOT NULL",
1171
+ );
1172
+ const pick = db.prepare("SELECT msgId, text FROM messages WHERE text_norm IS NULL AND text IS NOT NULL LIMIT ?");
1173
+ const fill = db.prepare("UPDATE messages SET text_norm = ? WHERE msgId = ? AND text_norm IS NULL");
1174
+ let updated = 0;
1175
+ while (updated < maxRows) {
1176
+ const rows = pick.all(Math.min(chunk, maxRows - updated));
1177
+ if (!rows.length) break;
1178
+ db.transaction(() => {
1179
+ for (const r of rows) fill.run(stripVietnamese(r.text), r.msgId);
1180
+ })();
1181
+ updated += rows.length;
1182
+ onProgress?.(updated);
1183
+ }
1184
+ const remaining = Boolean(
1185
+ db.prepare("SELECT 1 FROM messages WHERE text_norm IS NULL AND text IS NOT NULL LIMIT 1").get(),
1186
+ );
1187
+ return { updated, remaining };
1188
+ }
1189
+
1190
+ /**
1191
+ * Make the search fast, a slice at a time: fold the rows that have no fold, then build a trigram full-text index
1192
+ * (FTS5) of the folded text and a timestamp index. On 421,000 messages this turns a search for a rare word from 6 s into
1193
+ * 3 ms, and the tab counts of a common one from 1.9 s into 0.14 s.
1194
+ *
1195
+ * Built so a live daemon is never stopped by it: every step is a short transaction, the triggers that keep the index
1196
+ * current go in before the existing rows are indexed (so no row falls between), indexing a row twice is harmless
1197
+ * (`INSERT OR REPLACE`), and a run that stops half way (a budget, Ctrl+C, a crash) carries on where it was. Until it is
1198
+ * done a search still answers correctly, by scanning; {@link searchMessageRows} asks for a slice before each search.
1199
+ *
1200
+ * @param {object} [opts]
1201
+ * @param {number} [opts.budgetMs=Infinity] - stop after about this long (0: do nothing)
1202
+ * @param {boolean} [opts.foldOnly=false] - stop once every row has its fold
1203
+ * @param {number} [opts.sliceRows=20000] - rows indexed per transaction
1204
+ * @param {(p: {phase: string, done: number, total: number|null}) => void} [opts.onProgress] - called after each slice
1205
+ * is committed
1206
+ * @returns {{ready: boolean, phase: "ready"|"fold"|"index"}}
1207
+ */
1208
+ export function ensureSearchIndex({ budgetMs = Infinity, sliceRows = 20000, foldOnly = false, onProgress } = {}) {
1209
+ if (!db) throw new Error("Database not initialized");
1210
+ if (searchReady) return { ready: true, phase: "ready" };
1211
+ if (String(getSyncState("searchIndexReady")) === "1") {
1212
+ searchReady = true;
1213
+ return { ready: true, phase: "ready" };
1214
+ }
1215
+ if (budgetMs <= 0) return { ready: false, phase: "fold" };
1216
+ const deadline = Date.now() + budgetMs;
1217
+
1218
+ // 1. Fold what has no fold.
1219
+ let folded = 0;
1220
+ let total = null;
1221
+ for (;;) {
1222
+ const r = backfillTextNorm({
1223
+ maxRows: 5000,
1224
+ onProgress: (d) => onProgress?.({ phase: "fold", done: folded + d, total }),
1225
+ });
1226
+ if (total === null) total = r.updated + (r.remaining ? foldTodoCount() : 0);
1227
+ folded += r.updated;
1228
+ if (!r.remaining) break;
1229
+ if (Date.now() >= deadline) return { ready: false, phase: "fold" };
1230
+ }
1231
+ if (foldOnly) return { ready: false, phase: "index" };
1232
+
1233
+ // 2. The index and the triggers that keep it. Triggers first: a row written from now on is indexed by its own
1234
+ // trigger, and every row written before is at or below the highest rowid read in step 3.
1235
+ db.exec(`
1236
+ CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(text_norm, tokenize='trigram');
1237
+ CREATE TRIGGER IF NOT EXISTS messages_fts_ai AFTER INSERT ON messages WHEN new.text_norm IS NOT NULL BEGIN
1238
+ INSERT INTO messages_fts(rowid, text_norm) VALUES (new.rowid, new.text_norm);
1239
+ END;
1240
+ CREATE TRIGGER IF NOT EXISTS messages_fts_ad AFTER DELETE ON messages BEGIN
1241
+ DELETE FROM messages_fts WHERE rowid = old.rowid;
1242
+ END;
1243
+ CREATE TRIGGER IF NOT EXISTS messages_fts_au AFTER UPDATE OF text_norm ON messages BEGIN
1244
+ DELETE FROM messages_fts WHERE rowid = old.rowid;
1245
+ INSERT INTO messages_fts(rowid, text_norm) SELECT new.rowid, new.text_norm WHERE new.text_norm IS NOT NULL;
1246
+ END;
1247
+ `);
1248
+ if (Date.now() >= deadline) return { ready: false, phase: "index" };
1249
+ // The newest-first order of every search, so a common word is answered by the first rows of this index.
1250
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_ts ON messages(timestamp DESC, msgId DESC)");
1251
+
1252
+ // 3. Index the rows that exist, in slices.
1253
+ const max = db.prepare("SELECT COALESCE(MAX(rowid), 0) AS m FROM messages").get().m;
1254
+ let cursor = Number(getSyncState("searchIndexCursor")) || 0;
1255
+ const slice = db.prepare(
1256
+ "INSERT OR REPLACE INTO messages_fts(rowid, text_norm) SELECT rowid, text_norm FROM messages WHERE rowid > ? AND rowid <= ? AND text_norm IS NOT NULL",
1257
+ );
1258
+ while (cursor < max) {
1259
+ if (Date.now() >= deadline) return { ready: false, phase: "index" };
1260
+ const to = Math.min(max, cursor + sliceRows);
1261
+ db.transaction(() => {
1262
+ slice.run(cursor, to);
1263
+ setSyncState("searchIndexCursor", to);
1264
+ })();
1265
+ cursor = to;
1266
+ onProgress?.({ phase: "index", done: cursor, total: max });
1267
+ }
1268
+ setSyncState("searchIndexReady", "1");
1269
+ searchReady = true;
1270
+ return { ready: true, phase: "ready" };
1271
+ }
1272
+
1273
+ /** How many rows still have a text and no fold. */
1274
+ function foldTodoCount() {
1275
+ return db.prepare("SELECT COUNT(*) AS n FROM messages WHERE text_norm IS NULL AND text IS NOT NULL").get().n;
1276
+ }
1277
+
1278
+ /** The WHERE of a search: what a message must be to be a hit, apart from where the page starts. */
1279
+ function searchWhere({ norm, threadId, senderId, since, until, types }) {
1280
+ const text = String(norm ?? "");
1281
+ const like = `%${text.replace(/[\\%_]/g, "\\$&")}%`;
1282
+ const where = ["COALESCE(type, '') != 'deleted'"];
1283
+ const params = [];
1284
+ if (searchReady) {
1285
+ // The trigram index narrows to the rows holding the keyword (it needs three characters); the LIKE then makes
1286
+ // the match exact, so the index can only ever make a search faster, never change what it finds.
1287
+ if ([...text].length >= 3) {
1288
+ where.push("rowid IN (SELECT rowid FROM messages_fts WHERE messages_fts MATCH ?)");
1289
+ params.push(`"${text.replace(/"/g, '""')}"`);
1290
+ }
1291
+ where.push("text_norm LIKE ? ESCAPE '\\'");
1292
+ params.push(like);
1293
+ } else {
1294
+ // Not indexed yet: scan, and fold on the fly the rows that have no fold, so nothing is missed.
1295
+ where.push(
1296
+ "(text_norm LIKE ? ESCAPE '\\' OR (text_norm IS NULL AND text IS NOT NULL AND vn_strip(text) LIKE ? ESCAPE '\\'))",
1297
+ );
1298
+ params.push(like, like);
1299
+ }
691
1300
  if (threadId) {
692
1301
  where.push("threadId = ?");
693
1302
  params.push(String(threadId));
@@ -704,10 +1313,173 @@ export function searchMessages(opts = {}) {
704
1313
  where.push("timestamp <= ?");
705
1314
  params.push(Number(until));
706
1315
  }
707
- params.push(limit);
708
- return db
709
- .prepare(`SELECT * FROM messages WHERE ${where.join(" AND ")} ORDER BY timestamp DESC LIMIT ?`)
1316
+ if (Array.isArray(types) && types.length) {
1317
+ where.push(`type IN (${types.map(() => "?").join(",")})`);
1318
+ params.push(...types.map(String));
1319
+ }
1320
+ return { where, params };
1321
+ }
1322
+
1323
+ /**
1324
+ * What a search does before it runs: a slice of the index per search until it is complete, so the cost is bounded and
1325
+ * the search is correct whether or not the slice finished. One exception: when many rows still have no fold, finishing
1326
+ * the fold costs about what scanning them with the fold done on the fly would (18 s against 27 s on 421,000 messages),
1327
+ * and only the first search ever meets it, so it is finished first, with progress.
1328
+ */
1329
+ function prepareSearch() {
1330
+ const first = ensureSearchIndex({ budgetMs: searchBudgetMs, onProgress: searchProgress });
1331
+ if (!first.ready && first.phase === "fold" && searchBudgetMs > 0) {
1332
+ ensureSearchIndex({ budgetMs: Infinity, foldOnly: true, onProgress: searchProgress });
1333
+ }
1334
+ }
1335
+
1336
+ /** The statement of one page of a search, and its parameters. */
1337
+ function searchStatement(spec) {
1338
+ prepareSearch();
1339
+ const { where, params } = searchWhere(spec);
1340
+ if (spec.after) {
1341
+ where.push("(timestamp < ? OR (timestamp = ? AND msgId < ?))");
1342
+ params.push(Number(spec.after.timestamp), Number(spec.after.timestamp), String(spec.after.msgId));
1343
+ }
1344
+ params.push(Number.isFinite(spec.limit) ? spec.limit : -1);
1345
+ return {
1346
+ stmt: db.prepare(
1347
+ `SELECT * FROM messages WHERE ${where.join(" AND ")} ORDER BY timestamp DESC, msgId DESC LIMIT ?`,
1348
+ ),
1349
+ params,
1350
+ };
1351
+ }
1352
+
1353
+ /**
1354
+ * The rows of one page of a search, newest first, by the folded text.
1355
+ *
1356
+ * Purely local SQLite: it never touches the Zalo network. Recalled and deleted tombstones are left out. A match is a
1357
+ * substring of `text_norm`; the caller folds the keyword (src/utils/vn-text.js) and decides what an "exact" match
1358
+ * adds. Pages are keyed on `(timestamp, msgId)`, so a new message arriving between two pages cannot shift one.
1359
+ *
1360
+ * @param {object} spec
1361
+ * @param {string} spec.norm - the folded keyword
1362
+ * @param {string} [spec.threadId]
1363
+ * @param {string} [spec.senderId]
1364
+ * @param {number} [spec.since] - epoch ms, inclusive
1365
+ * @param {number} [spec.until] - epoch ms, inclusive
1366
+ * @param {string[]} [spec.types] - message types (`text`, `photo`, `file`, ...)
1367
+ * @param {{timestamp: number, msgId: string}|null} [spec.after] - the last row of the previous page
1368
+ * @param {number} [spec.limit=50]
1369
+ * @returns {Array<object>}
1370
+ */
1371
+ export function searchMessageRows(spec = {}) {
1372
+ if (!db) throw new Error("Database not initialized");
1373
+ const { stmt, params } = searchStatement({ ...spec, limit: Number.isFinite(spec.limit) ? spec.limit : 50 });
1374
+ return stmt.all(...params);
1375
+ }
1376
+
1377
+ /**
1378
+ * The same rows, one at a time and with no limit: for a caller that checks each row itself (the exact-accents mode)
1379
+ * and stops when it has enough, which a fixed-size page cannot do without asking again from the start.
1380
+ *
1381
+ * @param {object} spec - as {@link searchMessageRows}, without `limit`
1382
+ * @returns {IterableIterator<object>}
1383
+ */
1384
+ export function* iterateSearchRows(spec = {}) {
1385
+ if (!db) throw new Error("Database not initialized");
1386
+ const { stmt, params } = searchStatement({ ...spec, limit: undefined });
1387
+ yield* stmt.iterate(...params);
1388
+ }
1389
+
1390
+ /**
1391
+ * How many messages match, by message type: the numbers on a search's tabs. Ignores `types` and `after`, so the tabs
1392
+ * count the whole result whichever one is open.
1393
+ *
1394
+ * @param {object} spec - as {@link searchMessageRows}
1395
+ * @returns {Record<string, number>}
1396
+ */
1397
+ export function countSearchMatchesByType(spec = {}) {
1398
+ if (!db) throw new Error("Database not initialized");
1399
+ prepareSearch();
1400
+ const { where, params } = searchWhere({ ...spec, types: undefined });
1401
+ const rows = db
1402
+ .prepare(
1403
+ `SELECT COALESCE(type, '') AS type, COUNT(*) AS n FROM messages WHERE ${where.join(" AND ")} GROUP BY 1`,
1404
+ )
710
1405
  .all(...params);
1406
+ return Object.fromEntries(rows.map((r) => [r.type, r.n]));
1407
+ }
1408
+
1409
+ /**
1410
+ * The messages around one in its conversation: up to `before` older and `after` newer, oldest first, the message
1411
+ * itself left out. Tombstones are left out too.
1412
+ *
1413
+ * @param {string} threadId
1414
+ * @param {{timestamp: number, msgId: string}} anchor
1415
+ * @param {number} before
1416
+ * @param {number} after
1417
+ * @returns {{before: object[], after: object[]}}
1418
+ */
1419
+ export function getMessagesAround(threadId, anchor, before = 2, after = 2) {
1420
+ if (!db) throw new Error("Database not initialized");
1421
+ const ts = Number(anchor.timestamp);
1422
+ const id = String(anchor.msgId);
1423
+ const older = db
1424
+ .prepare(
1425
+ `SELECT * FROM messages WHERE threadId = ? AND COALESCE(type, '') != 'deleted'
1426
+ AND (timestamp < ? OR (timestamp = ? AND msgId < ?)) ORDER BY timestamp DESC, msgId DESC LIMIT ?`,
1427
+ )
1428
+ .all(String(threadId), ts, ts, id, Math.max(0, before));
1429
+ const newer = db
1430
+ .prepare(
1431
+ `SELECT * FROM messages WHERE threadId = ? AND COALESCE(type, '') != 'deleted'
1432
+ AND (timestamp > ? OR (timestamp = ? AND msgId > ?)) ORDER BY timestamp ASC, msgId ASC LIMIT ?`,
1433
+ )
1434
+ .all(String(threadId), ts, ts, id, Math.max(0, after));
1435
+ return { before: older.reverse(), after: newer };
1436
+ }
1437
+
1438
+ /**
1439
+ * The oldest message in the cache, for one conversation or (with none) for the whole account: how far back a search
1440
+ * can reach.
1441
+ *
1442
+ * @param {string} [threadId]
1443
+ * @returns {number|null} epoch ms
1444
+ */
1445
+ export function getOldestCachedTimestamp(threadId) {
1446
+ if (!db) throw new Error("Database not initialized");
1447
+ if (threadId) {
1448
+ const row = db.prepare("SELECT MIN(timestamp) AS ts FROM messages WHERE threadId = ?").get(String(threadId));
1449
+ return Number.isFinite(row?.ts) ? row.ts : null;
1450
+ }
1451
+ // One index lookup per conversation, instead of a scan of every message.
1452
+ const row = db
1453
+ .prepare(
1454
+ "SELECT MIN(first) AS ts FROM (SELECT (SELECT MIN(timestamp) FROM messages WHERE threadId = t.threadId) AS first FROM threads t)",
1455
+ )
1456
+ .get();
1457
+ return Number.isFinite(row?.ts) ? row.ts : null;
1458
+ }
1459
+
1460
+ /**
1461
+ * Search cached messages by text across one or all conversations, newest first. Accent-insensitive: the keyword and
1462
+ * the text are folded alike (src/utils/vn-text.js), so "duoc" finds "được". Kept for callers that want a plain
1463
+ * array; {@link searchMessageRows} and src/core/search.js give pages, tabs, snippets and the exact mode.
1464
+ *
1465
+ * @param {object} opts
1466
+ * @param {string} opts.query - What to look for (cut to 100 characters)
1467
+ * @param {string} [opts.threadId] - Restrict to one conversation
1468
+ * @param {string} [opts.senderId] - Restrict to one sender UID
1469
+ * @param {number} [opts.since] - Only messages at or after this epoch-ms timestamp
1470
+ * @param {number} [opts.until] - Only messages at or before this epoch-ms timestamp
1471
+ * @param {number} [opts.limit=50] - Max messages to return
1472
+ * @returns {Array<object>}
1473
+ */
1474
+ export function searchMessages(opts = {}) {
1475
+ if (!db) throw new Error("Database not initialized");
1476
+ const { query, threadId, senderId, since, until, limit = 50 } = opts;
1477
+ const norm = stripVietnamese(
1478
+ String(query ?? "")
1479
+ .trim()
1480
+ .slice(0, 100),
1481
+ );
1482
+ return searchMessageRows({ norm, threadId, senderId, since, until, limit });
711
1483
  }
712
1484
 
713
1485
  /**
@@ -718,15 +1490,19 @@ export function searchMessages(opts = {}) {
718
1490
  * groups *among the newest five threads of any kind* — frequently none —
719
1491
  * whereas asking for 5 groups should return the 5 newest groups.
720
1492
  *
721
- * @param {number} [limit=20]
1493
+ * No limit (or a non-positive one) means every thread: nothing returns a
1494
+ * capped list unless the caller asked for a cap.
1495
+ *
1496
+ * @param {number|null} [limit] - max threads; omitted, null or <= 0 = all
722
1497
  * @param {"dm"|"group"|null} [type=null] - null means both
723
1498
  */
724
- export function getRecentThreads(limit = 20, type = null) {
1499
+ export function getRecentThreads(limit = null, type = null) {
725
1500
  if (!db) throw new Error("Database not initialized");
1501
+ const n = Number(limit) > 0 ? Math.floor(Number(limit)) : -1; // SQLite: LIMIT -1 = no limit
726
1502
  if (type) {
727
- return db.prepare("SELECT * FROM threads WHERE type = ? ORDER BY lastUpdate DESC LIMIT ?").all(type, limit);
1503
+ return db.prepare("SELECT * FROM threads WHERE type = ? ORDER BY lastUpdate DESC LIMIT ?").all(type, n);
728
1504
  }
729
- return db.prepare("SELECT * FROM threads ORDER BY lastUpdate DESC LIMIT ?").all(limit);
1505
+ return db.prepare("SELECT * FROM threads ORDER BY lastUpdate DESC LIMIT ?").all(n);
730
1506
  }
731
1507
 
732
1508
  /**
@@ -819,14 +1595,16 @@ export function upsertThread(thread) {
819
1595
  * message's `dName`, `msg history` not at all -- so one conversation's media
820
1596
  * could land in three different folders depending on which command fetched it.
821
1597
  *
822
- * @param {number} [limit=5000]
1598
+ * @param {number|null} [limit] - max threads; omitted = every cached thread
823
1599
  * @returns {Map<string, {name: string, type: string}>}
824
1600
  */
825
- export function getThreadNames(limit = 5000) {
1601
+ export function getThreadNames(limit = null) {
826
1602
  const map = new Map();
827
1603
  try {
828
1604
  for (const t of getRecentThreads(limit)) {
829
- map.set(String(t.threadId), { name: t.name || String(t.threadId), type: t.type });
1605
+ // A 1-1 is titled by the owner's alias as it is now (./contact-names.js); the stored title can predate it.
1606
+ const name = t.type === "dm" ? dmTitle(t.threadId, t.name) : t.name;
1607
+ map.set(String(t.threadId), { name: name || String(t.threadId), type: t.type });
830
1608
  }
831
1609
  } catch {
832
1610
  /* an empty or unopened cache just means folders fall back to thread ids */
@@ -843,6 +1621,7 @@ export function getThreadNames(limit = 5000) {
843
1621
  *
844
1622
  * @param {object} [opts]
845
1623
  * @param {string} [opts.threadId] - restrict to one thread
1624
+ * @param {string[]} [opts.msgIds] - restrict to these messages (one asked for by id, however old)
846
1625
  * @param {number} [opts.since] - only messages at/after this epoch ms
847
1626
  * @param {number} [opts.until] - only messages at/before this epoch ms
848
1627
  * @param {boolean} [opts.onlyMissing=true] - skip rows already downloaded
@@ -851,7 +1630,7 @@ export function getThreadNames(limit = 5000) {
851
1630
  */
852
1631
  export function getAttachmentMessages(opts = {}) {
853
1632
  if (!db) throw new Error("Database not initialized");
854
- const { threadId, since, until, onlyMissing = true, includePruned = false, limit = 500 } = opts;
1633
+ const { threadId, msgIds, since, until, onlyMissing = true, includePruned = false, limit = 500 } = opts;
855
1634
  const where = ["has_attachment = 1"];
856
1635
  const params = [];
857
1636
  if (onlyMissing) where.push("localPath IS NULL");
@@ -859,6 +1638,11 @@ export function getAttachmentMessages(opts = {}) {
859
1638
  // fetches respect it; an explicit re-fetch can opt back in.
860
1639
  if (!includePruned) where.push("mediaPrunedAt IS NULL");
861
1640
  if (threadId) (where.push("threadId = ?"), params.push(String(threadId)));
1641
+ if (Array.isArray(msgIds)) {
1642
+ if (!msgIds.length) return [];
1643
+ where.push(`msgId IN (${msgIds.map(() => "?").join(", ")})`);
1644
+ params.push(...msgIds.map(String));
1645
+ }
862
1646
  if (Number.isFinite(since)) (where.push("timestamp >= ?"), params.push(since));
863
1647
  if (Number.isFinite(until)) (where.push("timestamp <= ?"), params.push(until));
864
1648
  params.push(limit);
@@ -1033,7 +1817,9 @@ export function recordConversationList({ present, clearBefore, markBefore, markK
1033
1817
  return db.transaction(() => {
1034
1818
  const cleared = db
1035
1819
  .prepare(
1036
- "UPDATE threads SET leftAt = NULL WHERE leftAt IS NOT NULL AND leftAt < @clearBefore " +
1820
+ // A listed group is one the account is in now (the list was mapped through the CURRENT group list):
1821
+ // like a join naming us, it ends a group exit too. Events of a gone group never do (./group-exit.js).
1822
+ "UPDATE threads SET leftAt = NULL, goneReason = NULL WHERE leftAt IS NOT NULL AND leftAt < @clearBefore " +
1037
1823
  "AND threadId IN (SELECT value FROM json_each(@present)) RETURNING threadId",
1038
1824
  )
1039
1825
  .all(params)
@@ -1140,6 +1926,202 @@ export function markThreadGone(threadId, at = Date.now()) {
1140
1926
  .run({ at: Number(at), threadId: String(threadId) });
1141
1927
  }
1142
1928
 
1929
+ /** Why a group stopped being ours (threads.goneReason). */
1930
+ export const GONE_REASONS = Object.freeze(["leave", "removed", "blocked", "disbanded"]);
1931
+
1932
+ /**
1933
+ * Record a group exit (./group-exit.js): the gone marker, the delete marker and why. Unlike
1934
+ * {@link markThreadGone}, a group never cached gets a row, so the delete marker holds for a restore that brings
1935
+ * the group's history in later.
1936
+ *
1937
+ * @param {string} threadId
1938
+ * @param {{at?: number, reason: string}} opts - `at`: the exit's time (epoch ms)
1939
+ * @returns {{leftAt: number, deleteMarkerAt: number, reason: string}}
1940
+ */
1941
+ export function markGroupGone(threadId, { at = Date.now(), reason }) {
1942
+ if (!db) throw new Error("Database not initialized");
1943
+ if (!GONE_REASONS.includes(reason)) throw new Error(`not a group exit reason: ${reason}`);
1944
+ const id = String(threadId);
1945
+ const when = Number(at);
1946
+ return db.transaction(() => {
1947
+ db.prepare(
1948
+ "INSERT INTO threads (threadId, type, lastUpdate) VALUES (?, 'group', 0) ON CONFLICT DO NOTHING",
1949
+ ).run(id);
1950
+ db.prepare(
1951
+ "UPDATE threads SET leftAt = @at, goneReason = @reason, " +
1952
+ "deleteMarkerAt = MAX(COALESCE(deleteMarkerAt, 0), @at) WHERE threadId = @id",
1953
+ ).run({ at: when, reason, id });
1954
+ const row = db.prepare("SELECT leftAt, deleteMarkerAt FROM threads WHERE threadId = ?").get(id);
1955
+ return { leftAt: Number(row.leftAt), deleteMarkerAt: Number(row.deleteMarkerAt), reason };
1956
+ })();
1957
+ }
1958
+
1959
+ /**
1960
+ * Raise a conversation's delete marker (never lowers it).
1961
+ *
1962
+ * @param {string} threadId
1963
+ * @param {number} at - epoch ms
1964
+ */
1965
+ export function raiseDeleteMarker(threadId, at) {
1966
+ if (!db) throw new Error("Database not initialized");
1967
+ return db
1968
+ .prepare("UPDATE threads SET deleteMarkerAt = MAX(COALESCE(deleteMarkerAt, 0), ?) WHERE threadId = ?")
1969
+ .run(Number(at), String(threadId));
1970
+ }
1971
+
1972
+ /** A group is gone while leftAt is set and no chat message is newer (the rule {@link getOrphanThreads} reads). */
1973
+ const STILL_GONE =
1974
+ "t.leftAt IS NOT NULL AND t.goneReason IS NOT NULL AND NOT EXISTS (SELECT 1 FROM messages m " +
1975
+ "WHERE m.threadId = t.threadId AND m.timestamp > t.leftAt AND COALESCE(m.type, '') <> 'group_event')";
1976
+
1977
+ /**
1978
+ * A group this account left, was removed or blocked from, or that was disbanded -- or null while it is ours.
1979
+ *
1980
+ * @param {string} threadId
1981
+ * @returns {{threadId: string, leftAt: number, goneReason: string, deleteMarkerAt: number|null, messages: number}|null}
1982
+ */
1983
+ export function getGroupGone(threadId) {
1984
+ if (!db) throw new Error("Database not initialized");
1985
+ const row = db
1986
+ .prepare(
1987
+ `SELECT t.threadId, t.leftAt, t.goneReason, t.deleteMarkerAt,
1988
+ (SELECT COUNT(*) FROM messages m WHERE m.threadId = t.threadId) AS messages
1989
+ FROM threads t WHERE t.threadId = ? AND ${STILL_GONE}`,
1990
+ )
1991
+ .get(String(threadId));
1992
+ if (!row) return null;
1993
+ return {
1994
+ threadId: String(row.threadId),
1995
+ leftAt: Number(row.leftAt),
1996
+ goneReason: row.goneReason,
1997
+ deleteMarkerAt: Number(row.deleteMarkerAt) || null,
1998
+ messages: Number(row.messages) || 0,
1999
+ };
2000
+ }
2001
+
2002
+ /**
2003
+ * Every gone group (see {@link getGroupGone}), with what is still cached of it.
2004
+ *
2005
+ * @returns {Array<{threadId: string, name: string|null, leftAt: number, goneReason: string, deleteMarkerAt: number|null, messages: number}>}
2006
+ */
2007
+ export function listGoneGroups() {
2008
+ if (!db) throw new Error("Database not initialized");
2009
+ return db
2010
+ .prepare(
2011
+ `SELECT t.threadId, t.name, t.leftAt, t.goneReason, t.deleteMarkerAt,
2012
+ (SELECT COUNT(*) FROM messages m WHERE m.threadId = t.threadId) AS messages
2013
+ FROM threads t WHERE ${STILL_GONE}`,
2014
+ )
2015
+ .all()
2016
+ .map((r) => ({
2017
+ threadId: String(r.threadId),
2018
+ name: r.name ?? null,
2019
+ leftAt: Number(r.leftAt),
2020
+ goneReason: r.goneReason,
2021
+ deleteMarkerAt: Number(r.deleteMarkerAt) || null,
2022
+ messages: Number(r.messages) || 0,
2023
+ }));
2024
+ }
2025
+
2026
+ /**
2027
+ * A `join` naming us: the group is ours again. Clears the gone marker and the reason; the delete marker stays, so
2028
+ * what was purged stays purged.
2029
+ *
2030
+ * @param {string} threadId
2031
+ * @returns {{changes: number}}
2032
+ */
2033
+ export function clearGroupGone(threadId) {
2034
+ if (!db) throw new Error("Database not initialized");
2035
+ return db
2036
+ .prepare(
2037
+ "UPDATE threads SET leftAt = NULL, goneReason = NULL WHERE threadId = ? AND " +
2038
+ "(leftAt IS NOT NULL OR goneReason IS NOT NULL)",
2039
+ )
2040
+ .run(String(threadId));
2041
+ }
2042
+
2043
+ /**
2044
+ * Delete one bounded chunk of a conversation's messages (their reactions with them; the row MACs and search entries
2045
+ * go through their triggers), in one transaction. The purge of a gone group calls it until it returns no rows,
2046
+ * handing the event loop back between chunks (./group-exit.js).
2047
+ *
2048
+ * @param {string} threadId
2049
+ * @param {number} [limit=500]
2050
+ * @returns {{rows: number, reactions: number, files: string[], newest: number}} `files`: the media paths the rows
2051
+ * held; `newest`: the latest timestamp deleted (0 when none)
2052
+ */
2053
+ export function purgeThreadMessagesChunk(threadId, limit = 500) {
2054
+ if (!db) throw new Error("Database not initialized");
2055
+ const id = String(threadId);
2056
+ return db.transaction(() => {
2057
+ const rows = db
2058
+ .prepare("SELECT msgId, localPath, timestamp FROM messages WHERE threadId = ? LIMIT ?")
2059
+ .all(id, Math.max(1, Math.floor(limit)));
2060
+ if (!rows.length) return { rows: 0, reactions: 0, files: [], newest: 0 };
2061
+ const ids = JSON.stringify(rows.map((r) => String(r.msgId)));
2062
+ const reactions = db
2063
+ .prepare("DELETE FROM reactions WHERE msgId IN (SELECT value FROM json_each(?))")
2064
+ .run(ids).changes;
2065
+ const deleted = db
2066
+ .prepare("DELETE FROM messages WHERE threadId = ? AND msgId IN (SELECT value FROM json_each(?))")
2067
+ .run(id, ids).changes;
2068
+ return {
2069
+ rows: deleted,
2070
+ reactions,
2071
+ files: rows.map((r) => r.localPath).filter(Boolean),
2072
+ newest: rows.reduce((m, r) => Math.max(m, Number(r.timestamp) || 0), 0),
2073
+ };
2074
+ })();
2075
+ }
2076
+
2077
+ /**
2078
+ * Delete what else a conversation holds besides its messages: reactions, board items (pins, notes, polls),
2079
+ * reminders, the cloud index and the conversation state (pin, unread mark, read watermark). The thread row stays: it
2080
+ * carries the delete marker.
2081
+ *
2082
+ * @param {string} threadId
2083
+ * @returns {{reactions: number, boardItems: number, reminders: number, cloudItems: number, convState: number, files: string[]}}
2084
+ * `files`: the cloud index's local copies, for the caller to delete when nothing else holds them
2085
+ */
2086
+ export function purgeThreadSideRows(threadId) {
2087
+ if (!db) throw new Error("Database not initialized");
2088
+ const id = String(threadId);
2089
+ return db.transaction(() => {
2090
+ const files = db
2091
+ .prepare("SELECT localPath FROM cloud_items WHERE threadId = ? AND localPath IS NOT NULL")
2092
+ .all(id)
2093
+ .map((r) => r.localPath);
2094
+ const run = (sql) => db.prepare(sql).run(id).changes;
2095
+ return {
2096
+ reactions: run("DELETE FROM reactions WHERE threadId = ?"),
2097
+ boardItems: run("DELETE FROM board_items WHERE threadId = ?"),
2098
+ reminders: run("DELETE FROM reminders WHERE threadId = ?"),
2099
+ cloudItems: run("DELETE FROM cloud_items WHERE threadId = ?"),
2100
+ convState: run("DELETE FROM conv_state WHERE threadId = ?"),
2101
+ files,
2102
+ };
2103
+ })();
2104
+ }
2105
+
2106
+ /**
2107
+ * The media paths of `files` that a cached row still points at (a message or a cloud item of another conversation).
2108
+ *
2109
+ * @param {string[]} files
2110
+ * @returns {Set<string>}
2111
+ */
2112
+ export function referencedMediaPaths(files) {
2113
+ if (!db) throw new Error("Database not initialized");
2114
+ if (!files.length) return new Set();
2115
+ const list = JSON.stringify([...new Set(files.map(String))]);
2116
+ const rows = db
2117
+ .prepare(
2118
+ "SELECT localPath FROM messages WHERE localPath IS NOT NULL AND localPath IN (SELECT value FROM json_each(?)) " +
2119
+ "UNION SELECT localPath FROM cloud_items WHERE localPath IN (SELECT value FROM json_each(?))",
2120
+ )
2121
+ .all(list, list);
2122
+ return new Set(rows.map((r) => String(r.localPath)));
2123
+ }
2124
+
1143
2125
  /**
1144
2126
  * Record that the account was seen in a conversation: clear its gone marker,
1145
2127
  * if that marker predates the sighting.
@@ -1159,7 +2141,9 @@ export function markThreadBack(threadId, seenAt) {
1159
2141
  const at = Number(seenAt);
1160
2142
  if (!Number.isFinite(at)) return { changes: 0 };
1161
2143
  return db
1162
- .prepare("UPDATE threads SET leftAt = NULL WHERE threadId = ? AND leftAt IS NOT NULL AND leftAt < ?")
2144
+ .prepare(
2145
+ "UPDATE threads SET leftAt = NULL, goneReason = NULL WHERE threadId = ? AND leftAt IS NOT NULL AND leftAt < ?",
2146
+ )
1163
2147
  .run(String(threadId), at);
1164
2148
  }
1165
2149
 
@@ -1306,6 +2290,27 @@ export function upsertReminder(r) {
1306
2290
  });
1307
2291
  }
1308
2292
 
2293
+ /**
2294
+ * Remove one reminder another device deleted (the `remove_reminder11` control), from whichever of the given
2295
+ * conversations holds it. A DM reminder is stored under the other person's id, and the control names both ends.
2296
+ *
2297
+ * @param {string} reminderId
2298
+ * @param {string[]} threadIds - the conversations it may be stored under
2299
+ * @returns {{removed: number, threadIds: string[]}} the conversations a row was removed from
2300
+ */
2301
+ export function removeReminder(reminderId, threadIds) {
2302
+ if (!db) throw new Error("Database not initialized");
2303
+ const ids = [...new Set((threadIds || []).filter((t) => t !== undefined && t !== null && t !== "").map(String))];
2304
+ if (!ids.length || reminderId === undefined || reminderId === null) return { removed: 0, threadIds: [] };
2305
+ const where = `reminderId = ? AND threadId IN (${ids.map(() => "?").join(", ")})`;
2306
+ const hit = db
2307
+ .prepare(`SELECT DISTINCT threadId FROM reminders WHERE ${where}`)
2308
+ .all(String(reminderId), ...ids)
2309
+ .map((r) => r.threadId);
2310
+ const removed = db.prepare(`DELETE FROM reminders WHERE ${where}`).run(String(reminderId), ...ids).changes;
2311
+ return { removed, threadIds: hit };
2312
+ }
2313
+
1309
2314
  /** Reminders for a thread, or all of them, soonest start first. */
1310
2315
  export function getReminders(threadId = null) {
1311
2316
  if (!db) throw new Error("Database not initialized");
@@ -1320,13 +2325,15 @@ export function getReminders(threadId = null) {
1320
2325
  */
1321
2326
  export function upsertCloudItem(item) {
1322
2327
  if (!db) throw new Error("Database not initialized");
2328
+ // A cloud pull respects the delete marker as the message writers do.
2329
+ if (belowDeleteMarker(item?.threadId, item?.timestamp)) return { changes: 0, belowDeleteMarker: true };
1323
2330
  return db
1324
2331
  .prepare(
1325
2332
  `INSERT INTO cloud_items
1326
2333
  (noiseId, threadId, msgId, msgType, mediaType, cloudUrl, encryptKey, checksum,
1327
- mediaSize, timestamp, localPath, raw_data, sync_timestamp)
2334
+ mediaSize, timestamp, localPath, raw_data, sync_timestamp, zKey, seenAt, keyVersion, algoVersion)
1328
2335
  VALUES (@noiseId, @threadId, @msgId, @msgType, @mediaType, @cloudUrl, @encryptKey, @checksum,
1329
- @mediaSize, @timestamp, @localPath, @raw_data, @sync_timestamp)
2336
+ @mediaSize, @timestamp, @localPath, @raw_data, @sync_timestamp, @zKey, @seenAt, @keyVersion, @algoVersion)
1330
2337
  ON CONFLICT(noiseId) DO UPDATE SET
1331
2338
  threadId = COALESCE(excluded.threadId, cloud_items.threadId),
1332
2339
  msgId = COALESCE(excluded.msgId, cloud_items.msgId),
@@ -1336,7 +2343,11 @@ export function upsertCloudItem(item) {
1336
2343
  mediaSize = COALESCE(excluded.mediaSize, cloud_items.mediaSize),
1337
2344
  localPath = COALESCE(excluded.localPath, cloud_items.localPath),
1338
2345
  raw_data = excluded.raw_data,
1339
- sync_timestamp = excluded.sync_timestamp`,
2346
+ sync_timestamp = excluded.sync_timestamp,
2347
+ zKey = COALESCE(excluded.zKey, cloud_items.zKey),
2348
+ seenAt = COALESCE(excluded.seenAt, cloud_items.seenAt),
2349
+ keyVersion = COALESCE(excluded.keyVersion, cloud_items.keyVersion),
2350
+ algoVersion = COALESCE(excluded.algoVersion, cloud_items.algoVersion)`,
1340
2351
  )
1341
2352
  .run({
1342
2353
  noiseId: String(item.noiseId),
@@ -1352,9 +2363,96 @@ export function upsertCloudItem(item) {
1352
2363
  localPath: item.localPath ?? null,
1353
2364
  raw_data: typeof item.raw_data === "object" ? JSON.stringify(item.raw_data) : (item.raw_data ?? null),
1354
2365
  sync_timestamp: item.sync_timestamp || Date.now(),
2366
+ zKey: item.zKey || null,
2367
+ seenAt: Number(item.seenAt) || null,
2368
+ keyVersion: item.keyVersion === undefined || item.keyVersion === null ? null : Number(item.keyVersion) || 0,
2369
+ algoVersion:
2370
+ item.algoVersion === undefined || item.algoVersion === null ? null : Number(item.algoVersion) || 0,
1355
2371
  });
1356
2372
  }
1357
2373
 
2374
+ /**
2375
+ * Remove the cloud items a queue `remove` entry names, by zKey. Returns how many rows went.
2376
+ *
2377
+ * @param {string[]} zKeys
2378
+ */
2379
+ export function removeCloudItemsByZKey(zKeys) {
2380
+ if (!db) throw new Error("Database not initialized");
2381
+ const del = db.prepare("DELETE FROM cloud_items WHERE zKey = ?");
2382
+ let n = 0;
2383
+ db.transaction(() => {
2384
+ for (const k of zKeys) if (k) n += del.run(String(k)).changes;
2385
+ })();
2386
+ return n;
2387
+ }
2388
+
2389
+ /**
2390
+ * Remove a conversation's cloud items older than `beforeTs` (a queue `del_thread` entry: the conversation was
2391
+ * cleared at that moment). Returns how many rows went.
2392
+ *
2393
+ * @param {string} threadId
2394
+ * @param {number} beforeTs - epoch ms; items with a smaller timestamp go
2395
+ */
2396
+ export function removeCloudItemsBefore(threadId, beforeTs) {
2397
+ if (!db) throw new Error("Database not initialized");
2398
+ return db
2399
+ .prepare("DELETE FROM cloud_items WHERE threadId = ? AND timestamp < ?")
2400
+ .run(String(threadId), Number(beforeTs) || 0).changes;
2401
+ }
2402
+
2403
+ /**
2404
+ * Remove every cloud item except the ones of the given conversations (a queue `reset_cloud` entry: the cloud was
2405
+ * emptied, and the self chat is the one conversation that survives it).
2406
+ *
2407
+ * @param {string[]} keepThreadIds
2408
+ */
2409
+ export function removeCloudItemsExcept(keepThreadIds) {
2410
+ if (!db) throw new Error("Database not initialized");
2411
+ const keep = [...new Set(keepThreadIds.filter(Boolean).map(String))];
2412
+ const marks = keep.map(() => "?").join(",");
2413
+ // SQLite reads an empty `NOT IN ()` as true, so an empty list empties the table.
2414
+ return db.prepare(`DELETE FROM cloud_items WHERE threadId IS NULL OR threadId NOT IN (${marks})`).run(...keep)
2415
+ .changes;
2416
+ }
2417
+
2418
+ /**
2419
+ * After a full walk: drop the items no page of that walk listed (`seenAt` older than the walk's start, or never
2420
+ * set). Only call it after a walk that the server said was complete.
2421
+ *
2422
+ * @param {number} walkStartedAt
2423
+ */
2424
+ export function sweepCloudItemsNotSeenSince(walkStartedAt) {
2425
+ if (!db) throw new Error("Database not initialized");
2426
+ return db.prepare("DELETE FROM cloud_items WHERE seenAt IS NULL OR seenAt < ?").run(Number(walkStartedAt)).changes;
2427
+ }
2428
+
2429
+ /**
2430
+ * Give the rows written before `zKey` existed their key: `compute(row)` is handed each such row and returns the key
2431
+ * (or null to leave it). Returns how many rows were filled.
2432
+ *
2433
+ * @param {(row: object) => string|null} compute
2434
+ */
2435
+ export function backfillCloudZKeys(compute) {
2436
+ if (!db) throw new Error("Database not initialized");
2437
+ const rows = db.prepare("SELECT noiseId, raw_data, threadId FROM cloud_items WHERE zKey IS NULL").all();
2438
+ const set = db.prepare("UPDATE cloud_items SET zKey = ? WHERE noiseId = ?");
2439
+ let n = 0;
2440
+ db.transaction(() => {
2441
+ for (const row of rows) {
2442
+ let parsed = null;
2443
+ try {
2444
+ parsed = JSON.parse(row.raw_data);
2445
+ } catch {}
2446
+ const key = parsed ? compute(parsed) : null;
2447
+ if (key) {
2448
+ set.run(key, row.noiseId);
2449
+ n++;
2450
+ }
2451
+ }
2452
+ })();
2453
+ return n;
2454
+ }
2455
+
1358
2456
  /** zCloud items, newest first; optionally one thread's. */
1359
2457
  export function getCloudItems(threadId = null, limit = 500) {
1360
2458
  if (!db) throw new Error("Database not initialized");
@@ -1365,12 +2463,29 @@ export function getCloudItems(threadId = null, limit = 500) {
1365
2463
  : db.prepare("SELECT * FROM cloud_items ORDER BY timestamp DESC LIMIT ?").all(limit);
1366
2464
  }
1367
2465
 
2466
+ /** What the local zCloud index holds: how many items, and the bytes of their media. */
2467
+ export function summarizeCloudItems() {
2468
+ if (!db) throw new Error("Database not initialized");
2469
+ const r = db.prepare("SELECT COUNT(*) AS items, COALESCE(SUM(mediaSize), 0) AS bytes FROM cloud_items").get();
2470
+ return { items: Number(r.items), bytes: Number(r.bytes) };
2471
+ }
2472
+
1368
2473
  /** The zCloud backup for one message, if the cloud queue has told us about it. */
1369
2474
  export function getCloudItemByMsgId(msgId) {
1370
2475
  if (!db) throw new Error("Database not initialized");
1371
2476
  return db.prepare("SELECT * FROM cloud_items WHERE msgId = ? LIMIT 1").get(String(msgId)) || null;
1372
2477
  }
1373
2478
 
2479
+ /**
2480
+ * The zCloud backup for one message by the key Zalo joins on (`cliMsgId_conversation_sender`, see
2481
+ * `cloudKeyOf` in sync-v2/zcloud.js). The queue's global message id is the literal "0" for most entries, so this is
2482
+ * the lookup that finds them.
2483
+ */
2484
+ export function getCloudItemByZKey(zKey) {
2485
+ if (!db) throw new Error("Database not initialized");
2486
+ return db.prepare("SELECT * FROM cloud_items WHERE zKey = ? LIMIT 1").get(String(zKey)) || null;
2487
+ }
2488
+
1374
2489
  /**
1375
2490
  * Advance a message's delivery state.
1376
2491
  *
@@ -1508,6 +2623,7 @@ export function markMessageRecalled(msgId, at = Date.now(), opts = {}) {
1508
2623
  `UPDATE messages SET
1509
2624
  type = 'deleted',
1510
2625
  text = '[deleted]',
2626
+ text_norm = '[deleted]',
1511
2627
  raw_data = @raw,
1512
2628
  -- The media goes with the message. Leaving has_attachment set would
1513
2629
  -- queue the attachment of a just-withdrawn message for download;
@@ -1539,28 +2655,26 @@ export function markMessageRecalled(msgId, at = Date.now(), opts = {}) {
1539
2655
  export function findMessageByClientId(cliMsgId, threadId = null) {
1540
2656
  if (!db) throw new Error("Database not initialized");
1541
2657
  if (cliMsgId === undefined || cliMsgId === null || cliMsgId === "") return null;
1542
- if (threadId !== undefined && threadId !== null && threadId !== "") {
1543
- return (
1544
- db
1545
- .prepare(
1546
- `SELECT * FROM messages
1547
- WHERE threadId = ? AND json_valid(raw_data) AND json_extract(raw_data, '$.cliMsgId') = ?
1548
- ORDER BY timestamp DESC LIMIT 1`,
1549
- )
1550
- .get(String(threadId), String(cliMsgId)) || null
1551
- );
1552
- }
1553
- return (
1554
- db
1555
- .prepare(
1556
- `SELECT * FROM messages
1557
- WHERE json_valid(raw_data) AND json_extract(raw_data, '$.cliMsgId') = ?
1558
- ORDER BY timestamp DESC LIMIT 1`,
1559
- )
1560
- .get(String(cliMsgId)) || null
2658
+ const scoped = threadId !== undefined && threadId !== null && threadId !== "";
2659
+ // Every match, newest first, sorted here: an ORDER BY in the query made SQLite walk the thread's timestamp
2660
+ // index instead of the client-id one, which is the whole cost this lookup used to have.
2661
+ const statements = cliLookups.get(db) ?? cliLookups.set(db, {}).get(db);
2662
+ const key = scoped ? "scoped" : "any";
2663
+ statements[key] ??= db.prepare(
2664
+ scoped
2665
+ ? `SELECT * FROM messages WHERE (${CLIENT_ID_EXPR}) = ? AND threadId = ?`
2666
+ : `SELECT * FROM messages WHERE (${CLIENT_ID_EXPR}) = ?`,
1561
2667
  );
2668
+ const rows = scoped
2669
+ ? statements[key].all(String(cliMsgId), String(threadId))
2670
+ : statements[key].all(String(cliMsgId));
2671
+ if (!rows.length) return null;
2672
+ return rows.reduce((newest, row) => (Number(row.timestamp) > Number(newest.timestamp) ? row : newest));
1562
2673
  }
1563
2674
 
2675
+ /** Prepared client-id lookups, one set per open database (a new initDb makes a new connection). */
2676
+ const cliLookups = new WeakMap();
2677
+
1564
2678
  /** Pinned / unread-marked state for a conversation. Applies to DMs too. */
1565
2679
  export function upsertConvState(st) {
1566
2680
  if (!db) throw new Error("Database not initialized");
@@ -1585,6 +2699,106 @@ export function upsertConvState(st) {
1585
2699
  });
1586
2700
  }
1587
2701
 
2702
+ /**
2703
+ * Move one of a conversation's reaction marks forward: `reactUnreadId` (the newest reaction someone else made) or
2704
+ * `reactSeenId` (the newest reported seen). Like the read watermark, it only moves forward; ids are compared as
2705
+ * integers.
2706
+ *
2707
+ * @param {{threadId: string, column: "reactUnreadId"|"reactSeenId", msgId: string}} mark
2708
+ * @returns {boolean} whether it moved
2709
+ */
2710
+ export function recordReactionMark({ threadId, column, msgId }) {
2711
+ if (!db) throw new Error("Database not initialized");
2712
+ if (column !== "reactUnreadId" && column !== "reactSeenId") throw new Error(`Unknown reaction mark ${column}`);
2713
+ const id = String(msgId ?? "");
2714
+ if (!/^\d+$/.test(id) || BigInt(id) === 0n) return false;
2715
+ const now = Date.now();
2716
+ return db.transaction(() => {
2717
+ const cur = db.prepare(`SELECT ${column} AS v FROM conv_state WHERE threadId = ?`).get(String(threadId));
2718
+ if (/^\d+$/.test(cur?.v ?? "") && BigInt(cur.v) >= BigInt(id)) return false;
2719
+ db.prepare(
2720
+ `INSERT INTO conv_state (threadId, ${column}, updatedAt) VALUES (?, ?, ?)
2721
+ ON CONFLICT(threadId) DO UPDATE SET ${column} = excluded.${column}, updatedAt = excluded.updatedAt`,
2722
+ ).run(String(threadId), id, now);
2723
+ return true;
2724
+ })();
2725
+ }
2726
+
2727
+ /**
2728
+ * Store when a user was last online, keeping the newer of what is stored and what is given.
2729
+ *
2730
+ * @param {{userId: string, lastOnline: number, source?: string}} row - `lastOnline` in epoch ms
2731
+ * @returns {boolean} whether it changed
2732
+ */
2733
+ export function upsertLastOnline({ userId, lastOnline, source = "listen" }) {
2734
+ if (!db) throw new Error("Database not initialized");
2735
+ const t = Number(lastOnline);
2736
+ if (!userId || !Number.isFinite(t) || t <= 0) return false;
2737
+ const res = db
2738
+ .prepare(
2739
+ `INSERT INTO last_online (userId, lastOnline, updatedAt, source) VALUES (?, ?, ?, ?)
2740
+ ON CONFLICT(userId) DO UPDATE SET lastOnline = excluded.lastOnline, updatedAt = excluded.updatedAt,
2741
+ source = excluded.source
2742
+ WHERE excluded.lastOnline > COALESCE(last_online.lastOnline, 0)`,
2743
+ )
2744
+ .run(String(userId), t, Date.now(), String(source));
2745
+ return res.changes > 0;
2746
+ }
2747
+
2748
+ /**
2749
+ * When a user was last online, as stored, or null.
2750
+ *
2751
+ * @param {string} userId
2752
+ * @returns {{userId: string, lastOnline: number, updatedAt: number, source: string}|null}
2753
+ */
2754
+ export function getLastOnline(userId) {
2755
+ if (!db) throw new Error("Database not initialized");
2756
+ return db.prepare("SELECT * FROM last_online WHERE userId = ?").get(String(userId)) || null;
2757
+ }
2758
+
2759
+ /**
2760
+ * Replace the stored alias snapshot with a complete one (a missing user means the owner removed that alias).
2761
+ *
2762
+ * @param {Map<string, string>} aliases - userId -> the owner's alias
2763
+ * @returns {boolean} whether the stored snapshot changed
2764
+ */
2765
+ export function replaceUserAliases(aliases) {
2766
+ if (!db) throw new Error("Database not initialized");
2767
+ const now = Date.now();
2768
+ const current = getUserAliases();
2769
+ let changed = current.size !== aliases.size;
2770
+ if (!changed) for (const [id, alias] of aliases) if (current.get(id) !== alias) changed = true;
2771
+ if (!changed) return false;
2772
+ const insert = db.prepare("INSERT INTO user_aliases (userId, alias, updatedAt) VALUES (?, ?, ?)");
2773
+ db.transaction(() => {
2774
+ db.prepare("DELETE FROM user_aliases").run();
2775
+ for (const [id, alias] of aliases) insert.run(String(id), String(alias), now);
2776
+ })();
2777
+ return true;
2778
+ }
2779
+
2780
+ /**
2781
+ * The stored alias snapshot. Small (one row per alias the owner set), read once per process and kept in memory.
2782
+ *
2783
+ * @returns {Map<string, string>} userId -> the owner's alias
2784
+ */
2785
+ export function getUserAliases() {
2786
+ if (!db) throw new Error("Database not initialized");
2787
+ const map = new Map();
2788
+ for (const r of db.prepare("SELECT userId, alias FROM user_aliases").all()) map.set(String(r.userId), r.alias);
2789
+ return map;
2790
+ }
2791
+
2792
+ /** Whether a database is open in this process (for display code that also runs before one is). */
2793
+ export function isDbOpen() {
2794
+ return Boolean(db?.open);
2795
+ }
2796
+
2797
+ /** A number that changes whenever a database is opened or closed (per-account caches key on it). */
2798
+ export function getDbGeneration() {
2799
+ return dbGeneration;
2800
+ }
2801
+
1588
2802
  /** Conversation state for one thread, or every thread that has any. */
1589
2803
  export function getConvState(threadId = null) {
1590
2804
  if (!db) throw new Error("Database not initialized");
@@ -1635,7 +2849,7 @@ export function recordReadWatermark({ threadId, msgId, ts }) {
1635
2849
  * `unreadAfter` counts cached messages only -- ids after the watermark that
1636
2850
  * someone other than this account sent, not recalled or deleted -- so it is a
1637
2851
  * floor, and null when no watermark is known yet ("never told", not "all
1638
- * read"). Own messages are told apart as everywhere else: zca-js rewrites an
2852
+ * read"). Own messages are told apart as everywhere else: the listener rewrites an
1639
2853
  * own message's raw sender "0" to this account's uid before it is stored.
1640
2854
  *
1641
2855
  * @param {string[]} threadIds
@@ -1669,6 +2883,22 @@ export function getReadStates(threadIds, ownId) {
1669
2883
  return out;
1670
2884
  }
1671
2885
 
2886
+ /**
2887
+ * Set only the name of a contact, creating the row when it is new and keeping its phone when it exists.
2888
+ * `upsertContact` replaces the phone too, which a caller that knows only the name must not do.
2889
+ *
2890
+ * @param {string|number} userId
2891
+ * @param {string} name
2892
+ */
2893
+ export function setContactName(userId, name) {
2894
+ if (!db) throw new Error("Database not initialized");
2895
+ if (userId === undefined || userId === null || userId === "" || !name) return;
2896
+ db.prepare(
2897
+ `INSERT INTO contacts (userId, name, phone) VALUES (?, ?, NULL)
2898
+ ON CONFLICT(userId) DO UPDATE SET name = excluded.name`,
2899
+ ).run(String(userId), String(name));
2900
+ }
2901
+
1672
2902
  export function upsertContact(contact) {
1673
2903
  if (!db) throw new Error("Database not initialized");
1674
2904
 
@@ -1690,8 +2920,8 @@ export function upsertContact(contact) {
1690
2920
  /**
1691
2921
  * The display name this account has seen for a user id, or null.
1692
2922
  *
1693
- * Used to turn a `@[uid]` mention token into "@Display Name". Two sources,
1694
- * in order:
2923
+ * Used to turn a `@[uid]` mention token into "@Display Name". The owner's
2924
+ * alias for the user wins; then two sources, in order:
1695
2925
  *
1696
2926
  * 1. `contacts` — authoritative, and the only source that can name someone
1697
2927
  * who has never posted. `msg send` fills it in: any uid it has to look
@@ -1711,7 +2941,21 @@ export function getDisplayName(userId) {
1711
2941
  if (!db) throw new Error("Database not initialized");
1712
2942
  if (userId === undefined || userId === null || userId === "") return null;
1713
2943
  const id = String(userId);
2944
+ // The owner's alias first, as Zalo shows the person everywhere (./contact-names.js).
2945
+ return aliasFor(id) ?? getStoredName(id);
2946
+ }
1714
2947
 
2948
+ /**
2949
+ * The name this cache holds for a user without the owner's alias: `contacts`, else the newest `senderName` (the name
2950
+ * a message carried). Null when the uid has never been seen.
2951
+ *
2952
+ * @param {string|number} userId
2953
+ * @returns {string|null}
2954
+ */
2955
+ export function getStoredName(userId) {
2956
+ if (!db) throw new Error("Database not initialized");
2957
+ if (userId === undefined || userId === null || userId === "") return null;
2958
+ const id = String(userId);
1715
2959
  const contact = db.prepare("SELECT name FROM contacts WHERE userId = ?").get(id);
1716
2960
  if (contact?.name) return contact.name;
1717
2961