@ardennguyen/zalo-agent-cli 2.5.8 → 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.
- package/.env.example +23 -2
- package/DISCLAIMER.md +3 -3
- package/LICENSE +2 -3
- package/NOTICE +14 -34
- package/README.md +166 -72
- package/package.json +37 -19
- package/src/commands/account.js +369 -40
- package/src/commands/auto-reply.js +8 -25
- package/src/commands/bank.js +25 -6
- package/src/commands/catalog.js +54 -11
- package/src/commands/cloud.js +459 -0
- package/src/commands/conv.js +470 -287
- package/src/commands/db.js +442 -0
- package/src/commands/fleet.js +449 -41
- package/src/commands/friend.js +198 -45
- package/src/commands/group.js +256 -43
- package/src/commands/label.js +16 -2
- package/src/commands/listen.js +495 -122
- package/src/commands/login.js +313 -117
- package/src/commands/mcp-approver.js +103 -0
- package/src/commands/mcp-webhook.js +13 -5
- package/src/commands/mcp.js +800 -104
- package/src/commands/msg-media.js +187 -0
- package/src/commands/msg-search.js +219 -0
- package/src/commands/msg.js +414 -110
- package/src/commands/oa/calls.js +134 -0
- package/src/commands/oa/content.js +266 -0
- package/src/commands/oa/gmf.js +429 -0
- package/src/commands/oa/messages.js +355 -0
- package/src/commands/oa/users.js +502 -0
- package/src/commands/oa-init.js +122 -123
- package/src/commands/oa-listen.js +374 -150
- package/src/commands/oa.js +83 -598
- package/src/commands/policy.js +224 -0
- package/src/commands/poll.js +3 -0
- package/src/commands/presence.js +175 -0
- package/src/commands/profile.js +45 -94
- package/src/commands/quick-msg.js +26 -0
- package/src/commands/read.js +172 -0
- package/src/commands/reminder.js +34 -4
- package/src/commands/social.js +223 -0
- package/src/commands/sync.js +482 -158
- package/src/commands/write.js +85 -0
- package/src/commands/zbs.js +502 -0
- package/src/core/account-devices.js +76 -0
- package/src/core/account-state.js +167 -0
- package/src/core/account-status.js +355 -0
- package/src/core/accounts.js +11 -4
- package/src/core/admin-api.js +392 -0
- package/src/core/approval.js +271 -0
- package/src/core/auto-reply.js +27 -0
- package/src/core/bank-accounts.js +1 -1
- package/src/core/block-sharing.js +43 -0
- package/src/core/board-pass.js +94 -0
- package/src/core/cached-message.js +78 -8
- package/src/core/cloud-plan.js +285 -0
- package/src/core/cloud-verify.js +305 -0
- package/src/core/confirm-guard.js +808 -0
- package/src/core/contact-names.js +504 -0
- package/src/core/control-events.js +525 -0
- package/src/core/control-replay.js +106 -0
- package/src/core/conversation-actions.js +214 -0
- package/src/core/credentials.js +112 -11
- package/src/core/current-user-names.js +60 -26
- package/src/core/daemon-channel.js +296 -15
- package/src/core/daemon-health.js +110 -7
- package/src/core/daemon-presence.js +455 -0
- package/src/core/daemon-sync.js +58 -18
- package/src/core/data-export.js +610 -0
- package/src/core/db-tools.js +473 -0
- package/src/core/db.js +1327 -83
- package/src/core/deploy-policy.js +560 -0
- package/src/core/device-since.js +123 -0
- package/src/core/e2ee-notice.js +41 -0
- package/src/core/exit-codes.js +7 -0
- package/src/core/export-crypt.js +290 -0
- package/src/core/fleet-controller.js +340 -0
- package/src/core/fleet-purge.js +144 -0
- package/src/core/fleet-qr.js +273 -0
- package/src/core/fleet-serve.js +292 -0
- package/src/core/fleet-supervisor.js +176 -0
- package/src/core/fleet-templates.js +568 -39
- package/src/core/fleet.js +232 -20
- package/src/core/friend-requests.js +80 -16
- package/src/core/friend-search.js +1 -1
- package/src/core/group-admin.js +2 -29
- package/src/core/group-departure.js +233 -0
- package/src/core/group-exit.js +621 -0
- package/src/core/group-members.js +21 -9
- package/src/core/group-settings.js +5 -207
- package/src/core/hidden-chat-actions.js +96 -0
- package/src/core/hidden-chats.js +425 -0
- package/src/core/history-fetch.js +81 -27
- package/src/core/keystore/config.js +163 -0
- package/src/core/keystore/container.js +208 -0
- package/src/core/keystore/index.js +483 -0
- package/src/core/keystore/keyring.js +588 -0
- package/src/core/keystore/kms.js +157 -0
- package/src/core/keystore/media-seal.js +711 -0
- package/src/core/keystore/providers.js +492 -0
- package/src/core/keystore/stores.js +177 -0
- package/src/core/keystore/worker.js +80 -0
- package/src/core/kick-marker.js +61 -0
- package/src/core/last-online.js +236 -0
- package/src/core/list-all.js +280 -0
- package/src/core/listener-lifecycle.js +101 -10
- package/src/core/live-api.js +1 -1
- package/src/core/live-store.js +111 -53
- package/src/core/local-reads.js +16 -0
- package/src/core/logout.js +102 -140
- package/src/core/media-deliver.js +732 -0
- package/src/core/media-route.js +347 -0
- package/src/core/media-store.js +408 -0
- package/src/core/mutual-groups.js +94 -0
- package/src/core/name-refresh.js +135 -0
- package/src/core/oa/calls.js +212 -0
- package/src/core/oa/content.js +390 -0
- package/src/core/oa/gmf.js +537 -0
- package/src/core/oa/messages.js +470 -0
- package/src/core/oa/oauth.js +422 -0
- package/src/core/oa/transport.js +645 -0
- package/src/core/oa/users.js +694 -0
- package/src/core/oa-client.js +49 -415
- package/src/core/overflow-repair.js +221 -0
- package/src/core/policy-layer.js +55 -0
- package/src/core/policy-schema.js +401 -0
- package/src/core/policy-store.js +1058 -0
- package/src/core/presence-config.js +100 -0
- package/src/core/presence-leases.js +211 -0
- package/src/core/presence.js +688 -0
- package/src/core/profile-settings.js +243 -0
- package/src/core/qr-login-flow.js +237 -0
- package/src/core/read-state.js +145 -22
- package/src/core/receipts.js +355 -548
- package/src/core/recent-conversations.js +28 -6
- package/src/core/row-mac.js +405 -0
- package/src/core/search.js +271 -0
- package/src/core/secure-page.js +771 -0
- package/src/core/self-heal.js +493 -34
- package/src/core/session-expiry.js +103 -0
- package/src/core/session-notice.js +249 -0
- package/src/core/social/client.js +296 -0
- package/src/core/social/dpop.js +54 -0
- package/src/core/socket-host.js +437 -0
- package/src/core/sqlite.js +520 -0
- package/src/core/startup-gate.js +49 -5
- package/src/core/storage-quota.js +796 -0
- package/src/core/sync-action.js +180 -0
- package/src/core/sync-v2/auto-sync.js +356 -0
- package/src/core/sync-v2/board.js +130 -92
- package/src/core/sync-v2/conv-state.js +21 -4
- package/src/core/sync-v2/gap-advice.js +2 -3
- package/src/core/sync-v2/index.js +739 -323
- package/src/core/sync-v2/media.js +116 -27
- package/src/core/sync-v2/plan.js +16 -2
- package/src/core/sync-v2/ranges.js +98 -0
- package/src/core/sync-v2/reactions.js +12 -196
- package/src/core/sync-v2/senders.js +32 -14
- package/src/core/sync-v2/zcloud.js +177 -579
- package/src/core/sync.js +23 -21
- package/src/core/test-fake-session.js +87 -0
- package/src/core/typing.js +78 -0
- package/src/core/unknown-acts.js +240 -0
- package/src/core/voice-text.js +171 -0
- package/src/core/webhook-outbox.js +110 -12
- package/src/core/zalo-client.js +147 -188
- package/src/core/zbs/api.js +505 -0
- package/src/core/zbs/image.js +85 -0
- package/src/core/zbs/phone.js +59 -0
- package/src/core/zbs/rsa.js +129 -0
- package/src/core/zbs/template-check.js +449 -0
- package/src/index.js +60 -10
- package/src/mcp/action-tool.js +188 -0
- package/src/mcp/actions-business.js +488 -0
- package/src/mcp/actions-conversation.js +633 -0
- package/src/mcp/actions-media.js +268 -0
- package/src/mcp/actions-profile.js +281 -0
- package/src/mcp/actions-social.js +518 -0
- package/src/mcp/instructions.js +19 -5
- package/src/mcp/mcp-config.js +112 -10
- package/src/mcp/mcp-http-transport.js +162 -25
- package/src/mcp/mcp-server.js +14 -3
- package/src/mcp/mcp-tools.js +1686 -384
- package/src/mcp/message-buffer.js +58 -12
- package/src/mcp/notifier.js +1 -1
- package/src/mcp/official-tool.js +298 -0
- package/src/mcp/sync-jobs.js +7 -1
- package/src/mcp/sync-stages.js +72 -0
- package/src/mcp/thread-name-cache.js +43 -5
- package/src/mcp/tool-presence.js +153 -0
- package/src/mcp/wait-batch.js +27 -0
- package/src/mcp/wait-result.js +19 -21
- package/src/utils/bank-helpers.js +52 -1
- package/src/utils/cli-args.js +12 -12
- package/src/utils/date-range.js +50 -0
- package/src/utils/hidden-access.js +141 -0
- package/src/utils/interrupt.js +37 -0
- package/src/utils/json-input.js +41 -0
- package/src/utils/list-replies.js +60 -0
- package/src/utils/my-documents.js +2 -3
- package/src/utils/output.js +66 -2
- package/src/utils/qr-display.js +14 -8
- package/src/utils/qr-http-server.js +674 -134
- package/src/utils/quote.js +8 -8
- package/src/utils/secret-input.js +57 -0
- package/src/utils/vn-text.js +72 -0
- package/src/zalo/README.md +46 -0
- package/src/zalo/anomaly-store.js +49 -0
- package/src/zalo/api/actions.js +670 -0
- package/src/zalo/api/boards.js +1036 -0
- package/src/zalo/api/business.js +662 -0
- package/src/zalo/api/conversations.js +329 -0
- package/src/zalo/api/groups.js +631 -0
- package/src/zalo/api/messages.js +695 -0
- package/src/zalo/api/people.js +711 -0
- package/src/zalo/api/profile.js +374 -0
- package/src/zalo/api/session.js +45 -0
- package/src/zalo/api/upload.js +976 -0
- package/src/zalo/api.js +117 -0
- package/src/zalo/client.js +206 -0
- package/src/zalo/custom/forward.js +199 -0
- package/src/zalo/custom/gid.js +123 -0
- package/src/zalo/custom/group-history.js +246 -0
- package/src/zalo/custom/group-invite.js +53 -0
- package/src/zalo/custom/group-settings.js +186 -0
- package/src/zalo/custom/group-visibility.js +71 -0
- package/src/zalo/custom/pin.js +220 -0
- package/src/zalo/custom/renewlink.js +115 -0
- package/src/zalo/device-fingerprint.js +33 -0
- package/src/zalo/download-fetch.js +45 -0
- package/src/zalo/enums.js +25 -0
- package/src/zalo/errors.js +195 -0
- package/src/zalo/format/mentions.js +140 -0
- package/src/zalo/format/split-message.js +222 -0
- package/src/zalo/format/urgency.js +29 -0
- package/src/zalo/headers.js +93 -0
- package/src/zalo/index.js +72 -0
- package/src/zalo/kernel/atomic-file.js +217 -0
- package/src/zalo/kernel/bound.js +46 -0
- package/src/zalo/kernel/cipher.js +88 -0
- package/src/zalo/kernel/cookies.js +125 -0
- package/src/zalo/kernel/endpoint.js +211 -0
- package/src/zalo/kernel/http.js +360 -0
- package/src/zalo/kernel/json-ids.js +118 -0
- package/src/zalo/kernel/login-cipher.js +165 -0
- package/src/zalo/kernel/secret-file.js +45 -0
- package/src/zalo/kernel/session.js +261 -0
- package/src/zalo/kernel/zcloud-cipher.js +83 -0
- package/src/zalo/kickout.js +136 -0
- package/src/zalo/listener/dispatch.js +404 -0
- package/src/zalo/listener/frames.js +222 -0
- package/src/zalo/listener/friend-events.js +113 -0
- package/src/zalo/listener/group-events.js +117 -0
- package/src/zalo/listener/keepalive.js +191 -0
- package/src/zalo/listener/listener.js +469 -0
- package/src/zalo/listener/models.js +220 -0
- package/src/zalo/listener/reactions.js +224 -0
- package/src/zalo/listener/socket-tap.js +228 -0
- package/src/zalo/login.js +387 -0
- package/src/zalo/logout.js +192 -0
- package/src/zalo/maintenance.js +183 -0
- package/src/zalo/official-logout.js +254 -0
- package/src/zalo/paging.js +114 -0
- package/src/zalo/profile.js +184 -0
- package/src/zalo/pulls.js +129 -0
- package/src/zalo/qr-image.js +90 -0
- package/src/zalo/qr-login.js +494 -0
- package/src/zalo/queues/control-queue.js +193 -0
- package/src/zalo/queues/offline-queue.js +275 -0
- package/src/zalo/queues/queue-verify.js +306 -0
- package/src/zalo/reads.js +723 -0
- package/src/zalo/receipts.js +550 -0
- package/src/zalo/req-id.js +24 -0
- package/src/zalo/retry.js +343 -0
- package/src/zalo/session-call.js +55 -0
- package/src/zalo/socket.js +762 -0
- package/src/zalo/transfer-sync/assets.js +181 -0
- package/src/zalo/transfer-sync/channel.js +459 -0
- package/src/zalo/transfer-sync/download.js +161 -0
- package/src/zalo/transfer-sync/message-types.js +520 -0
- package/src/zalo/transfer-sync/transfer.js +468 -0
- package/src/zalo/trust-store.js +99 -0
- package/src/zalo/trust-wasm.js +393 -0
- package/src/zalo/upkeep.js +127 -0
- package/src/zalo/web-call.js +103 -0
- package/src/zalo/writes.js +704 -0
- package/src/zalo/zcloud-e2ee.js +214 -0
- package/src/zalo/zcloud.js +802 -0
- package/node_modules/asynckit/LICENSE +0 -21
- package/node_modules/asynckit/README.md +0 -233
- package/node_modules/asynckit/bench.js +0 -76
- package/node_modules/asynckit/index.js +0 -6
- package/node_modules/asynckit/lib/abort.js +0 -29
- package/node_modules/asynckit/lib/async.js +0 -34
- package/node_modules/asynckit/lib/defer.js +0 -26
- package/node_modules/asynckit/lib/iterate.js +0 -75
- package/node_modules/asynckit/lib/readable_asynckit.js +0 -91
- package/node_modules/asynckit/lib/readable_parallel.js +0 -25
- package/node_modules/asynckit/lib/readable_serial.js +0 -25
- package/node_modules/asynckit/lib/readable_serial_ordered.js +0 -29
- package/node_modules/asynckit/lib/state.js +0 -37
- package/node_modules/asynckit/lib/streamify.js +0 -141
- package/node_modules/asynckit/lib/terminator.js +0 -29
- package/node_modules/asynckit/package.json +0 -63
- package/node_modules/asynckit/parallel.js +0 -43
- package/node_modules/asynckit/serial.js +0 -17
- package/node_modules/asynckit/serialOrdered.js +0 -75
- package/node_modules/asynckit/stream.js +0 -21
- package/node_modules/bignumber.js/CHANGELOG.md +0 -381
- package/node_modules/bignumber.js/LICENCE.md +0 -26
- package/node_modules/bignumber.js/README.md +0 -289
- package/node_modules/bignumber.js/bignumber.d.mts +0 -6
- package/node_modules/bignumber.js/bignumber.d.ts +0 -5
- package/node_modules/bignumber.js/bignumber.js +0 -2922
- package/node_modules/bignumber.js/bignumber.mjs +0 -2907
- package/node_modules/bignumber.js/doc/API.html +0 -2249
- package/node_modules/bignumber.js/package.json +0 -60
- package/node_modules/bignumber.js/types.d.ts +0 -1821
- package/node_modules/call-bind-apply-helpers/.eslintrc +0 -17
- package/node_modules/call-bind-apply-helpers/.github/FUNDING.yml +0 -12
- package/node_modules/call-bind-apply-helpers/.nycrc +0 -9
- package/node_modules/call-bind-apply-helpers/CHANGELOG.md +0 -30
- package/node_modules/call-bind-apply-helpers/LICENSE +0 -21
- package/node_modules/call-bind-apply-helpers/README.md +0 -62
- package/node_modules/call-bind-apply-helpers/actualApply.d.ts +0 -1
- package/node_modules/call-bind-apply-helpers/actualApply.js +0 -10
- package/node_modules/call-bind-apply-helpers/applyBind.d.ts +0 -19
- package/node_modules/call-bind-apply-helpers/applyBind.js +0 -10
- package/node_modules/call-bind-apply-helpers/functionApply.d.ts +0 -1
- package/node_modules/call-bind-apply-helpers/functionApply.js +0 -4
- package/node_modules/call-bind-apply-helpers/functionCall.d.ts +0 -1
- package/node_modules/call-bind-apply-helpers/functionCall.js +0 -4
- package/node_modules/call-bind-apply-helpers/index.d.ts +0 -64
- package/node_modules/call-bind-apply-helpers/index.js +0 -15
- package/node_modules/call-bind-apply-helpers/package.json +0 -85
- package/node_modules/call-bind-apply-helpers/reflectApply.d.ts +0 -3
- package/node_modules/call-bind-apply-helpers/reflectApply.js +0 -4
- package/node_modules/call-bind-apply-helpers/test/index.js +0 -63
- package/node_modules/call-bind-apply-helpers/tsconfig.json +0 -9
- package/node_modules/combined-stream/License +0 -19
- package/node_modules/combined-stream/Readme.md +0 -138
- package/node_modules/combined-stream/lib/combined_stream.js +0 -208
- package/node_modules/combined-stream/package.json +0 -25
- package/node_modules/crypto-js/CONTRIBUTING.md +0 -28
- package/node_modules/crypto-js/LICENSE +0 -24
- package/node_modules/crypto-js/README.md +0 -275
- package/node_modules/crypto-js/aes.js +0 -234
- package/node_modules/crypto-js/blowfish.js +0 -471
- package/node_modules/crypto-js/bower.json +0 -39
- package/node_modules/crypto-js/cipher-core.js +0 -895
- package/node_modules/crypto-js/core.js +0 -807
- package/node_modules/crypto-js/crypto-js.js +0 -6657
- package/node_modules/crypto-js/docs/QuickStartGuide.wiki +0 -470
- package/node_modules/crypto-js/enc-base64.js +0 -136
- package/node_modules/crypto-js/enc-base64url.js +0 -148
- package/node_modules/crypto-js/enc-hex.js +0 -18
- package/node_modules/crypto-js/enc-latin1.js +0 -18
- package/node_modules/crypto-js/enc-utf16.js +0 -149
- package/node_modules/crypto-js/enc-utf8.js +0 -18
- package/node_modules/crypto-js/evpkdf.js +0 -134
- package/node_modules/crypto-js/format-hex.js +0 -66
- package/node_modules/crypto-js/format-openssl.js +0 -18
- package/node_modules/crypto-js/hmac-md5.js +0 -18
- package/node_modules/crypto-js/hmac-ripemd160.js +0 -18
- package/node_modules/crypto-js/hmac-sha1.js +0 -18
- package/node_modules/crypto-js/hmac-sha224.js +0 -18
- package/node_modules/crypto-js/hmac-sha256.js +0 -18
- package/node_modules/crypto-js/hmac-sha3.js +0 -18
- package/node_modules/crypto-js/hmac-sha384.js +0 -18
- package/node_modules/crypto-js/hmac-sha512.js +0 -18
- package/node_modules/crypto-js/hmac.js +0 -143
- package/node_modules/crypto-js/index.js +0 -18
- package/node_modules/crypto-js/lib-typedarrays.js +0 -76
- package/node_modules/crypto-js/md5.js +0 -268
- package/node_modules/crypto-js/mode-cfb.js +0 -80
- package/node_modules/crypto-js/mode-ctr-gladman.js +0 -116
- package/node_modules/crypto-js/mode-ctr.js +0 -58
- package/node_modules/crypto-js/mode-ecb.js +0 -40
- package/node_modules/crypto-js/mode-ofb.js +0 -54
- package/node_modules/crypto-js/package.json +0 -42
- package/node_modules/crypto-js/pad-ansix923.js +0 -49
- package/node_modules/crypto-js/pad-iso10126.js +0 -44
- package/node_modules/crypto-js/pad-iso97971.js +0 -40
- package/node_modules/crypto-js/pad-nopadding.js +0 -30
- package/node_modules/crypto-js/pad-pkcs7.js +0 -18
- package/node_modules/crypto-js/pad-zeropadding.js +0 -47
- package/node_modules/crypto-js/pbkdf2.js +0 -145
- package/node_modules/crypto-js/rabbit-legacy.js +0 -190
- package/node_modules/crypto-js/rabbit.js +0 -192
- package/node_modules/crypto-js/rc4.js +0 -139
- package/node_modules/crypto-js/ripemd160.js +0 -267
- package/node_modules/crypto-js/sha1.js +0 -150
- package/node_modules/crypto-js/sha224.js +0 -80
- package/node_modules/crypto-js/sha256.js +0 -199
- package/node_modules/crypto-js/sha3.js +0 -326
- package/node_modules/crypto-js/sha384.js +0 -83
- package/node_modules/crypto-js/sha512.js +0 -326
- package/node_modules/crypto-js/tripledes.js +0 -779
- package/node_modules/crypto-js/x64-core.js +0 -304
- package/node_modules/delayed-stream/.npmignore +0 -1
- package/node_modules/delayed-stream/License +0 -19
- package/node_modules/delayed-stream/Makefile +0 -7
- package/node_modules/delayed-stream/Readme.md +0 -141
- package/node_modules/delayed-stream/lib/delayed_stream.js +0 -107
- package/node_modules/delayed-stream/package.json +0 -27
- package/node_modules/dunder-proto/.eslintrc +0 -5
- package/node_modules/dunder-proto/.github/FUNDING.yml +0 -12
- package/node_modules/dunder-proto/.nycrc +0 -13
- package/node_modules/dunder-proto/CHANGELOG.md +0 -24
- package/node_modules/dunder-proto/LICENSE +0 -21
- package/node_modules/dunder-proto/README.md +0 -54
- package/node_modules/dunder-proto/get.d.ts +0 -5
- package/node_modules/dunder-proto/get.js +0 -30
- package/node_modules/dunder-proto/package.json +0 -76
- package/node_modules/dunder-proto/set.d.ts +0 -5
- package/node_modules/dunder-proto/set.js +0 -35
- package/node_modules/dunder-proto/test/get.js +0 -34
- package/node_modules/dunder-proto/test/index.js +0 -4
- package/node_modules/dunder-proto/test/set.js +0 -50
- package/node_modules/dunder-proto/tsconfig.json +0 -9
- package/node_modules/es-define-property/.eslintrc +0 -13
- package/node_modules/es-define-property/.github/FUNDING.yml +0 -12
- package/node_modules/es-define-property/.nycrc +0 -9
- package/node_modules/es-define-property/CHANGELOG.md +0 -29
- package/node_modules/es-define-property/LICENSE +0 -21
- package/node_modules/es-define-property/README.md +0 -49
- package/node_modules/es-define-property/index.d.ts +0 -3
- package/node_modules/es-define-property/index.js +0 -14
- package/node_modules/es-define-property/package.json +0 -81
- package/node_modules/es-define-property/test/index.js +0 -56
- package/node_modules/es-define-property/tsconfig.json +0 -10
- package/node_modules/es-errors/.eslintrc +0 -5
- package/node_modules/es-errors/.github/FUNDING.yml +0 -12
- package/node_modules/es-errors/CHANGELOG.md +0 -40
- package/node_modules/es-errors/LICENSE +0 -21
- package/node_modules/es-errors/README.md +0 -55
- package/node_modules/es-errors/eval.d.ts +0 -3
- package/node_modules/es-errors/eval.js +0 -4
- package/node_modules/es-errors/index.d.ts +0 -3
- package/node_modules/es-errors/index.js +0 -4
- package/node_modules/es-errors/package.json +0 -80
- package/node_modules/es-errors/range.d.ts +0 -3
- package/node_modules/es-errors/range.js +0 -4
- package/node_modules/es-errors/ref.d.ts +0 -3
- package/node_modules/es-errors/ref.js +0 -4
- package/node_modules/es-errors/syntax.d.ts +0 -3
- package/node_modules/es-errors/syntax.js +0 -4
- package/node_modules/es-errors/test/index.js +0 -19
- package/node_modules/es-errors/tsconfig.json +0 -49
- package/node_modules/es-errors/type.d.ts +0 -3
- package/node_modules/es-errors/type.js +0 -4
- package/node_modules/es-errors/uri.d.ts +0 -3
- package/node_modules/es-errors/uri.js +0 -4
- package/node_modules/es-object-atoms/.eslintrc +0 -16
- package/node_modules/es-object-atoms/.github/FUNDING.yml +0 -12
- package/node_modules/es-object-atoms/CHANGELOG.md +0 -44
- package/node_modules/es-object-atoms/LICENSE +0 -21
- package/node_modules/es-object-atoms/README.md +0 -63
- package/node_modules/es-object-atoms/RequireObjectCoercible.d.ts +0 -3
- package/node_modules/es-object-atoms/RequireObjectCoercible.js +0 -11
- package/node_modules/es-object-atoms/ToObject.d.ts +0 -7
- package/node_modules/es-object-atoms/ToObject.js +0 -10
- package/node_modules/es-object-atoms/index.d.ts +0 -3
- package/node_modules/es-object-atoms/index.js +0 -4
- package/node_modules/es-object-atoms/isObject.d.ts +0 -3
- package/node_modules/es-object-atoms/isObject.js +0 -6
- package/node_modules/es-object-atoms/package.json +0 -79
- package/node_modules/es-object-atoms/test/index.js +0 -38
- package/node_modules/es-object-atoms/tsconfig.json +0 -7
- package/node_modules/es-set-tostringtag/.eslintrc +0 -13
- package/node_modules/es-set-tostringtag/.nycrc +0 -9
- package/node_modules/es-set-tostringtag/CHANGELOG.md +0 -67
- package/node_modules/es-set-tostringtag/LICENSE +0 -21
- package/node_modules/es-set-tostringtag/README.md +0 -53
- package/node_modules/es-set-tostringtag/index.d.ts +0 -10
- package/node_modules/es-set-tostringtag/index.js +0 -35
- package/node_modules/es-set-tostringtag/package.json +0 -78
- package/node_modules/es-set-tostringtag/test/index.js +0 -85
- package/node_modules/es-set-tostringtag/tsconfig.json +0 -9
- package/node_modules/form-data/CHANGELOG.md +0 -686
- package/node_modules/form-data/License +0 -19
- package/node_modules/form-data/README.md +0 -355
- package/node_modules/form-data/index.d.ts +0 -62
- package/node_modules/form-data/lib/browser.js +0 -4
- package/node_modules/form-data/lib/form_data.js +0 -506
- package/node_modules/form-data/lib/populate.js +0 -10
- package/node_modules/form-data/node_modules/mime-db/HISTORY.md +0 -507
- package/node_modules/form-data/node_modules/mime-db/LICENSE +0 -23
- package/node_modules/form-data/node_modules/mime-db/README.md +0 -100
- package/node_modules/form-data/node_modules/mime-db/db.json +0 -8519
- package/node_modules/form-data/node_modules/mime-db/index.js +0 -12
- package/node_modules/form-data/node_modules/mime-db/package.json +0 -60
- package/node_modules/form-data/node_modules/mime-types/HISTORY.md +0 -397
- package/node_modules/form-data/node_modules/mime-types/LICENSE +0 -23
- package/node_modules/form-data/node_modules/mime-types/README.md +0 -113
- package/node_modules/form-data/node_modules/mime-types/index.js +0 -188
- package/node_modules/form-data/node_modules/mime-types/package.json +0 -44
- package/node_modules/form-data/package.json +0 -82
- package/node_modules/function-bind/.eslintrc +0 -21
- package/node_modules/function-bind/.github/FUNDING.yml +0 -12
- package/node_modules/function-bind/.github/SECURITY.md +0 -3
- package/node_modules/function-bind/.nycrc +0 -13
- package/node_modules/function-bind/CHANGELOG.md +0 -136
- package/node_modules/function-bind/LICENSE +0 -20
- package/node_modules/function-bind/README.md +0 -46
- package/node_modules/function-bind/implementation.js +0 -84
- package/node_modules/function-bind/index.js +0 -5
- package/node_modules/function-bind/package.json +0 -87
- package/node_modules/function-bind/test/.eslintrc +0 -9
- package/node_modules/function-bind/test/index.js +0 -252
- package/node_modules/get-intrinsic/.eslintrc +0 -42
- package/node_modules/get-intrinsic/.github/FUNDING.yml +0 -12
- package/node_modules/get-intrinsic/.nycrc +0 -9
- package/node_modules/get-intrinsic/CHANGELOG.md +0 -186
- package/node_modules/get-intrinsic/LICENSE +0 -21
- package/node_modules/get-intrinsic/README.md +0 -71
- package/node_modules/get-intrinsic/index.js +0 -378
- package/node_modules/get-intrinsic/package.json +0 -97
- package/node_modules/get-intrinsic/test/GetIntrinsic.js +0 -274
- package/node_modules/get-proto/.eslintrc +0 -10
- package/node_modules/get-proto/.github/FUNDING.yml +0 -12
- package/node_modules/get-proto/.nycrc +0 -9
- package/node_modules/get-proto/CHANGELOG.md +0 -21
- package/node_modules/get-proto/LICENSE +0 -21
- package/node_modules/get-proto/Object.getPrototypeOf.d.ts +0 -5
- package/node_modules/get-proto/Object.getPrototypeOf.js +0 -6
- package/node_modules/get-proto/README.md +0 -50
- package/node_modules/get-proto/Reflect.getPrototypeOf.d.ts +0 -3
- package/node_modules/get-proto/Reflect.getPrototypeOf.js +0 -4
- package/node_modules/get-proto/index.d.ts +0 -5
- package/node_modules/get-proto/index.js +0 -27
- package/node_modules/get-proto/package.json +0 -81
- package/node_modules/get-proto/test/index.js +0 -68
- package/node_modules/get-proto/tsconfig.json +0 -9
- package/node_modules/gopd/.eslintrc +0 -16
- package/node_modules/gopd/.github/FUNDING.yml +0 -12
- package/node_modules/gopd/CHANGELOG.md +0 -45
- package/node_modules/gopd/LICENSE +0 -21
- package/node_modules/gopd/README.md +0 -40
- package/node_modules/gopd/gOPD.d.ts +0 -1
- package/node_modules/gopd/gOPD.js +0 -4
- package/node_modules/gopd/index.d.ts +0 -5
- package/node_modules/gopd/index.js +0 -15
- package/node_modules/gopd/package.json +0 -77
- package/node_modules/gopd/test/index.js +0 -36
- package/node_modules/gopd/tsconfig.json +0 -9
- package/node_modules/has-symbols/.eslintrc +0 -11
- package/node_modules/has-symbols/.github/FUNDING.yml +0 -12
- package/node_modules/has-symbols/.nycrc +0 -9
- package/node_modules/has-symbols/CHANGELOG.md +0 -91
- package/node_modules/has-symbols/LICENSE +0 -21
- package/node_modules/has-symbols/README.md +0 -46
- package/node_modules/has-symbols/index.d.ts +0 -3
- package/node_modules/has-symbols/index.js +0 -14
- package/node_modules/has-symbols/package.json +0 -111
- package/node_modules/has-symbols/shams.d.ts +0 -3
- package/node_modules/has-symbols/shams.js +0 -45
- package/node_modules/has-symbols/test/index.js +0 -22
- package/node_modules/has-symbols/test/shams/core-js.js +0 -29
- package/node_modules/has-symbols/test/shams/get-own-property-symbols.js +0 -29
- package/node_modules/has-symbols/test/tests.js +0 -58
- package/node_modules/has-symbols/tsconfig.json +0 -10
- package/node_modules/has-tostringtag/.eslintrc +0 -5
- package/node_modules/has-tostringtag/.github/FUNDING.yml +0 -12
- package/node_modules/has-tostringtag/.nycrc +0 -13
- package/node_modules/has-tostringtag/CHANGELOG.md +0 -42
- package/node_modules/has-tostringtag/LICENSE +0 -21
- package/node_modules/has-tostringtag/README.md +0 -46
- package/node_modules/has-tostringtag/index.d.ts +0 -3
- package/node_modules/has-tostringtag/index.js +0 -8
- package/node_modules/has-tostringtag/package.json +0 -108
- package/node_modules/has-tostringtag/shams.d.ts +0 -3
- package/node_modules/has-tostringtag/shams.js +0 -8
- package/node_modules/has-tostringtag/test/index.js +0 -21
- package/node_modules/has-tostringtag/test/shams/core-js.js +0 -31
- package/node_modules/has-tostringtag/test/shams/get-own-property-symbols.js +0 -30
- package/node_modules/has-tostringtag/test/tests.js +0 -15
- package/node_modules/has-tostringtag/tsconfig.json +0 -49
- package/node_modules/hasown/.github/FUNDING.yml +0 -12
- package/node_modules/hasown/.nycrc +0 -13
- package/node_modules/hasown/CHANGELOG.md +0 -58
- package/node_modules/hasown/LICENSE +0 -21
- package/node_modules/hasown/README.md +0 -40
- package/node_modules/hasown/eslint.config.mjs +0 -6
- package/node_modules/hasown/index.d.ts +0 -3
- package/node_modules/hasown/index.js +0 -8
- package/node_modules/hasown/package.json +0 -91
- package/node_modules/hasown/tsconfig.json +0 -6
- package/node_modules/json-bigint/LICENSE +0 -20
- package/node_modules/json-bigint/README.md +0 -240
- package/node_modules/json-bigint/index.js +0 -12
- package/node_modules/json-bigint/lib/parse.js +0 -443
- package/node_modules/json-bigint/lib/stringify.js +0 -384
- package/node_modules/json-bigint/package.json +0 -34
- package/node_modules/math-intrinsics/.eslintrc +0 -16
- package/node_modules/math-intrinsics/.github/FUNDING.yml +0 -12
- package/node_modules/math-intrinsics/CHANGELOG.md +0 -24
- package/node_modules/math-intrinsics/LICENSE +0 -21
- package/node_modules/math-intrinsics/README.md +0 -50
- package/node_modules/math-intrinsics/abs.d.ts +0 -1
- package/node_modules/math-intrinsics/abs.js +0 -4
- package/node_modules/math-intrinsics/constants/maxArrayLength.d.ts +0 -3
- package/node_modules/math-intrinsics/constants/maxArrayLength.js +0 -4
- package/node_modules/math-intrinsics/constants/maxSafeInteger.d.ts +0 -3
- package/node_modules/math-intrinsics/constants/maxSafeInteger.js +0 -5
- package/node_modules/math-intrinsics/constants/maxValue.d.ts +0 -3
- package/node_modules/math-intrinsics/constants/maxValue.js +0 -5
- package/node_modules/math-intrinsics/floor.d.ts +0 -1
- package/node_modules/math-intrinsics/floor.js +0 -4
- package/node_modules/math-intrinsics/isFinite.d.ts +0 -3
- package/node_modules/math-intrinsics/isFinite.js +0 -12
- package/node_modules/math-intrinsics/isInteger.d.ts +0 -3
- package/node_modules/math-intrinsics/isInteger.js +0 -16
- package/node_modules/math-intrinsics/isNaN.d.ts +0 -1
- package/node_modules/math-intrinsics/isNaN.js +0 -6
- package/node_modules/math-intrinsics/isNegativeZero.d.ts +0 -3
- package/node_modules/math-intrinsics/isNegativeZero.js +0 -6
- package/node_modules/math-intrinsics/max.d.ts +0 -1
- package/node_modules/math-intrinsics/max.js +0 -4
- package/node_modules/math-intrinsics/min.d.ts +0 -1
- package/node_modules/math-intrinsics/min.js +0 -4
- package/node_modules/math-intrinsics/mod.d.ts +0 -3
- package/node_modules/math-intrinsics/mod.js +0 -9
- package/node_modules/math-intrinsics/package.json +0 -86
- package/node_modules/math-intrinsics/pow.d.ts +0 -1
- package/node_modules/math-intrinsics/pow.js +0 -4
- package/node_modules/math-intrinsics/round.d.ts +0 -1
- package/node_modules/math-intrinsics/round.js +0 -4
- package/node_modules/math-intrinsics/sign.d.ts +0 -3
- package/node_modules/math-intrinsics/sign.js +0 -11
- package/node_modules/math-intrinsics/test/index.js +0 -192
- package/node_modules/math-intrinsics/tsconfig.json +0 -3
- package/node_modules/pako/LICENSE +0 -21
- package/node_modules/pako/README.md +0 -155
- package/node_modules/pako/dist/pako.es5.js +0 -6760
- package/node_modules/pako/dist/pako.es5.min.js +0 -2
- package/node_modules/pako/dist/pako.esm.mjs +0 -6945
- package/node_modules/pako/dist/pako.js +0 -6964
- package/node_modules/pako/dist/pako.min.js +0 -2
- package/node_modules/pako/dist/pako_deflate.es5.js +0 -3953
- package/node_modules/pako/dist/pako_deflate.es5.min.js +0 -2
- package/node_modules/pako/dist/pako_deflate.js +0 -4154
- package/node_modules/pako/dist/pako_deflate.min.js +0 -2
- package/node_modules/pako/dist/pako_inflate.es5.js +0 -3272
- package/node_modules/pako/dist/pako_inflate.es5.min.js +0 -2
- package/node_modules/pako/dist/pako_inflate.js +0 -3279
- package/node_modules/pako/dist/pako_inflate.min.js +0 -2
- package/node_modules/pako/index.js +0 -18
- package/node_modules/pako/lib/deflate.js +0 -387
- package/node_modules/pako/lib/inflate.js +0 -456
- package/node_modules/pako/lib/utils/common.js +0 -48
- package/node_modules/pako/lib/utils/strings.js +0 -174
- package/node_modules/pako/lib/zlib/README +0 -59
- package/node_modules/pako/lib/zlib/adler32.js +0 -51
- package/node_modules/pako/lib/zlib/constants.js +0 -68
- package/node_modules/pako/lib/zlib/crc32.js +0 -59
- package/node_modules/pako/lib/zlib/deflate.js +0 -2069
- package/node_modules/pako/lib/zlib/gzheader.js +0 -58
- package/node_modules/pako/lib/zlib/inffast.js +0 -344
- package/node_modules/pako/lib/zlib/inflate.js +0 -1575
- package/node_modules/pako/lib/zlib/inftrees.js +0 -340
- package/node_modules/pako/lib/zlib/messages.js +0 -32
- package/node_modules/pako/lib/zlib/trees.js +0 -1179
- package/node_modules/pako/lib/zlib/zstream.js +0 -47
- package/node_modules/pako/package.json +0 -73
- package/node_modules/semver/LICENSE +0 -15
- package/node_modules/semver/README.md +0 -680
- package/node_modules/semver/bin/semver.js +0 -195
- package/node_modules/semver/classes/comparator.js +0 -143
- package/node_modules/semver/classes/index.js +0 -7
- package/node_modules/semver/classes/range.js +0 -577
- package/node_modules/semver/classes/semver.js +0 -350
- package/node_modules/semver/functions/clean.js +0 -8
- package/node_modules/semver/functions/cmp.js +0 -54
- package/node_modules/semver/functions/coerce.js +0 -62
- package/node_modules/semver/functions/compare-build.js +0 -9
- package/node_modules/semver/functions/compare-loose.js +0 -5
- package/node_modules/semver/functions/compare.js +0 -7
- package/node_modules/semver/functions/diff.js +0 -60
- package/node_modules/semver/functions/eq.js +0 -5
- package/node_modules/semver/functions/gt.js +0 -5
- package/node_modules/semver/functions/gte.js +0 -5
- package/node_modules/semver/functions/inc.js +0 -21
- package/node_modules/semver/functions/lt.js +0 -5
- package/node_modules/semver/functions/lte.js +0 -5
- package/node_modules/semver/functions/major.js +0 -5
- package/node_modules/semver/functions/minor.js +0 -5
- package/node_modules/semver/functions/neq.js +0 -5
- package/node_modules/semver/functions/parse.js +0 -18
- package/node_modules/semver/functions/patch.js +0 -5
- package/node_modules/semver/functions/prerelease.js +0 -8
- package/node_modules/semver/functions/rcompare.js +0 -5
- package/node_modules/semver/functions/rsort.js +0 -5
- package/node_modules/semver/functions/satisfies.js +0 -12
- package/node_modules/semver/functions/sort.js +0 -5
- package/node_modules/semver/functions/truncate.js +0 -48
- package/node_modules/semver/functions/valid.js +0 -8
- package/node_modules/semver/index.js +0 -93
- package/node_modules/semver/internal/constants.js +0 -37
- package/node_modules/semver/internal/debug.js +0 -11
- package/node_modules/semver/internal/identifiers.js +0 -29
- package/node_modules/semver/internal/lrucache.js +0 -42
- package/node_modules/semver/internal/parse-options.js +0 -17
- package/node_modules/semver/internal/re.js +0 -223
- package/node_modules/semver/package.json +0 -78
- package/node_modules/semver/preload.js +0 -4
- package/node_modules/semver/range.bnf +0 -17
- package/node_modules/semver/ranges/gtr.js +0 -6
- package/node_modules/semver/ranges/intersects.js +0 -9
- package/node_modules/semver/ranges/ltr.js +0 -6
- package/node_modules/semver/ranges/max-satisfying.js +0 -27
- package/node_modules/semver/ranges/min-satisfying.js +0 -26
- package/node_modules/semver/ranges/min-version.js +0 -63
- package/node_modules/semver/ranges/outside.js +0 -82
- package/node_modules/semver/ranges/simplify.js +0 -49
- package/node_modules/semver/ranges/subset.js +0 -249
- package/node_modules/semver/ranges/to-comparators.js +0 -10
- package/node_modules/semver/ranges/valid.js +0 -13
- package/node_modules/spark-md5/LICENSE +0 -13
- package/node_modules/spark-md5/README.md +0 -191
- package/node_modules/spark-md5/package.json +0 -35
- package/node_modules/spark-md5/spark-md5.js +0 -751
- package/node_modules/spark-md5/spark-md5.min.js +0 -1
- package/node_modules/tldts/LICENSE +0 -13
- package/node_modules/tldts/README.md +0 -327
- package/node_modules/tldts/bin/cli.js +0 -21
- package/node_modules/tldts/dist/cjs/index.js +0 -666
- package/node_modules/tldts/dist/cjs/index.js.map +0 -1
- package/node_modules/tldts/dist/cjs/src/data/trie.js +0 -14
- package/node_modules/tldts/dist/cjs/src/data/trie.js.map +0 -1
- package/node_modules/tldts/dist/cjs/src/suffix-trie.js +0 -67
- package/node_modules/tldts/dist/cjs/src/suffix-trie.js.map +0 -1
- package/node_modules/tldts/dist/cjs/tsconfig.tsbuildinfo +0 -1
- package/node_modules/tldts/dist/es6/index.js +0 -33
- package/node_modules/tldts/dist/es6/index.js.map +0 -1
- package/node_modules/tldts/dist/es6/src/data/trie.js +0 -11
- package/node_modules/tldts/dist/es6/src/data/trie.js.map +0 -1
- package/node_modules/tldts/dist/es6/src/suffix-trie.js +0 -64
- package/node_modules/tldts/dist/es6/src/suffix-trie.js.map +0 -1
- package/node_modules/tldts/dist/es6/tsconfig.bundle.tsbuildinfo +0 -1
- package/node_modules/tldts/dist/index.cjs.min.js +0 -2
- package/node_modules/tldts/dist/index.cjs.min.js.map +0 -1
- package/node_modules/tldts/dist/index.esm.min.js +0 -2
- package/node_modules/tldts/dist/index.esm.min.js.map +0 -1
- package/node_modules/tldts/dist/index.umd.min.js +0 -2
- package/node_modules/tldts/dist/index.umd.min.js.map +0 -1
- package/node_modules/tldts/dist/types/index.d.ts +0 -7
- package/node_modules/tldts/dist/types/src/data/trie.d.ts +0 -5
- package/node_modules/tldts/dist/types/src/suffix-trie.d.ts +0 -5
- package/node_modules/tldts/index.ts +0 -62
- package/node_modules/tldts/package.json +0 -91
- package/node_modules/tldts/src/data/trie.ts +0 -14
- package/node_modules/tldts/src/suffix-trie.ts +0 -110
- package/node_modules/tldts-core/LICENSE +0 -13
- package/node_modules/tldts-core/README.md +0 -3
- package/node_modules/tldts-core/dist/cjs/index.js +0 -561
- package/node_modules/tldts-core/dist/cjs/index.js.map +0 -1
- package/node_modules/tldts-core/dist/cjs/src/domain-without-suffix.js +0 -15
- package/node_modules/tldts-core/dist/cjs/src/domain-without-suffix.js.map +0 -1
- package/node_modules/tldts-core/dist/cjs/src/domain.js +0 -83
- package/node_modules/tldts-core/dist/cjs/src/domain.js.map +0 -1
- package/node_modules/tldts-core/dist/cjs/src/extract-hostname.js +0 -149
- package/node_modules/tldts-core/dist/cjs/src/extract-hostname.js.map +0 -1
- package/node_modules/tldts-core/dist/cjs/src/factory.js +0 -104
- package/node_modules/tldts-core/dist/cjs/src/factory.js.map +0 -1
- package/node_modules/tldts-core/dist/cjs/src/is-ip.js +0 -72
- package/node_modules/tldts-core/dist/cjs/src/is-ip.js.map +0 -1
- package/node_modules/tldts-core/dist/cjs/src/is-valid.js +0 -69
- package/node_modules/tldts-core/dist/cjs/src/is-valid.js.map +0 -1
- package/node_modules/tldts-core/dist/cjs/src/lookup/fast-path.js +0 -69
- package/node_modules/tldts-core/dist/cjs/src/lookup/fast-path.js.map +0 -1
- package/node_modules/tldts-core/dist/cjs/src/lookup/interface.js +0 -3
- package/node_modules/tldts-core/dist/cjs/src/lookup/interface.js.map +0 -1
- package/node_modules/tldts-core/dist/cjs/src/options.js +0 -22
- package/node_modules/tldts-core/dist/cjs/src/options.js.map +0 -1
- package/node_modules/tldts-core/dist/cjs/src/subdomain.js +0 -14
- package/node_modules/tldts-core/dist/cjs/src/subdomain.js.map +0 -1
- package/node_modules/tldts-core/dist/cjs/tsconfig.tsbuildinfo +0 -1
- package/node_modules/tldts-core/dist/es6/index.js +0 -4
- package/node_modules/tldts-core/dist/es6/index.js.map +0 -1
- package/node_modules/tldts-core/dist/es6/src/domain-without-suffix.js +0 -12
- package/node_modules/tldts-core/dist/es6/src/domain-without-suffix.js.map +0 -1
- package/node_modules/tldts-core/dist/es6/src/domain.js +0 -80
- package/node_modules/tldts-core/dist/es6/src/domain.js.map +0 -1
- package/node_modules/tldts-core/dist/es6/src/extract-hostname.js +0 -146
- package/node_modules/tldts-core/dist/es6/src/extract-hostname.js.map +0 -1
- package/node_modules/tldts-core/dist/es6/src/factory.js +0 -99
- package/node_modules/tldts-core/dist/es6/src/factory.js.map +0 -1
- package/node_modules/tldts-core/dist/es6/src/is-ip.js +0 -69
- package/node_modules/tldts-core/dist/es6/src/is-ip.js.map +0 -1
- package/node_modules/tldts-core/dist/es6/src/is-valid.js +0 -66
- package/node_modules/tldts-core/dist/es6/src/is-valid.js.map +0 -1
- package/node_modules/tldts-core/dist/es6/src/lookup/fast-path.js +0 -66
- package/node_modules/tldts-core/dist/es6/src/lookup/fast-path.js.map +0 -1
- package/node_modules/tldts-core/dist/es6/src/lookup/interface.js +0 -2
- package/node_modules/tldts-core/dist/es6/src/lookup/interface.js.map +0 -1
- package/node_modules/tldts-core/dist/es6/src/options.js +0 -19
- package/node_modules/tldts-core/dist/es6/src/options.js.map +0 -1
- package/node_modules/tldts-core/dist/es6/src/subdomain.js +0 -11
- package/node_modules/tldts-core/dist/es6/src/subdomain.js.map +0 -1
- package/node_modules/tldts-core/dist/es6/tsconfig.bundle.tsbuildinfo +0 -1
- package/node_modules/tldts-core/dist/types/index.d.ts +0 -4
- package/node_modules/tldts-core/dist/types/src/domain-without-suffix.d.ts +0 -6
- package/node_modules/tldts-core/dist/types/src/domain.d.ts +0 -5
- package/node_modules/tldts-core/dist/types/src/extract-hostname.d.ts +0 -5
- package/node_modules/tldts-core/dist/types/src/factory.d.ts +0 -28
- package/node_modules/tldts-core/dist/types/src/is-ip.d.ts +0 -6
- package/node_modules/tldts-core/dist/types/src/is-valid.d.ts +0 -15
- package/node_modules/tldts-core/dist/types/src/lookup/fast-path.d.ts +0 -2
- package/node_modules/tldts-core/dist/types/src/lookup/interface.d.ts +0 -9
- package/node_modules/tldts-core/dist/types/src/options.d.ts +0 -10
- package/node_modules/tldts-core/dist/types/src/subdomain.d.ts +0 -4
- package/node_modules/tldts-core/index.ts +0 -10
- package/node_modules/tldts-core/package.json +0 -68
- package/node_modules/tldts-core/src/domain-without-suffix.ts +0 -14
- package/node_modules/tldts-core/src/domain.ts +0 -100
- package/node_modules/tldts-core/src/extract-hostname.ts +0 -170
- package/node_modules/tldts-core/src/factory.ts +0 -160
- package/node_modules/tldts-core/src/is-ip.ts +0 -87
- package/node_modules/tldts-core/src/is-valid.ts +0 -79
- package/node_modules/tldts-core/src/lookup/fast-path.ts +0 -80
- package/node_modules/tldts-core/src/lookup/interface.ts +0 -10
- package/node_modules/tldts-core/src/options.ts +0 -39
- package/node_modules/tldts-core/src/subdomain.ts +0 -11
- package/node_modules/tough-cookie/LICENSE +0 -12
- package/node_modules/tough-cookie/README.md +0 -154
- package/node_modules/tough-cookie/dist/cookie/canonicalDomain.d.ts +0 -33
- package/node_modules/tough-cookie/dist/cookie/canonicalDomain.js +0 -65
- package/node_modules/tough-cookie/dist/cookie/constants.d.ts +0 -54
- package/node_modules/tough-cookie/dist/cookie/constants.js +0 -38
- package/node_modules/tough-cookie/dist/cookie/cookie.d.ts +0 -326
- package/node_modules/tough-cookie/dist/cookie/cookie.js +0 -831
- package/node_modules/tough-cookie/dist/cookie/cookieCompare.d.ts +0 -58
- package/node_modules/tough-cookie/dist/cookie/cookieCompare.js +0 -84
- package/node_modules/tough-cookie/dist/cookie/cookieJar.d.ts +0 -621
- package/node_modules/tough-cookie/dist/cookie/cookieJar.js +0 -1000
- package/node_modules/tough-cookie/dist/cookie/defaultPath.d.ts +0 -40
- package/node_modules/tough-cookie/dist/cookie/defaultPath.js +0 -60
- package/node_modules/tough-cookie/dist/cookie/domainMatch.d.ts +0 -38
- package/node_modules/tough-cookie/dist/cookie/domainMatch.js +0 -94
- package/node_modules/tough-cookie/dist/cookie/formatDate.d.ts +0 -15
- package/node_modules/tough-cookie/dist/cookie/formatDate.js +0 -20
- package/node_modules/tough-cookie/dist/cookie/index.d.ts +0 -29
- package/node_modules/tough-cookie/dist/cookie/index.js +0 -54
- package/node_modules/tough-cookie/dist/cookie/parseDate.d.ts +0 -103
- package/node_modules/tough-cookie/dist/cookie/parseDate.js +0 -323
- package/node_modules/tough-cookie/dist/cookie/permutePath.d.ts +0 -14
- package/node_modules/tough-cookie/dist/cookie/permutePath.js +0 -32
- package/node_modules/tough-cookie/dist/getPublicSuffix.d.ts +0 -55
- package/node_modules/tough-cookie/dist/getPublicSuffix.js +0 -71
- package/node_modules/tough-cookie/dist/memstore.d.ts +0 -220
- package/node_modules/tough-cookie/dist/memstore.js +0 -187
- package/node_modules/tough-cookie/dist/pathMatch.d.ts +0 -17
- package/node_modules/tough-cookie/dist/pathMatch.js +0 -40
- package/node_modules/tough-cookie/dist/permuteDomain.d.ts +0 -15
- package/node_modules/tough-cookie/dist/permuteDomain.js +0 -44
- package/node_modules/tough-cookie/dist/store.d.ts +0 -211
- package/node_modules/tough-cookie/dist/store.js +0 -76
- package/node_modules/tough-cookie/dist/utils.d.ts +0 -34
- package/node_modules/tough-cookie/dist/utils.js +0 -99
- package/node_modules/tough-cookie/dist/validators.d.ts +0 -24
- package/node_modules/tough-cookie/dist/validators.js +0 -90
- package/node_modules/tough-cookie/dist/version.d.ts +0 -5
- package/node_modules/tough-cookie/dist/version.js +0 -8
- package/node_modules/tough-cookie/package.json +0 -144
- package/node_modules/ws/LICENSE +0 -20
- package/node_modules/ws/README.md +0 -548
- package/node_modules/ws/browser.js +0 -8
- package/node_modules/ws/index.js +0 -22
- package/node_modules/ws/lib/buffer-util.js +0 -131
- package/node_modules/ws/lib/constants.js +0 -19
- package/node_modules/ws/lib/event-target.js +0 -292
- package/node_modules/ws/lib/extension.js +0 -203
- package/node_modules/ws/lib/limiter.js +0 -55
- package/node_modules/ws/lib/permessage-deflate.js +0 -530
- package/node_modules/ws/lib/receiver.js +0 -743
- package/node_modules/ws/lib/sender.js +0 -607
- package/node_modules/ws/lib/stream.js +0 -161
- package/node_modules/ws/lib/subprotocol.js +0 -62
- package/node_modules/ws/lib/validation.js +0 -152
- package/node_modules/ws/lib/websocket-server.js +0 -562
- package/node_modules/ws/lib/websocket.js +0 -1407
- package/node_modules/ws/package.json +0 -74
- package/node_modules/ws/wrapper.mjs +0 -21
- package/node_modules/zca-js/.prettierrc +0 -5
- package/node_modules/zca-js/CODE_OF_CONDUCT.md +0 -163
- package/node_modules/zca-js/CONTRIBUTING.md +0 -470
- package/node_modules/zca-js/LICENSE +0 -21
- package/node_modules/zca-js/README.md +0 -225
- package/node_modules/zca-js/SECURITY.md +0 -83
- package/node_modules/zca-js/dist/Errors/ZaloApiError.d.ts +0 -4
- package/node_modules/zca-js/dist/Errors/ZaloApiError.js +0 -7
- package/node_modules/zca-js/dist/Errors/ZaloApiLoginQRAborted.d.ts +0 -4
- package/node_modules/zca-js/dist/Errors/ZaloApiLoginQRAborted.js +0 -7
- package/node_modules/zca-js/dist/Errors/ZaloApiLoginQRDeclined.d.ts +0 -4
- package/node_modules/zca-js/dist/Errors/ZaloApiLoginQRDeclined.js +0 -7
- package/node_modules/zca-js/dist/Errors/ZaloApiMissingImageMetadataGetter.d.ts +0 -4
- package/node_modules/zca-js/dist/Errors/ZaloApiMissingImageMetadataGetter.js +0 -7
- package/node_modules/zca-js/dist/Errors/index.d.ts +0 -4
- package/node_modules/zca-js/dist/Errors/index.js +0 -4
- package/node_modules/zca-js/dist/apis/acceptFriendRequest.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/acceptFriendRequest.js +0 -28
- package/node_modules/zca-js/dist/apis/addGroupBlockedMember.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/addGroupBlockedMember.js +0 -28
- package/node_modules/zca-js/dist/apis/addGroupDeputy.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/addGroupDeputy.js +0 -30
- package/node_modules/zca-js/dist/apis/addPollOptions.d.ts +0 -14
- package/node_modules/zca-js/dist/apis/addPollOptions.js +0 -26
- package/node_modules/zca-js/dist/apis/addQuickMessage.d.ts +0 -11
- package/node_modules/zca-js/dist/apis/addQuickMessage.js +0 -60
- package/node_modules/zca-js/dist/apis/addReaction.d.ts +0 -18
- package/node_modules/zca-js/dist/apis/addReaction.js +0 -294
- package/node_modules/zca-js/dist/apis/addUnreadMark.d.ts +0 -8
- package/node_modules/zca-js/dist/apis/addUnreadMark.js +0 -52
- package/node_modules/zca-js/dist/apis/addUserToGroup.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/addUserToGroup.js +0 -34
- package/node_modules/zca-js/dist/apis/blockUser.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/blockUser.js +0 -28
- package/node_modules/zca-js/dist/apis/blockViewFeed.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/blockViewFeed.js +0 -30
- package/node_modules/zca-js/dist/apis/changeAccountAvatar.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/changeAccountAvatar.js +0 -52
- package/node_modules/zca-js/dist/apis/changeFriendAlias.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/changeFriendAlias.js +0 -27
- package/node_modules/zca-js/dist/apis/changeGroupAvatar.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/changeGroupAvatar.js +0 -44
- package/node_modules/zca-js/dist/apis/changeGroupName.d.ts +0 -4
- package/node_modules/zca-js/dist/apis/changeGroupName.js +0 -32
- package/node_modules/zca-js/dist/apis/changeGroupOwner.d.ts +0 -4
- package/node_modules/zca-js/dist/apis/changeGroupOwner.js +0 -30
- package/node_modules/zca-js/dist/apis/createAutoReply.d.ts +0 -14
- package/node_modules/zca-js/dist/apis/createAutoReply.js +0 -37
- package/node_modules/zca-js/dist/apis/createBankAccount.d.ts +0 -8
- package/node_modules/zca-js/dist/apis/createBankAccount.js +0 -32
- package/node_modules/zca-js/dist/apis/createCatalog.d.ts +0 -7
- package/node_modules/zca-js/dist/apis/createCatalog.js +0 -29
- package/node_modules/zca-js/dist/apis/createGroup.d.ts +0 -28
- package/node_modules/zca-js/dist/apis/createGroup.js +0 -43
- package/node_modules/zca-js/dist/apis/createNote.d.ts +0 -7
- package/node_modules/zca-js/dist/apis/createNote.js +0 -47
- package/node_modules/zca-js/dist/apis/createPoll.d.ts +0 -36
- package/node_modules/zca-js/dist/apis/createPoll.js +0 -40
- package/node_modules/zca-js/dist/apis/createProductCatalog.d.ts +0 -23
- package/node_modules/zca-js/dist/apis/createProductCatalog.js +0 -50
- package/node_modules/zca-js/dist/apis/createReminder.d.ts +0 -12
- package/node_modules/zca-js/dist/apis/createReminder.js +0 -63
- package/node_modules/zca-js/dist/apis/custom.d.ts +0 -9
- package/node_modules/zca-js/dist/apis/custom.js +0 -15
- package/node_modules/zca-js/dist/apis/deleteAutoReply.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/deleteAutoReply.js +0 -29
- package/node_modules/zca-js/dist/apis/deleteAvatar.d.ts +0 -9
- package/node_modules/zca-js/dist/apis/deleteAvatar.js +0 -27
- package/node_modules/zca-js/dist/apis/deleteBankAccount.d.ts +0 -11
- package/node_modules/zca-js/dist/apis/deleteBankAccount.js +0 -32
- package/node_modules/zca-js/dist/apis/deleteCatalog.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/deleteCatalog.js +0 -28
- package/node_modules/zca-js/dist/apis/deleteChat.d.ts +0 -19
- package/node_modules/zca-js/dist/apis/deleteChat.js +0 -50
- package/node_modules/zca-js/dist/apis/deleteGroupInviteBox.d.ts +0 -9
- package/node_modules/zca-js/dist/apis/deleteGroupInviteBox.js +0 -27
- package/node_modules/zca-js/dist/apis/deleteMessage.d.ts +0 -14
- package/node_modules/zca-js/dist/apis/deleteMessage.js +0 -52
- package/node_modules/zca-js/dist/apis/deleteProductCatalog.d.ts +0 -10
- package/node_modules/zca-js/dist/apis/deleteProductCatalog.js +0 -31
- package/node_modules/zca-js/dist/apis/disableGroupLink.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/disableGroupLink.js +0 -24
- package/node_modules/zca-js/dist/apis/disperseGroup.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/disperseGroup.js +0 -28
- package/node_modules/zca-js/dist/apis/editNote.d.ts +0 -17
- package/node_modules/zca-js/dist/apis/editNote.js +0 -46
- package/node_modules/zca-js/dist/apis/editReminder.d.ts +0 -13
- package/node_modules/zca-js/dist/apis/editReminder.js +0 -61
- package/node_modules/zca-js/dist/apis/enableGroupLink.d.ts +0 -6
- package/node_modules/zca-js/dist/apis/enableGroupLink.js +0 -25
- package/node_modules/zca-js/dist/apis/fetchAccountInfo.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/fetchAccountInfo.js +0 -10
- package/node_modules/zca-js/dist/apis/findUser.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/findUser.js +0 -42
- package/node_modules/zca-js/dist/apis/findUserByUsername.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/findUserByUsername.js +0 -27
- package/node_modules/zca-js/dist/apis/forwardMessage.d.ts +0 -24
- package/node_modules/zca-js/dist/apis/forwardMessage.js +0 -114
- package/node_modules/zca-js/dist/apis/getAliasList.d.ts +0 -8
- package/node_modules/zca-js/dist/apis/getAliasList.js +0 -27
- package/node_modules/zca-js/dist/apis/getAllFriends.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/getAllFriends.js +0 -34
- package/node_modules/zca-js/dist/apis/getAllGroups.d.ts +0 -7
- package/node_modules/zca-js/dist/apis/getAllGroups.js +0 -10
- package/node_modules/zca-js/dist/apis/getArchivedChatList.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/getArchivedChatList.js +0 -23
- package/node_modules/zca-js/dist/apis/getAutoDeleteChat.d.ts +0 -9
- package/node_modules/zca-js/dist/apis/getAutoDeleteChat.js +0 -21
- package/node_modules/zca-js/dist/apis/getAutoReplyList.d.ts +0 -6
- package/node_modules/zca-js/dist/apis/getAutoReplyList.js +0 -24
- package/node_modules/zca-js/dist/apis/getAvatarList.d.ts +0 -12
- package/node_modules/zca-js/dist/apis/getAvatarList.js +0 -28
- package/node_modules/zca-js/dist/apis/getAvatarUrlProfile.d.ts +0 -7
- package/node_modules/zca-js/dist/apis/getAvatarUrlProfile.js +0 -30
- package/node_modules/zca-js/dist/apis/getBizAccount.d.ts +0 -24
- package/node_modules/zca-js/dist/apis/getBizAccount.js +0 -27
- package/node_modules/zca-js/dist/apis/getCatalogList.d.ts +0 -18
- package/node_modules/zca-js/dist/apis/getCatalogList.js +0 -32
- package/node_modules/zca-js/dist/apis/getCloseFriends.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/getCloseFriends.js +0 -20
- package/node_modules/zca-js/dist/apis/getContext.d.ts +0 -1
- package/node_modules/zca-js/dist/apis/getContext.js +0 -4
- package/node_modules/zca-js/dist/apis/getCookie.d.ts +0 -1
- package/node_modules/zca-js/dist/apis/getCookie.js +0 -9
- package/node_modules/zca-js/dist/apis/getFriendBoardList.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/getFriendBoardList.js +0 -26
- package/node_modules/zca-js/dist/apis/getFriendOnlines.d.ts +0 -10
- package/node_modules/zca-js/dist/apis/getFriendOnlines.js +0 -35
- package/node_modules/zca-js/dist/apis/getFriendRecommendations.d.ts +0 -42
- package/node_modules/zca-js/dist/apis/getFriendRecommendations.js +0 -27
- package/node_modules/zca-js/dist/apis/getFriendRequestStatus.d.ts +0 -8
- package/node_modules/zca-js/dist/apis/getFriendRequestStatus.js +0 -25
- package/node_modules/zca-js/dist/apis/getFullAvatar.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/getFullAvatar.js +0 -25
- package/node_modules/zca-js/dist/apis/getGroupBlockedMember.d.ts +0 -23
- package/node_modules/zca-js/dist/apis/getGroupBlockedMember.js +0 -29
- package/node_modules/zca-js/dist/apis/getGroupChatHistory.d.ts +0 -8
- package/node_modules/zca-js/dist/apis/getGroupChatHistory.js +0 -36
- package/node_modules/zca-js/dist/apis/getGroupInfo.d.ts +0 -16
- package/node_modules/zca-js/dist/apis/getGroupInfo.js +0 -32
- package/node_modules/zca-js/dist/apis/getGroupInviteBoxInfo.d.ts +0 -32
- package/node_modules/zca-js/dist/apis/getGroupInviteBoxInfo.js +0 -38
- package/node_modules/zca-js/dist/apis/getGroupInviteBoxList.d.ts +0 -38
- package/node_modules/zca-js/dist/apis/getGroupInviteBoxList.js +0 -31
- package/node_modules/zca-js/dist/apis/getGroupLinkDetail.d.ts +0 -9
- package/node_modules/zca-js/dist/apis/getGroupLinkDetail.js +0 -25
- package/node_modules/zca-js/dist/apis/getGroupLinkInfo.d.ts +0 -34
- package/node_modules/zca-js/dist/apis/getGroupLinkInfo.js +0 -28
- package/node_modules/zca-js/dist/apis/getGroupMembersInfo.d.ts +0 -17
- package/node_modules/zca-js/dist/apis/getGroupMembersInfo.js +0 -24
- package/node_modules/zca-js/dist/apis/getHiddenConversations.d.ts +0 -11
- package/node_modules/zca-js/dist/apis/getHiddenConversations.js +0 -23
- package/node_modules/zca-js/dist/apis/getLabels.d.ts +0 -7
- package/node_modules/zca-js/dist/apis/getLabels.js +0 -28
- package/node_modules/zca-js/dist/apis/getListBank.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/getListBank.js +0 -20
- package/node_modules/zca-js/dist/apis/getListBankAccount.d.ts +0 -7
- package/node_modules/zca-js/dist/apis/getListBankAccount.js +0 -27
- package/node_modules/zca-js/dist/apis/getListBoard.d.ts +0 -21
- package/node_modules/zca-js/dist/apis/getListBoard.js +0 -45
- package/node_modules/zca-js/dist/apis/getListDevice.d.ts +0 -10
- package/node_modules/zca-js/dist/apis/getListDevice.js +0 -22
- package/node_modules/zca-js/dist/apis/getListReminder.d.ts +0 -28
- package/node_modules/zca-js/dist/apis/getListReminder.js +0 -47
- package/node_modules/zca-js/dist/apis/getMultiUsersByPhones.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/getMultiUsersByPhones.js +0 -39
- package/node_modules/zca-js/dist/apis/getMute.d.ts +0 -13
- package/node_modules/zca-js/dist/apis/getMute.js +0 -22
- package/node_modules/zca-js/dist/apis/getOwnId.d.ts +0 -1
- package/node_modules/zca-js/dist/apis/getOwnId.js +0 -4
- package/node_modules/zca-js/dist/apis/getPendingGroupMembers.d.ts +0 -11
- package/node_modules/zca-js/dist/apis/getPendingGroupMembers.js +0 -27
- package/node_modules/zca-js/dist/apis/getPinConversations.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/getPinConversations.js +0 -22
- package/node_modules/zca-js/dist/apis/getPollDetail.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/getPollDetail.js +0 -30
- package/node_modules/zca-js/dist/apis/getProductCatalogList.d.ts +0 -20
- package/node_modules/zca-js/dist/apis/getProductCatalogList.js +0 -33
- package/node_modules/zca-js/dist/apis/getQR.d.ts +0 -4
- package/node_modules/zca-js/dist/apis/getQR.js +0 -29
- package/node_modules/zca-js/dist/apis/getQuickMessageList.d.ts +0 -7
- package/node_modules/zca-js/dist/apis/getQuickMessageList.js +0 -24
- package/node_modules/zca-js/dist/apis/getRelatedFriendGroup.d.ts +0 -6
- package/node_modules/zca-js/dist/apis/getRelatedFriendGroup.js +0 -30
- package/node_modules/zca-js/dist/apis/getReminder.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/getReminder.js +0 -25
- package/node_modules/zca-js/dist/apis/getReminderResponses.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/getReminderResponses.js +0 -24
- package/node_modules/zca-js/dist/apis/getSentFriendRequest.d.ts +0 -18
- package/node_modules/zca-js/dist/apis/getSentFriendRequest.js +0 -24
- package/node_modules/zca-js/dist/apis/getSettings.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/getSettings.js +0 -20
- package/node_modules/zca-js/dist/apis/getStickerCategoryDetail.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/getStickerCategoryDetail.js +0 -24
- package/node_modules/zca-js/dist/apis/getStickers.d.ts +0 -1
- package/node_modules/zca-js/dist/apis/getStickers.js +0 -40
- package/node_modules/zca-js/dist/apis/getStickersDetail.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/getStickersDetail.js +0 -40
- package/node_modules/zca-js/dist/apis/getUnreadMark.d.ts +0 -14
- package/node_modules/zca-js/dist/apis/getUnreadMark.js +0 -30
- package/node_modules/zca-js/dist/apis/getUserInfo.d.ts +0 -8
- package/node_modules/zca-js/dist/apis/getUserInfo.js +0 -44
- package/node_modules/zca-js/dist/apis/inviteUserToGroups.d.ts +0 -10
- package/node_modules/zca-js/dist/apis/inviteUserToGroups.js +0 -30
- package/node_modules/zca-js/dist/apis/joinGroupInviteBox.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/joinGroupInviteBox.js +0 -25
- package/node_modules/zca-js/dist/apis/joinGroupLink.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/joinGroupLink.js +0 -27
- package/node_modules/zca-js/dist/apis/keepAlive.d.ts +0 -4
- package/node_modules/zca-js/dist/apis/keepAlive.js +0 -22
- package/node_modules/zca-js/dist/apis/lastOnline.d.ts +0 -7
- package/node_modules/zca-js/dist/apis/lastOnline.js +0 -26
- package/node_modules/zca-js/dist/apis/leaveGroup.d.ts +0 -4
- package/node_modules/zca-js/dist/apis/leaveGroup.js +0 -33
- package/node_modules/zca-js/dist/apis/listen.d.ts +0 -102
- package/node_modules/zca-js/dist/apis/listen.js +0 -425
- package/node_modules/zca-js/dist/apis/lockPoll.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/lockPoll.js +0 -28
- package/node_modules/zca-js/dist/apis/login.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/login.js +0 -96
- package/node_modules/zca-js/dist/apis/loginQR.d.ts +0 -71
- package/node_modules/zca-js/dist/apis/loginQR.js +0 -376
- package/node_modules/zca-js/dist/apis/logoutV2.js +0 -79
- package/node_modules/zca-js/dist/apis/lostFocus.d.ts +0 -4
- package/node_modules/zca-js/dist/apis/lostFocus.js +0 -23
- package/node_modules/zca-js/dist/apis/parseLink.d.ts +0 -21
- package/node_modules/zca-js/dist/apis/parseLink.js +0 -27
- package/node_modules/zca-js/dist/apis/registerCatalog.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/registerCatalog.js +0 -27
- package/node_modules/zca-js/dist/apis/rejectFriendRequest.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/rejectFriendRequest.js +0 -27
- package/node_modules/zca-js/dist/apis/removeFriend.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/removeFriend.js +0 -28
- package/node_modules/zca-js/dist/apis/removeFriendAlias.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/removeFriendAlias.js +0 -24
- package/node_modules/zca-js/dist/apis/removeGroupBlockedMember.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/removeGroupBlockedMember.js +0 -28
- package/node_modules/zca-js/dist/apis/removeGroupDeputy.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/removeGroupDeputy.js +0 -30
- package/node_modules/zca-js/dist/apis/removeQuickMessage.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/removeQuickMessage.js +0 -27
- package/node_modules/zca-js/dist/apis/removeReminder.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/removeReminder.js +0 -40
- package/node_modules/zca-js/dist/apis/removeUnreadMark.d.ts +0 -8
- package/node_modules/zca-js/dist/apis/removeUnreadMark.js +0 -50
- package/node_modules/zca-js/dist/apis/removeUserFromGroup.d.ts +0 -4
- package/node_modules/zca-js/dist/apis/removeUserFromGroup.js +0 -34
- package/node_modules/zca-js/dist/apis/resetHiddenConversPin.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/resetHiddenConversPin.js +0 -20
- package/node_modules/zca-js/dist/apis/reuseAvatar.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/reuseAvatar.js +0 -26
- package/node_modules/zca-js/dist/apis/reviewPendingMemberRequest.d.ts +0 -14
- package/node_modules/zca-js/dist/apis/reviewPendingMemberRequest.js +0 -38
- package/node_modules/zca-js/dist/apis/scanURL.d.ts +0 -4
- package/node_modules/zca-js/dist/apis/scanURL.js +0 -28
- package/node_modules/zca-js/dist/apis/searchSticker.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/searchSticker.js +0 -28
- package/node_modules/zca-js/dist/apis/sendBankCard.d.ts +0 -9
- package/node_modules/zca-js/dist/apis/sendBankCard.js +0 -53
- package/node_modules/zca-js/dist/apis/sendCard.d.ts +0 -10
- package/node_modules/zca-js/dist/apis/sendCard.js +0 -75
- package/node_modules/zca-js/dist/apis/sendDeliveredEvent.d.ts +0 -16
- package/node_modules/zca-js/dist/apis/sendDeliveredEvent.js +0 -55
- package/node_modules/zca-js/dist/apis/sendFriendRequest.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/sendFriendRequest.js +0 -39
- package/node_modules/zca-js/dist/apis/sendLink.d.ts +0 -10
- package/node_modules/zca-js/dist/apis/sendLink.js +0 -78
- package/node_modules/zca-js/dist/apis/sendMessage.d.ts +0 -105
- package/node_modules/zca-js/dist/apis/sendMessage.js +0 -486
- package/node_modules/zca-js/dist/apis/sendReport.d.ts +0 -17
- package/node_modules/zca-js/dist/apis/sendReport.js +0 -53
- package/node_modules/zca-js/dist/apis/sendSeenEvent.d.ts +0 -16
- package/node_modules/zca-js/dist/apis/sendSeenEvent.js +0 -63
- package/node_modules/zca-js/dist/apis/sendSticker.d.ts +0 -10
- package/node_modules/zca-js/dist/apis/sendSticker.js +0 -74
- package/node_modules/zca-js/dist/apis/sendTypingEvent.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/sendTypingEvent.js +0 -33
- package/node_modules/zca-js/dist/apis/sendVideo.d.ts +0 -35
- package/node_modules/zca-js/dist/apis/sendVideo.js +0 -134
- package/node_modules/zca-js/dist/apis/sendVoice.d.ts +0 -12
- package/node_modules/zca-js/dist/apis/sendVoice.js +0 -89
- package/node_modules/zca-js/dist/apis/setHiddenConversations.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/setHiddenConversations.js +0 -39
- package/node_modules/zca-js/dist/apis/setMute.d.ts +0 -20
- package/node_modules/zca-js/dist/apis/setMute.js +0 -67
- package/node_modules/zca-js/dist/apis/setPinnedConversations.d.ts +0 -3
- package/node_modules/zca-js/dist/apis/setPinnedConversations.js +0 -34
- package/node_modules/zca-js/dist/apis/sharePoll.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/sharePoll.js +0 -28
- package/node_modules/zca-js/dist/apis/unblockUser.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/unblockUser.js +0 -28
- package/node_modules/zca-js/dist/apis/undo.d.ts +0 -9
- package/node_modules/zca-js/dist/apis/undo.js +0 -42
- package/node_modules/zca-js/dist/apis/undoFriendRequest.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/undoFriendRequest.js +0 -27
- package/node_modules/zca-js/dist/apis/updateActiveStatus.d.ts +0 -4
- package/node_modules/zca-js/dist/apis/updateActiveStatus.js +0 -27
- package/node_modules/zca-js/dist/apis/updateArchivedChatList.d.ts +0 -10
- package/node_modules/zca-js/dist/apis/updateArchivedChatList.js +0 -34
- package/node_modules/zca-js/dist/apis/updateAutoDeleteChat.d.ts +0 -9
- package/node_modules/zca-js/dist/apis/updateAutoDeleteChat.js +0 -40
- package/node_modules/zca-js/dist/apis/updateAutoReply.d.ts +0 -15
- package/node_modules/zca-js/dist/apis/updateAutoReply.js +0 -38
- package/node_modules/zca-js/dist/apis/updateBankAccount.d.ts +0 -9
- package/node_modules/zca-js/dist/apis/updateBankAccount.js +0 -31
- package/node_modules/zca-js/dist/apis/updateCatalog.d.ts +0 -11
- package/node_modules/zca-js/dist/apis/updateCatalog.js +0 -30
- package/node_modules/zca-js/dist/apis/updateGroupSettings.d.ts +0 -40
- package/node_modules/zca-js/dist/apis/updateGroupSettings.js +0 -43
- package/node_modules/zca-js/dist/apis/updateHiddenConversPin.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/updateHiddenConversPin.js +0 -30
- package/node_modules/zca-js/dist/apis/updateLabels.d.ts +0 -15
- package/node_modules/zca-js/dist/apis/updateLabels.js +0 -34
- package/node_modules/zca-js/dist/apis/updateLang.d.ts +0 -6
- package/node_modules/zca-js/dist/apis/updateLang.js +0 -30
- package/node_modules/zca-js/dist/apis/updateProductCatalog.d.ts +0 -25
- package/node_modules/zca-js/dist/apis/updateProductCatalog.js +0 -51
- package/node_modules/zca-js/dist/apis/updateProfile.d.ts +0 -20
- package/node_modules/zca-js/dist/apis/updateProfile.js +0 -43
- package/node_modules/zca-js/dist/apis/updateProfileBio.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/updateProfileBio.js +0 -27
- package/node_modules/zca-js/dist/apis/updateQuickMessage.d.ts +0 -11
- package/node_modules/zca-js/dist/apis/updateQuickMessage.js +0 -61
- package/node_modules/zca-js/dist/apis/updateSettings.d.ts +0 -16
- package/node_modules/zca-js/dist/apis/updateSettings.js +0 -90
- package/node_modules/zca-js/dist/apis/upgradeGroupToCommunity.d.ts +0 -2
- package/node_modules/zca-js/dist/apis/upgradeGroupToCommunity.js +0 -27
- package/node_modules/zca-js/dist/apis/uploadAttachment.d.ts +0 -50
- package/node_modules/zca-js/dist/apis/uploadAttachment.js +0 -197
- package/node_modules/zca-js/dist/apis/uploadProductPhoto.d.ts +0 -14
- package/node_modules/zca-js/dist/apis/uploadProductPhoto.js +0 -50
- package/node_modules/zca-js/dist/apis/votePoll.d.ts +0 -5
- package/node_modules/zca-js/dist/apis/votePoll.js +0 -29
- package/node_modules/zca-js/dist/apis.d.ts +0 -317
- package/node_modules/zca-js/dist/apis.js +0 -319
- package/node_modules/zca-js/dist/cjs/Errors/ZaloApiError.cjs +0 -11
- package/node_modules/zca-js/dist/cjs/Errors/ZaloApiLoginQRAborted.cjs +0 -12
- package/node_modules/zca-js/dist/cjs/Errors/ZaloApiLoginQRDeclined.cjs +0 -12
- package/node_modules/zca-js/dist/cjs/Errors/ZaloApiMissingImageMetadataGetter.cjs +0 -12
- package/node_modules/zca-js/dist/cjs/apis/acceptFriendRequest.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/addGroupBlockedMember.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/addGroupDeputy.cjs +0 -35
- package/node_modules/zca-js/dist/cjs/apis/addPollOptions.cjs +0 -31
- package/node_modules/zca-js/dist/cjs/apis/addQuickMessage.cjs +0 -65
- package/node_modules/zca-js/dist/cjs/apis/addReaction.cjs +0 -308
- package/node_modules/zca-js/dist/cjs/apis/addUnreadMark.cjs +0 -66
- package/node_modules/zca-js/dist/cjs/apis/addUserToGroup.cjs +0 -39
- package/node_modules/zca-js/dist/cjs/apis/blockUser.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/blockViewFeed.cjs +0 -35
- package/node_modules/zca-js/dist/cjs/apis/changeAccountAvatar.cjs +0 -57
- package/node_modules/zca-js/dist/cjs/apis/changeFriendAlias.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/changeGroupAvatar.cjs +0 -49
- package/node_modules/zca-js/dist/cjs/apis/changeGroupName.cjs +0 -37
- package/node_modules/zca-js/dist/cjs/apis/changeGroupOwner.cjs +0 -35
- package/node_modules/zca-js/dist/cjs/apis/createAutoReply.cjs +0 -42
- package/node_modules/zca-js/dist/cjs/apis/createBankAccount.cjs +0 -37
- package/node_modules/zca-js/dist/cjs/apis/createCatalog.cjs +0 -34
- package/node_modules/zca-js/dist/cjs/apis/createGroup.cjs +0 -48
- package/node_modules/zca-js/dist/cjs/apis/createNote.cjs +0 -52
- package/node_modules/zca-js/dist/cjs/apis/createPoll.cjs +0 -45
- package/node_modules/zca-js/dist/cjs/apis/createProductCatalog.cjs +0 -55
- package/node_modules/zca-js/dist/cjs/apis/createReminder.cjs +0 -77
- package/node_modules/zca-js/dist/cjs/apis/custom.cjs +0 -19
- package/node_modules/zca-js/dist/cjs/apis/deleteAutoReply.cjs +0 -34
- package/node_modules/zca-js/dist/cjs/apis/deleteAvatar.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/deleteBankAccount.cjs +0 -37
- package/node_modules/zca-js/dist/cjs/apis/deleteCatalog.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/deleteChat.cjs +0 -64
- package/node_modules/zca-js/dist/cjs/apis/deleteGroupInviteBox.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/deleteMessage.cjs +0 -66
- package/node_modules/zca-js/dist/cjs/apis/deleteProductCatalog.cjs +0 -36
- package/node_modules/zca-js/dist/cjs/apis/disableGroupLink.cjs +0 -29
- package/node_modules/zca-js/dist/cjs/apis/disperseGroup.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/editNote.cjs +0 -51
- package/node_modules/zca-js/dist/cjs/apis/editReminder.cjs +0 -75
- package/node_modules/zca-js/dist/cjs/apis/enableGroupLink.cjs +0 -30
- package/node_modules/zca-js/dist/cjs/apis/fetchAccountInfo.cjs +0 -15
- package/node_modules/zca-js/dist/cjs/apis/findUser.cjs +0 -56
- package/node_modules/zca-js/dist/cjs/apis/findUserByUsername.cjs +0 -41
- package/node_modules/zca-js/dist/cjs/apis/forwardMessage.cjs +0 -129
- package/node_modules/zca-js/dist/cjs/apis/getAliasList.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/getAllFriends.cjs +0 -48
- package/node_modules/zca-js/dist/cjs/apis/getAllGroups.cjs +0 -15
- package/node_modules/zca-js/dist/cjs/apis/getArchivedChatList.cjs +0 -28
- package/node_modules/zca-js/dist/cjs/apis/getAutoDeleteChat.cjs +0 -26
- package/node_modules/zca-js/dist/cjs/apis/getAutoReplyList.cjs +0 -29
- package/node_modules/zca-js/dist/cjs/apis/getAvatarList.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/getAvatarUrlProfile.cjs +0 -44
- package/node_modules/zca-js/dist/cjs/apis/getBizAccount.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/getCatalogList.cjs +0 -37
- package/node_modules/zca-js/dist/cjs/apis/getCloseFriends.cjs +0 -25
- package/node_modules/zca-js/dist/cjs/apis/getContext.cjs +0 -9
- package/node_modules/zca-js/dist/cjs/apis/getCookie.cjs +0 -14
- package/node_modules/zca-js/dist/cjs/apis/getFriendBoardList.cjs +0 -31
- package/node_modules/zca-js/dist/cjs/apis/getFriendOnlines.cjs +0 -40
- package/node_modules/zca-js/dist/cjs/apis/getFriendRecommendations.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/getFriendRequestStatus.cjs +0 -30
- package/node_modules/zca-js/dist/cjs/apis/getFullAvatar.cjs +0 -30
- package/node_modules/zca-js/dist/cjs/apis/getGroupBlockedMember.cjs +0 -34
- package/node_modules/zca-js/dist/cjs/apis/getGroupChatHistory.cjs +0 -51
- package/node_modules/zca-js/dist/cjs/apis/getGroupInfo.cjs +0 -37
- package/node_modules/zca-js/dist/cjs/apis/getGroupInviteBoxInfo.cjs +0 -43
- package/node_modules/zca-js/dist/cjs/apis/getGroupInviteBoxList.cjs +0 -36
- package/node_modules/zca-js/dist/cjs/apis/getGroupLinkDetail.cjs +0 -30
- package/node_modules/zca-js/dist/cjs/apis/getGroupLinkInfo.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/getGroupMembersInfo.cjs +0 -29
- package/node_modules/zca-js/dist/cjs/apis/getHiddenConversations.cjs +0 -28
- package/node_modules/zca-js/dist/cjs/apis/getLabels.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/getListBank.cjs +0 -25
- package/node_modules/zca-js/dist/cjs/apis/getListBankAccount.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/getListBoard.cjs +0 -59
- package/node_modules/zca-js/dist/cjs/apis/getListDevice.cjs +0 -27
- package/node_modules/zca-js/dist/cjs/apis/getListReminder.cjs +0 -61
- package/node_modules/zca-js/dist/cjs/apis/getMultiUsersByPhones.cjs +0 -53
- package/node_modules/zca-js/dist/cjs/apis/getMute.cjs +0 -27
- package/node_modules/zca-js/dist/cjs/apis/getOwnId.cjs +0 -9
- package/node_modules/zca-js/dist/cjs/apis/getPendingGroupMembers.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/getPinConversations.cjs +0 -27
- package/node_modules/zca-js/dist/cjs/apis/getPollDetail.cjs +0 -35
- package/node_modules/zca-js/dist/cjs/apis/getProductCatalogList.cjs +0 -38
- package/node_modules/zca-js/dist/cjs/apis/getQR.cjs +0 -34
- package/node_modules/zca-js/dist/cjs/apis/getQuickMessageList.cjs +0 -29
- package/node_modules/zca-js/dist/cjs/apis/getRelatedFriendGroup.cjs +0 -35
- package/node_modules/zca-js/dist/cjs/apis/getReminder.cjs +0 -30
- package/node_modules/zca-js/dist/cjs/apis/getReminderResponses.cjs +0 -29
- package/node_modules/zca-js/dist/cjs/apis/getSentFriendRequest.cjs +0 -29
- package/node_modules/zca-js/dist/cjs/apis/getSettings.cjs +0 -25
- package/node_modules/zca-js/dist/cjs/apis/getStickerCategoryDetail.cjs +0 -29
- package/node_modules/zca-js/dist/cjs/apis/getStickers.cjs +0 -45
- package/node_modules/zca-js/dist/cjs/apis/getStickersDetail.cjs +0 -45
- package/node_modules/zca-js/dist/cjs/apis/getUnreadMark.cjs +0 -35
- package/node_modules/zca-js/dist/cjs/apis/getUserInfo.cjs +0 -58
- package/node_modules/zca-js/dist/cjs/apis/inviteUserToGroups.cjs +0 -35
- package/node_modules/zca-js/dist/cjs/apis/joinGroupInviteBox.cjs +0 -30
- package/node_modules/zca-js/dist/cjs/apis/joinGroupLink.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/keepAlive.cjs +0 -27
- package/node_modules/zca-js/dist/cjs/apis/lastOnline.cjs +0 -31
- package/node_modules/zca-js/dist/cjs/apis/leaveGroup.cjs +0 -38
- package/node_modules/zca-js/dist/cjs/apis/listen.cjs +0 -440
- package/node_modules/zca-js/dist/cjs/apis/lockPoll.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/login.cjs +0 -102
- package/node_modules/zca-js/dist/cjs/apis/loginQR.cjs +0 -368
- package/node_modules/zca-js/dist/cjs/apis/logoutV2.cjs +0 -83
- package/node_modules/zca-js/dist/cjs/apis/lostFocus.cjs +0 -28
- package/node_modules/zca-js/dist/cjs/apis/parseLink.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/registerCatalog.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/rejectFriendRequest.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/removeFriend.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/removeFriendAlias.cjs +0 -29
- package/node_modules/zca-js/dist/cjs/apis/removeGroupBlockedMember.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/removeGroupDeputy.cjs +0 -35
- package/node_modules/zca-js/dist/cjs/apis/removeQuickMessage.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/removeReminder.cjs +0 -54
- package/node_modules/zca-js/dist/cjs/apis/removeUnreadMark.cjs +0 -64
- package/node_modules/zca-js/dist/cjs/apis/removeUserFromGroup.cjs +0 -39
- package/node_modules/zca-js/dist/cjs/apis/resetHiddenConversPin.cjs +0 -25
- package/node_modules/zca-js/dist/cjs/apis/reuseAvatar.cjs +0 -31
- package/node_modules/zca-js/dist/cjs/apis/reviewPendingMemberRequest.cjs +0 -43
- package/node_modules/zca-js/dist/cjs/apis/scanURL.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/searchSticker.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/sendBankCard.cjs +0 -68
- package/node_modules/zca-js/dist/cjs/apis/sendCard.cjs +0 -89
- package/node_modules/zca-js/dist/cjs/apis/sendDeliveredEvent.cjs +0 -69
- package/node_modules/zca-js/dist/cjs/apis/sendFriendRequest.cjs +0 -44
- package/node_modules/zca-js/dist/cjs/apis/sendLink.cjs +0 -92
- package/node_modules/zca-js/dist/cjs/apis/sendMessage.cjs +0 -500
- package/node_modules/zca-js/dist/cjs/apis/sendReport.cjs +0 -67
- package/node_modules/zca-js/dist/cjs/apis/sendSeenEvent.cjs +0 -77
- package/node_modules/zca-js/dist/cjs/apis/sendSticker.cjs +0 -88
- package/node_modules/zca-js/dist/cjs/apis/sendTypingEvent.cjs +0 -47
- package/node_modules/zca-js/dist/cjs/apis/sendVideo.cjs +0 -148
- package/node_modules/zca-js/dist/cjs/apis/sendVoice.cjs +0 -103
- package/node_modules/zca-js/dist/cjs/apis/setHiddenConversations.cjs +0 -53
- package/node_modules/zca-js/dist/cjs/apis/setMute.cjs +0 -81
- package/node_modules/zca-js/dist/cjs/apis/setPinnedConversations.cjs +0 -48
- package/node_modules/zca-js/dist/cjs/apis/sharePoll.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/unblockUser.cjs +0 -33
- package/node_modules/zca-js/dist/cjs/apis/undo.cjs +0 -56
- package/node_modules/zca-js/dist/cjs/apis/undoFriendRequest.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/updateActiveStatus.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/updateArchivedChatList.cjs +0 -39
- package/node_modules/zca-js/dist/cjs/apis/updateAutoDeleteChat.cjs +0 -54
- package/node_modules/zca-js/dist/cjs/apis/updateAutoReply.cjs +0 -43
- package/node_modules/zca-js/dist/cjs/apis/updateBankAccount.cjs +0 -36
- package/node_modules/zca-js/dist/cjs/apis/updateCatalog.cjs +0 -35
- package/node_modules/zca-js/dist/cjs/apis/updateGroupSettings.cjs +0 -48
- package/node_modules/zca-js/dist/cjs/apis/updateHiddenConversPin.cjs +0 -35
- package/node_modules/zca-js/dist/cjs/apis/updateLabels.cjs +0 -39
- package/node_modules/zca-js/dist/cjs/apis/updateLang.cjs +0 -35
- package/node_modules/zca-js/dist/cjs/apis/updateProductCatalog.cjs +0 -56
- package/node_modules/zca-js/dist/cjs/apis/updateProfile.cjs +0 -48
- package/node_modules/zca-js/dist/cjs/apis/updateProfileBio.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/updateQuickMessage.cjs +0 -66
- package/node_modules/zca-js/dist/cjs/apis/updateSettings.cjs +0 -95
- package/node_modules/zca-js/dist/cjs/apis/upgradeGroupToCommunity.cjs +0 -32
- package/node_modules/zca-js/dist/cjs/apis/uploadAttachment.cjs +0 -211
- package/node_modules/zca-js/dist/cjs/apis/uploadProductPhoto.cjs +0 -55
- package/node_modules/zca-js/dist/cjs/apis/votePoll.cjs +0 -34
- package/node_modules/zca-js/dist/cjs/apis.cjs +0 -324
- package/node_modules/zca-js/dist/cjs/context.cjs +0 -34
- package/node_modules/zca-js/dist/cjs/index.cjs +0 -159
- package/node_modules/zca-js/dist/cjs/models/AutoReply.cjs +0 -9
- package/node_modules/zca-js/dist/cjs/models/Bank.cjs +0 -263
- package/node_modules/zca-js/dist/cjs/models/Board.cjs +0 -8
- package/node_modules/zca-js/dist/cjs/models/DeliveredMessage.cjs +0 -23
- package/node_modules/zca-js/dist/cjs/models/Enum.cjs +0 -27
- package/node_modules/zca-js/dist/cjs/models/FriendEvent.cjs +0 -87
- package/node_modules/zca-js/dist/cjs/models/Group.cjs +0 -13
- package/node_modules/zca-js/dist/cjs/models/GroupEvent.cjs +0 -94
- package/node_modules/zca-js/dist/cjs/models/Message.cjs +0 -35
- package/node_modules/zca-js/dist/cjs/models/Reaction.cjs +0 -74
- package/node_modules/zca-js/dist/cjs/models/Reminder.cjs +0 -9
- package/node_modules/zca-js/dist/cjs/models/SeenMessage.cjs +0 -23
- package/node_modules/zca-js/dist/cjs/models/Typing.cjs +0 -23
- package/node_modules/zca-js/dist/cjs/models/Undo.cjs +0 -16
- package/node_modules/zca-js/dist/cjs/models/ZBusiness.cjs +0 -39
- package/node_modules/zca-js/dist/cjs/update.cjs +0 -34
- package/node_modules/zca-js/dist/cjs/utils.cjs +0 -703
- package/node_modules/zca-js/dist/cjs/zalo.cjs +0 -112
- package/node_modules/zca-js/dist/context.d.ts +0 -179
- package/node_modules/zca-js/dist/context.js +0 -28
- package/node_modules/zca-js/dist/index.d.ts +0 -166
- package/node_modules/zca-js/dist/index.js +0 -14
- package/node_modules/zca-js/dist/models/Attachment.d.ts +0 -9
- package/node_modules/zca-js/dist/models/Attachment.js +0 -1
- package/node_modules/zca-js/dist/models/AutoReply.d.ts +0 -20
- package/node_modules/zca-js/dist/models/AutoReply.js +0 -7
- package/node_modules/zca-js/dist/models/Bank.d.ts +0 -291
- package/node_modules/zca-js/dist/models/Bank.js +0 -262
- package/node_modules/zca-js/dist/models/Board.d.ts +0 -60
- package/node_modules/zca-js/dist/models/Board.js +0 -6
- package/node_modules/zca-js/dist/models/Catalog.d.ts +0 -16
- package/node_modules/zca-js/dist/models/Catalog.js +0 -1
- package/node_modules/zca-js/dist/models/DeliveredMessage.d.ts +0 -27
- package/node_modules/zca-js/dist/models/DeliveredMessage.js +0 -17
- package/node_modules/zca-js/dist/models/Enum.d.ts +0 -21
- package/node_modules/zca-js/dist/models/Enum.js +0 -25
- package/node_modules/zca-js/dist/models/FriendEvent.d.ts +0 -107
- package/node_modules/zca-js/dist/models/FriendEvent.js +0 -83
- package/node_modules/zca-js/dist/models/Group.d.ts +0 -125
- package/node_modules/zca-js/dist/models/Group.js +0 -11
- package/node_modules/zca-js/dist/models/GroupEvent.d.ts +0 -178
- package/node_modules/zca-js/dist/models/GroupEvent.js +0 -90
- package/node_modules/zca-js/dist/models/Label.d.ts +0 -10
- package/node_modules/zca-js/dist/models/Label.js +0 -1
- package/node_modules/zca-js/dist/models/Message.d.ts +0 -91
- package/node_modules/zca-js/dist/models/Message.js +0 -29
- package/node_modules/zca-js/dist/models/ProductCatalog.d.ts +0 -17
- package/node_modules/zca-js/dist/models/ProductCatalog.js +0 -1
- package/node_modules/zca-js/dist/models/QuickMessage.d.ts +0 -25
- package/node_modules/zca-js/dist/models/QuickMessage.js +0 -1
- package/node_modules/zca-js/dist/models/Reaction.d.ts +0 -85
- package/node_modules/zca-js/dist/models/Reaction.js +0 -70
- package/node_modules/zca-js/dist/models/Reminder.d.ts +0 -51
- package/node_modules/zca-js/dist/models/Reminder.js +0 -7
- package/node_modules/zca-js/dist/models/SeenMessage.d.ts +0 -26
- package/node_modules/zca-js/dist/models/SeenMessage.js +0 -17
- package/node_modules/zca-js/dist/models/Sticker.d.ts +0 -27
- package/node_modules/zca-js/dist/models/Sticker.js +0 -1
- package/node_modules/zca-js/dist/models/Typing.d.ts +0 -24
- package/node_modules/zca-js/dist/models/Typing.js +0 -17
- package/node_modules/zca-js/dist/models/Undo.d.ts +0 -34
- package/node_modules/zca-js/dist/models/Undo.js +0 -12
- package/node_modules/zca-js/dist/models/User.d.ts +0 -70
- package/node_modules/zca-js/dist/models/User.js +0 -1
- package/node_modules/zca-js/dist/models/ZBusiness.d.ts +0 -22
- package/node_modules/zca-js/dist/models/ZBusiness.js +0 -35
- package/node_modules/zca-js/dist/models/index.d.ts +0 -22
- package/node_modules/zca-js/dist/models/index.js +0 -22
- package/node_modules/zca-js/dist/update.d.ts +0 -2
- package/node_modules/zca-js/dist/update.js +0 -29
- package/node_modules/zca-js/dist/utils.d.ts +0 -167
- package/node_modules/zca-js/dist/utils.js +0 -719
- package/node_modules/zca-js/dist/zalo.d.ts +0 -41
- package/node_modules/zca-js/dist/zalo.js +0 -107
- package/node_modules/zca-js/eslint.config.js +0 -21
- package/node_modules/zca-js/index.d.ts +0 -2
- package/node_modules/zca-js/package.json +0 -78
- package/node_modules/zca-js/rollup.config.js +0 -28
- package/patches/zca-js+2.2.0.patch +0 -1445
- package/src/cli.test.js +0 -127
- package/src/core/forward.js +0 -112
- package/src/core/group-history.js +0 -248
- package/src/core/group-invite.js +0 -53
- package/src/core/offline-queue.js +0 -194
- package/src/core/pin.js +0 -222
- package/src/core/socket-tap.js +0 -154
- package/src/core/sync-v2/assets.js +0 -181
- package/src/core/sync-v2/gid.js +0 -106
- package/src/core/sync-v2/keepalive.js +0 -177
- package/src/core/sync-v2/message-types.js +0 -522
- package/src/core/sync-v2/renewlink.js +0 -124
- package/src/core/sync-v2/zcloud-cipher.js +0 -88
- package/src/core/zca-custom.js +0 -78
- package/src/mcp/message-buffer.test.js +0 -360
- package/src/mcp/notifier.test.js +0 -275
- package/src/mcp/thread-filter.test.js +0 -206
- package/src/mcp/thread-name-cache.test.js +0 -142
- package/src/utils/atomic-file.js +0 -209
- package/src/utils/bank-helpers.test.js +0 -66
- package/src/utils/device-fingerprint.js +0 -72
- package/src/utils/mentions.js +0 -140
- package/src/utils/proxy-helpers.test.js +0 -36
- package/src/utils/split-message.js +0 -166
- package/src/utils/urgency.js +0 -29
- /package/src/{core → zalo/custom}/user-info.js +0 -0
- /package/src/{utils → zalo/format}/extract-message-text.js +0 -0
- /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
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
64
|
-
--
|
|
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
|
|
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
|
|
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
|
-
|
|
306
|
-
|
|
307
|
-
"
|
|
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).
|
|
556
|
-
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
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
|
-
*
|
|
623
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
673
|
-
*
|
|
674
|
-
*
|
|
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 {
|
|
678
|
-
* @param {
|
|
679
|
-
* @param {
|
|
680
|
-
* @
|
|
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
|
|
1166
|
+
export function backfillTextNorm({ chunk = 5000, maxRows = Infinity, onProgress } = {}) {
|
|
686
1167
|
if (!db) throw new Error("Database not initialized");
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
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
|
-
|
|
708
|
-
|
|
709
|
-
.
|
|
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
|
-
*
|
|
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 =
|
|
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,
|
|
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(
|
|
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=
|
|
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 =
|
|
1601
|
+
export function getThreadNames(limit = null) {
|
|
826
1602
|
const map = new Map();
|
|
827
1603
|
try {
|
|
828
1604
|
for (const t of getRecentThreads(limit)) {
|
|
829
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
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:
|
|
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".
|
|
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
|
|