@ardennguyen/zalo-agent-cli 2.5.9 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 -222
- 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/mcp/mcp-tools.js
CHANGED
|
@@ -1,32 +1,57 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP tool registrations for Zalo message access, sending, user lookup, and group productivity.
|
|
3
|
-
* Registers
|
|
3
|
+
* Registers 36 tools: zalo_get_messages, zalo_get_history, zalo_send_message, zalo_list_threads,
|
|
4
4
|
* zalo_search_threads, zalo_mark_read, zalo_view_media, zalo_react, zalo_undo, zalo_get_group_members,
|
|
5
5
|
* zalo_list_conversations, zalo_coverage, zalo_sync, zalo_sync_status, zalo_search_messages,
|
|
6
6
|
* zalo_lookup_user, zalo_forward_message, zalo_delete_message, zalo_reminder, zalo_note, zalo_poll,
|
|
7
|
-
* zalo_wait_for_message, zalo_label, zalo_friend, zalo_group
|
|
7
|
+
* zalo_wait_for_message, zalo_label, zalo_friend, zalo_group, zalo_read, zalo_write, and the action tools
|
|
8
|
+
* zalo_conversation, zalo_profile, zalo_auto_reply, zalo_quick_message, zalo_catalog, zalo_bank, zalo_cloud,
|
|
9
|
+
* zalo_sticker and zalo_link (their action tables are src/mcp/actions-*.js, run by src/mcp/action-tool.js), and
|
|
10
|
+
* zalo_official, which runs the official-API commands (src/mcp/official-tool.js).
|
|
11
|
+
* Every CLI command has an action here, or a reason it has none; tests/unit/mcp-cli-parity.test.js holds the map.
|
|
8
12
|
*
|
|
9
13
|
* A tool that mirrors a CLI command calls the same code the command does (src/core/cached-message.js,
|
|
10
14
|
* forward.js, pin.js, group-members.js, recent-conversations.js, src/utils/my-documents.js, urgency.js),
|
|
11
15
|
* so the two cannot drift apart.
|
|
12
16
|
*/
|
|
13
17
|
|
|
14
|
-
import { existsSync } from "node:fs";
|
|
18
|
+
import { existsSync, unlinkSync } from "node:fs";
|
|
15
19
|
import { resolve } from "node:path";
|
|
16
20
|
import { z } from "zod";
|
|
21
|
+
import { officialMeta, officialTool } from "./official-tool.js";
|
|
17
22
|
import { openFile } from "../utils/open-file.js";
|
|
18
23
|
import {
|
|
19
24
|
getMessages,
|
|
25
|
+
getMessagesInRange,
|
|
26
|
+
getAllMessagesInRange,
|
|
20
27
|
getMessageById,
|
|
21
|
-
|
|
28
|
+
getMessageForAction,
|
|
22
29
|
getDisplayName,
|
|
30
|
+
getStoredName,
|
|
31
|
+
setContactName,
|
|
23
32
|
getThreadType,
|
|
24
33
|
getThreadNames,
|
|
25
34
|
getConvState,
|
|
26
35
|
getReadStates,
|
|
27
36
|
} from "../core/db.js";
|
|
28
|
-
import {
|
|
37
|
+
import { searchPage } from "../core/search.js";
|
|
38
|
+
import { parsePeriod } from "../utils/date-range.js";
|
|
39
|
+
import { downloadSyncedMedia, DOWNLOADABLE_KINDS } from "../core/sync-v2/media.js";
|
|
40
|
+
import { mediaPlainSize } from "../core/keystore/media-seal.js";
|
|
41
|
+
import { scopeOfDir } from "../core/keystore/keyring.js";
|
|
42
|
+
import { getAccountDir } from "../core/credentials.js";
|
|
43
|
+
import {
|
|
44
|
+
chooseDelivery,
|
|
45
|
+
decryptToTempfile,
|
|
46
|
+
deliverCachedMedia,
|
|
47
|
+
inlineContent,
|
|
48
|
+
mediaInfo,
|
|
49
|
+
removeMediaTemp,
|
|
50
|
+
} from "../core/media-deliver.js";
|
|
51
|
+
import { ensureMediaServed } from "../core/media-route.js";
|
|
29
52
|
import { describeZaloError } from "../core/sync-v2/board.js";
|
|
53
|
+
import { boardPage, groupReminderPage } from "../zalo/api/boards.js";
|
|
54
|
+
import { allAliases, allBoardItems, allReminders } from "../core/list-all.js";
|
|
30
55
|
import { fetchAndCacheHistory } from "../core/history-fetch.js";
|
|
31
56
|
import {
|
|
32
57
|
cachedCliMsgId,
|
|
@@ -35,42 +60,90 @@ import {
|
|
|
35
60
|
cachedMessageById,
|
|
36
61
|
reactionCliMsgId,
|
|
37
62
|
recallCliMsgId,
|
|
63
|
+
quotedReply,
|
|
64
|
+
cachedReplyTo,
|
|
65
|
+
resolveReplyTo,
|
|
38
66
|
} from "../core/cached-message.js";
|
|
39
|
-
import {
|
|
40
|
-
|
|
67
|
+
import {
|
|
68
|
+
buildForwardReference,
|
|
69
|
+
sendForward,
|
|
70
|
+
LOG_SRC_TYPE,
|
|
71
|
+
videoResendOptions,
|
|
72
|
+
voiceResendOptions,
|
|
73
|
+
} from "../zalo/custom/forward.js";
|
|
74
|
+
import { undoPayload } from "../zalo/custom/group-visibility.js";
|
|
75
|
+
import { pinMessage, unpinMessage, textPinParams } from "../zalo/custom/pin.js";
|
|
41
76
|
import { coverageReport } from "../core/coverage.js";
|
|
42
77
|
import { groupMemberUids, fetchMemberNames } from "../core/group-members.js";
|
|
78
|
+
import { getGroupInfoWatched, recordOwnExit, goneFields, goneGroupMap, sendRefusal } from "../core/group-exit.js";
|
|
79
|
+
import { departureMessage, planLeave, runLeave } from "../core/group-departure.js";
|
|
80
|
+
import { mutualGroupsOrError } from "../core/mutual-groups.js";
|
|
43
81
|
import { recentConversations } from "../core/recent-conversations.js";
|
|
82
|
+
import { callReadAll, describeReads, READ_NAMES, ReadUsageError } from "../zalo/reads.js";
|
|
83
|
+
import "../core/local-reads.js";
|
|
84
|
+
import { buildWrite, callWrite, describeWrites, WRITE_NAMES, WRITES } from "../zalo/writes.js";
|
|
44
85
|
import { describeReadState, readOnZalo } from "../core/read-state.js";
|
|
45
|
-
import { extractMessageText } from "../
|
|
46
|
-
import { expandMentions, shiftStyles, ALL_MENTION_UID } from "../
|
|
86
|
+
import { extractMessageText } from "../zalo/format/extract-message-text.js";
|
|
87
|
+
import { expandMentions, shiftStyles, ALL_MENTION_UID } from "../zalo/format/mentions.js";
|
|
47
88
|
import { resolveSelfThread } from "../utils/my-documents.js";
|
|
48
89
|
import { buildQuote, resolveQuoteSender } from "../utils/quote.js";
|
|
49
|
-
import { urgencyLevel } from "../
|
|
50
|
-
import { splitMessage, sendParts } from "../
|
|
90
|
+
import { urgencyLevel } from "../zalo/format/urgency.js";
|
|
91
|
+
import { splitMessage, sendParts } from "../zalo/format/split-message.js";
|
|
51
92
|
import { hasLiteralNewline, LITERAL_NEWLINE_WARNING } from "../utils/literal-newline.js";
|
|
52
|
-
import { markdownToZalo, resolveSendFormat } from "../
|
|
53
|
-
import {
|
|
93
|
+
import { markdownToZalo, resolveSendFormat } from "../zalo/format/markdown.js";
|
|
94
|
+
import { MAX_SETTLE_MS, batchParams, waitResult } from "./wait-result.js";
|
|
95
|
+
import { SYNC_STAGES } from "./sync-jobs.js";
|
|
54
96
|
import {
|
|
55
97
|
describeFriendAddError,
|
|
98
|
+
describeFriendUndoError,
|
|
56
99
|
extractErrorCode,
|
|
57
100
|
friendStatusFrom,
|
|
58
101
|
friendsFrom,
|
|
102
|
+
readSentRequests,
|
|
59
103
|
receivedRequestsFrom,
|
|
60
104
|
sentRequestsFrom,
|
|
61
105
|
} from "../core/friend-requests.js";
|
|
106
|
+
import { errorCodeOf } from "../zalo/errors.js";
|
|
62
107
|
import {
|
|
63
|
-
CONFIRMED_ACTIONS,
|
|
64
108
|
NOT_A_MEMBER_CODES,
|
|
65
109
|
REMOVE_NOT_IN_GROUP,
|
|
66
110
|
createdGroupFrom,
|
|
67
|
-
groupConfirmRequired,
|
|
68
111
|
groupInfoFrom,
|
|
69
112
|
memberChangeFrom,
|
|
70
113
|
} from "../core/group-admin.js";
|
|
114
|
+
import { gateMcp, removedLabels } from "../core/confirm-guard.js";
|
|
115
|
+
import { getSecurePage } from "../core/secure-page.js";
|
|
116
|
+
import { hiddenChatsFor, hiddenEventView, readThreadIds, withoutHidden } from "../core/hidden-chats.js";
|
|
117
|
+
|
|
118
|
+
/** The conversation ids a raw read names (moved to src/core/hidden-chats.js; `read run` uses it too). */
|
|
119
|
+
export { readThreadIds } from "../core/hidden-chats.js";
|
|
120
|
+
import { resolveHiddenChats, resolveMediaDelivery } from "../core/deploy-policy.js";
|
|
71
121
|
import { resolveCurrentUserNames, withCurrentSenderNames } from "../core/current-user-names.js";
|
|
122
|
+
import { aliasFor, noteAliasSet, personNameFields, senderNameFields } from "../core/contact-names.js";
|
|
123
|
+
import { actionTool, confirmInput, dryRunInput, ticketInput } from "./action-tool.js";
|
|
124
|
+
import { gateToolsByPresence } from "./tool-presence.js";
|
|
125
|
+
import { BIN_TO_DISPLAY, generateQrTransferImage, qrTransferCaption, resolveBankBin } from "../utils/bank-helpers.js";
|
|
126
|
+
import { CONVERSATION_ACTIONS, CONVERSATION_META } from "./actions-conversation.js";
|
|
127
|
+
import { PROFILE_ACTIONS, PROFILE_META } from "./actions-profile.js";
|
|
128
|
+
import {
|
|
129
|
+
AUTO_REPLY_ACTIONS,
|
|
130
|
+
AUTO_REPLY_META,
|
|
131
|
+
BANK_ACTIONS,
|
|
132
|
+
BANK_META,
|
|
133
|
+
CATALOG_ACTIONS,
|
|
134
|
+
CATALOG_META,
|
|
135
|
+
QUICK_MESSAGE_ACTIONS,
|
|
136
|
+
QUICK_MESSAGE_META,
|
|
137
|
+
} from "./actions-business.js";
|
|
138
|
+
import { CLOUD_ACTIONS, CLOUD_META, LINK_ACTIONS, LINK_META, STICKER_ACTIONS, STICKER_META } from "./actions-media.js";
|
|
139
|
+
import {
|
|
140
|
+
FRIEND_EXTRA_ACTIONS,
|
|
141
|
+
FRIEND_EXTRA_INPUTS,
|
|
142
|
+
GROUP_EXTRA_ACTIONS,
|
|
143
|
+
GROUP_EXTRA_INPUTS,
|
|
144
|
+
} from "./actions-social.js";
|
|
72
145
|
|
|
73
|
-
/** Repeat mode codes matching
|
|
146
|
+
/** Repeat mode codes matching Zalo's reminder repeat modes and src/commands/reminder.js. */
|
|
74
147
|
const REMINDER_REPEAT_MODES = { none: 0, daily: 1, weekly: 2, monthly: 3 };
|
|
75
148
|
const REMINDER_REPEAT_LABELS = { 0: "none", 1: "daily", 2: "weekly", 3: "monthly" };
|
|
76
149
|
|
|
@@ -99,7 +172,7 @@ function parseReminderTime(val) {
|
|
|
99
172
|
/**
|
|
100
173
|
* Build the source descriptor `buildForwardReference` expects from a cached message row.
|
|
101
174
|
*
|
|
102
|
-
* @param {object} api - logged-in
|
|
175
|
+
* @param {object} api - logged-in session
|
|
103
176
|
* @param {object} row - cached message row from zalo.db
|
|
104
177
|
* @returns {Promise<object>}
|
|
105
178
|
*/
|
|
@@ -160,11 +233,12 @@ async function forwardSourceForMcp(api, row) {
|
|
|
160
233
|
* Omitted means "work it out"; an explicit 0 or 1 is always obeyed.
|
|
161
234
|
*
|
|
162
235
|
* @param {string} threadId
|
|
163
|
-
* @param {
|
|
236
|
+
* @param {"dm"|"group"} [explicit] - the caller's threadType, if they gave one
|
|
164
237
|
* @returns {number} THREAD_USER or THREAD_GROUP
|
|
165
238
|
*/
|
|
166
239
|
function resolveThreadType(threadId, explicit) {
|
|
167
|
-
if (explicit
|
|
240
|
+
if (explicit === "group") return THREAD_GROUP;
|
|
241
|
+
if (explicit === "dm") return THREAD_USER;
|
|
168
242
|
try {
|
|
169
243
|
return getThreadType(String(threadId)) === "group" ? THREAD_GROUP : THREAD_USER;
|
|
170
244
|
} catch {
|
|
@@ -173,19 +247,62 @@ function resolveThreadType(threadId, explicit) {
|
|
|
173
247
|
}
|
|
174
248
|
}
|
|
175
249
|
|
|
176
|
-
/**
|
|
250
|
+
/** A group's conversation id in a label: `g` and the group id. */
|
|
251
|
+
const LABEL_GROUP_ID = /^g\d+$/;
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* A thread as a conversation label names it: `g<groupId>` for a group, the bare id for a user (Zalo's
|
|
255
|
+
* conversation ids). An id already given as `g<digits>` is kept.
|
|
256
|
+
*
|
|
257
|
+
* @param {string} threadId
|
|
258
|
+
* @param {"dm"|"group"} [explicit] - the caller's threadType, if they gave one
|
|
259
|
+
* @returns {string}
|
|
260
|
+
*/
|
|
261
|
+
function labelConversationId(threadId, explicit) {
|
|
262
|
+
const id = String(threadId);
|
|
263
|
+
if (LABEL_GROUP_ID.test(id)) return id;
|
|
264
|
+
return resolveThreadType(id, explicit) === THREAD_GROUP ? `g${id}` : id;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** Thread type constants matching the engine's THREAD_TYPE (src/zalo/enums.js) */
|
|
177
268
|
const THREAD_USER = 0;
|
|
178
269
|
|
|
179
270
|
/** Thread type for groups — the only kind Zalo delivers mentions in. */
|
|
180
271
|
const THREAD_GROUP = 1;
|
|
181
272
|
|
|
273
|
+
/** What a reply calls a thread type: the same words an input takes. */
|
|
274
|
+
const threadTypeName = (type) => (Number(type) === THREAD_GROUP ? "group" : "dm");
|
|
275
|
+
|
|
182
276
|
/**
|
|
183
277
|
* How many member ids `zalo_get_group_members` asks Zalo to name per request.
|
|
184
|
-
*
|
|
278
|
+
* The session puts them in the request URL, and Zalo asks in bounded batches
|
|
185
279
|
* too; 50 is the batch the group commands already use for `getGroupInfo`.
|
|
186
280
|
*/
|
|
187
281
|
const MEMBER_NAME_BATCH = 50;
|
|
188
282
|
|
|
283
|
+
/** The kinds of content zalo_send_message sends besides text; one per call. */
|
|
284
|
+
const SEND_MODES = ["filePath/files", "link", "cardUserId", "sticker", "voiceUrl", "video", "bankCard", "qrTransfer"];
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Which of SEND_MODES a zalo_send_message call gives, by its input names.
|
|
288
|
+
*
|
|
289
|
+
* @param {object} val - the call's input
|
|
290
|
+
* @returns {string[]}
|
|
291
|
+
*/
|
|
292
|
+
function sendModes(val) {
|
|
293
|
+
const hasFile = Boolean(val.filePath || (Array.isArray(val.files) && val.files.length > 0));
|
|
294
|
+
return [
|
|
295
|
+
hasFile && "files",
|
|
296
|
+
val.link && "link",
|
|
297
|
+
val.cardUserId && "cardUserId",
|
|
298
|
+
val.sticker && "sticker",
|
|
299
|
+
val.voiceUrl && "voiceUrl",
|
|
300
|
+
val.video && "video",
|
|
301
|
+
val.bankCard && "bankCard",
|
|
302
|
+
val.qrTransfer && "qrTransfer",
|
|
303
|
+
].filter(Boolean);
|
|
304
|
+
}
|
|
305
|
+
|
|
189
306
|
/** How a refusal tells an agent to supply a message's cliMsgId itself. */
|
|
190
307
|
const CLI_MSG_ID_HINT = "the `cliMsgId` parameter (zalo_send_message returns it for a message you sent)";
|
|
191
308
|
|
|
@@ -224,9 +341,37 @@ const CLI_MSG_ID_HINT = "the `cliMsgId` parameter (zalo_send_message returns it
|
|
|
224
341
|
* @param {string} uid
|
|
225
342
|
* @returns {string|null}
|
|
226
343
|
*/
|
|
344
|
+
/**
|
|
345
|
+
* Record the name this account shows for a user (the nickname just set, or the profile name after a nickname was
|
|
346
|
+
* removed) in `contacts`, where `getDisplayName` reads first. Best effort, like cachedDisplayName: the MCP tests run
|
|
347
|
+
* without a db, and a name that fails to persist only costs the next lookup.
|
|
348
|
+
* @param {string} uid
|
|
349
|
+
* @param {string} name
|
|
350
|
+
*/
|
|
351
|
+
function rememberContactName(uid, name) {
|
|
352
|
+
try {
|
|
353
|
+
setContactName(uid, name);
|
|
354
|
+
} catch {
|
|
355
|
+
/* no db open in this process */
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
227
359
|
function cachedDisplayName(uid) {
|
|
228
360
|
try {
|
|
229
361
|
return getDisplayName(uid);
|
|
362
|
+
} catch {
|
|
363
|
+
return aliasFor(uid); // no db in this process: the owner's alias, when the daemon holds one
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* The name the cache holds for a user without the owner's alias (`db.getStoredName`), or null.
|
|
369
|
+
* @param {string} uid
|
|
370
|
+
* @returns {string|null}
|
|
371
|
+
*/
|
|
372
|
+
function cachedStoredName(uid) {
|
|
373
|
+
try {
|
|
374
|
+
return getStoredName(uid);
|
|
230
375
|
} catch {
|
|
231
376
|
return null; // no db in this process
|
|
232
377
|
}
|
|
@@ -235,7 +380,7 @@ function cachedDisplayName(uid) {
|
|
|
235
380
|
/**
|
|
236
381
|
* This account's own uid, or "" when the session cannot say.
|
|
237
382
|
*
|
|
238
|
-
* @param {object} api -
|
|
383
|
+
* @param {object} api - session object
|
|
239
384
|
* @returns {string}
|
|
240
385
|
*/
|
|
241
386
|
function ownIdOf(api) {
|
|
@@ -252,7 +397,7 @@ function ownIdOf(api) {
|
|
|
252
397
|
* device -- for the tools that list conversations. Empty when the cache
|
|
253
398
|
* cannot answer, so a listing never fails for want of it.
|
|
254
399
|
*
|
|
255
|
-
* @param {object} api -
|
|
400
|
+
* @param {object} api - session object
|
|
256
401
|
* @param {string[]} threadIds
|
|
257
402
|
* @returns {Map<string, object>} threadId -> an entry of db.js getReadStates
|
|
258
403
|
*/
|
|
@@ -271,11 +416,11 @@ function readStatesOf(api, threadIds) {
|
|
|
271
416
|
* `me`, or this account's own uid, means My Documents: a 1-1 conversation of
|
|
272
417
|
* its own whose id is the session's `loginInfo.send2me_id`, never the own uid
|
|
273
418
|
* (src/utils/my-documents.js, the same function `msg send me` calls). An
|
|
274
|
-
* explicit `threadType:
|
|
419
|
+
* explicit `threadType: "group"` is refused, as `msg send me -t 1` is.
|
|
275
420
|
*
|
|
276
|
-
* @param {object} api -
|
|
421
|
+
* @param {object} api - session object
|
|
277
422
|
* @param {string} threadId - as the caller gave it
|
|
278
|
-
* @param {
|
|
423
|
+
* @param {"dm"|"group"} [threadTypeIn] - the caller's threadType, if they gave one
|
|
279
424
|
* @returns {null|{threadId: string, notice: string}|{error: string}} null when it is not a self reference
|
|
280
425
|
*/
|
|
281
426
|
function selfThread(api, threadId, threadTypeIn) {
|
|
@@ -288,7 +433,7 @@ function selfThread(api, threadId, threadTypeIn) {
|
|
|
288
433
|
return resolveSelfThread(threadId, {
|
|
289
434
|
ownId: ownId === null ? null : String(ownId),
|
|
290
435
|
send2meId: () => api.getContext().loginInfo?.send2me_id,
|
|
291
|
-
groupRequested:
|
|
436
|
+
groupRequested: threadTypeIn === "group",
|
|
292
437
|
});
|
|
293
438
|
}
|
|
294
439
|
|
|
@@ -299,9 +444,9 @@ function selfThread(api, threadId, threadTypeIn) {
|
|
|
299
444
|
* typed by {@link resolveThreadType}: the caller's explicit threadType, else
|
|
300
445
|
* the cache's.
|
|
301
446
|
*
|
|
302
|
-
* @param {object} api -
|
|
447
|
+
* @param {object} api - session object
|
|
303
448
|
* @param {string} threadIdIn - as the caller gave it
|
|
304
|
-
* @param {
|
|
449
|
+
* @param {"dm"|"group"} [threadTypeIn] - the caller's threadType, if they gave one
|
|
305
450
|
* @returns {{threadId: string, threadType: number, notice?: string}|{error: string}} `notice` only for My Documents
|
|
306
451
|
*/
|
|
307
452
|
function actionThread(api, threadIdIn, threadTypeIn) {
|
|
@@ -329,6 +474,113 @@ function err(message) {
|
|
|
329
474
|
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
330
475
|
}
|
|
331
476
|
|
|
477
|
+
/**
|
|
478
|
+
* One cached message as zalo_get_history returns it.
|
|
479
|
+
* @param {object} m - a `messages` row
|
|
480
|
+
* @returns {object}
|
|
481
|
+
*/
|
|
482
|
+
function cachedHistoryRow(m) {
|
|
483
|
+
return {
|
|
484
|
+
msgId: m.msgId,
|
|
485
|
+
cliMsgId: cachedCliMsgId(m) ?? undefined,
|
|
486
|
+
threadId: m.threadId,
|
|
487
|
+
senderId: m.senderId || null,
|
|
488
|
+
senderName: m.senderName || null,
|
|
489
|
+
text: m.text,
|
|
490
|
+
timestamp: m.timestamp,
|
|
491
|
+
type: m.type,
|
|
492
|
+
mediaCached: m.localPath ? true : undefined,
|
|
493
|
+
hasAttachment: m.has_attachment ? true : undefined,
|
|
494
|
+
msgStatus: m.msgStatus ?? undefined,
|
|
495
|
+
replyTo: cachedReplyTo(m),
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/** The largest sticker picture zalo_view_media fetches. */
|
|
500
|
+
const STICKER_MAX_BYTES = 2 * 1024 * 1024;
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* A sticker's picture, fetched for zalo_view_media and not kept: stickers are not downloaded with the messages. The
|
|
504
|
+
* URL comes from the live message, else from Zalo's sticker detail for the id the cached message names.
|
|
505
|
+
*
|
|
506
|
+
* @param {object} api
|
|
507
|
+
* @param {object|null} row - the cached message
|
|
508
|
+
* @param {object|null} buffered - the live message
|
|
509
|
+
* @param {(url: string, init: object) => Promise<Response>} [fetchImpl]
|
|
510
|
+
* @returns {Promise<{bytes: Buffer, mime: string} | {error: string}>}
|
|
511
|
+
*/
|
|
512
|
+
export async function stickerPicture(api, row, buffered, fetchImpl = (...a) => fetch(...a)) {
|
|
513
|
+
let url = buffered?.attachment?.url || null;
|
|
514
|
+
if (!url) {
|
|
515
|
+
let content = null;
|
|
516
|
+
try {
|
|
517
|
+
content = JSON.parse(row?.raw_data || "{}")?.content ?? null;
|
|
518
|
+
} catch {
|
|
519
|
+
/* no stored content */
|
|
520
|
+
}
|
|
521
|
+
const id = Number(content?.id);
|
|
522
|
+
if (!Number.isFinite(id) || id <= 0) return { error: "This sticker message does not say which sticker it is." };
|
|
523
|
+
try {
|
|
524
|
+
const [detail] = (await api.getStickersDetail([id])) ?? [];
|
|
525
|
+
url = detail?.stickerWebpUrl || detail?.stickerUrl || null;
|
|
526
|
+
} catch (e) {
|
|
527
|
+
return { error: `Zalo did not describe the sticker: ${e.message}` };
|
|
528
|
+
}
|
|
529
|
+
if (!url) return { error: "Zalo did not give a picture for this sticker." };
|
|
530
|
+
}
|
|
531
|
+
try {
|
|
532
|
+
const res = await fetchImpl(url, { signal: AbortSignal.timeout(15_000), redirect: "follow" });
|
|
533
|
+
const mime = String(res.headers.get("content-type") || "")
|
|
534
|
+
.split(";")[0]
|
|
535
|
+
.trim()
|
|
536
|
+
.toLowerCase();
|
|
537
|
+
if (!res.ok || !mime.startsWith("image/")) {
|
|
538
|
+
return { error: `The sticker's picture could not be fetched (HTTP ${res.status}).` };
|
|
539
|
+
}
|
|
540
|
+
const bytes = Buffer.from(await res.arrayBuffer());
|
|
541
|
+
if (bytes.length > STICKER_MAX_BYTES) return { error: "The sticker's picture is too large to show." };
|
|
542
|
+
return { bytes, mime };
|
|
543
|
+
} catch (e) {
|
|
544
|
+
return { error: `The sticker's picture could not be fetched: ${e.message}` };
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* A thread's cached messages between two times, oldest first: every one, or one page of `limit` (bug-reports #5).
|
|
550
|
+
*
|
|
551
|
+
* Cache only: Zalo's server serves nothing older than this login, so a date range is the cache's question.
|
|
552
|
+
*
|
|
553
|
+
* @param {string} threadId
|
|
554
|
+
* @param {{since: number|null, until: number|null, limit: number}} range - `limit` Infinity: every message in the period
|
|
555
|
+
* @param {object} [nameCache]
|
|
556
|
+
* @returns {object} tool payload
|
|
557
|
+
*/
|
|
558
|
+
function cacheHistoryRange(threadId, { since, until, limit }, nameCache) {
|
|
559
|
+
let rows;
|
|
560
|
+
let nextSince = null;
|
|
561
|
+
if (Number.isFinite(limit)) ({ rows, nextSince } = getMessagesInRange(String(threadId), { since, until, limit }));
|
|
562
|
+
else rows = getAllMessagesInRange(String(threadId), { since, until }).rows;
|
|
563
|
+
const messages = rows.map(cachedHistoryRow);
|
|
564
|
+
const info = nameCache?.get(String(threadId));
|
|
565
|
+
if (info) for (const m of messages) m.threadName = info.name;
|
|
566
|
+
return {
|
|
567
|
+
threadId: String(threadId),
|
|
568
|
+
source: "cache",
|
|
569
|
+
since,
|
|
570
|
+
until,
|
|
571
|
+
count: messages.length,
|
|
572
|
+
messages,
|
|
573
|
+
// Pass `nextSince` back as `since` (same `until`) for the next page.
|
|
574
|
+
hasMore: nextSince !== null,
|
|
575
|
+
nextSince,
|
|
576
|
+
...(messages.length === 0 && {
|
|
577
|
+
note:
|
|
578
|
+
"Nothing cached for this conversation in this period. Zalo's server serves only messages since this " +
|
|
579
|
+
"login; older ones are restored with `zalo-agent sync` (the owner's phone confirms it).",
|
|
580
|
+
}),
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
|
|
332
584
|
/**
|
|
333
585
|
* Read a thread's history out of the local cache.
|
|
334
586
|
*
|
|
@@ -336,7 +588,7 @@ function err(message) {
|
|
|
336
588
|
* to fall back to asking Zalo.
|
|
337
589
|
*
|
|
338
590
|
* @param {string} threadId
|
|
339
|
-
* @param {number} limit
|
|
591
|
+
* @param {number} limit - Infinity: every cached message
|
|
340
592
|
* @param {number} [before] - epoch ms; return messages older than this
|
|
341
593
|
* @param {object} [nameCache]
|
|
342
594
|
* @returns {object|null} tool payload, or null when the cache is empty/unopened
|
|
@@ -344,26 +596,13 @@ function err(message) {
|
|
|
344
596
|
function cacheHistory(threadId, limit, before, nameCache) {
|
|
345
597
|
let rows;
|
|
346
598
|
try {
|
|
347
|
-
rows = getMessages(String(threadId), limit, before);
|
|
599
|
+
rows = getMessages(String(threadId), Number.isFinite(limit) ? limit : -1, before);
|
|
348
600
|
} catch {
|
|
349
601
|
return null; // no db open in this process — server path it is
|
|
350
602
|
}
|
|
351
603
|
if (!rows || rows.length === 0) return null;
|
|
352
604
|
|
|
353
|
-
const messages = rows
|
|
354
|
-
.map((m) => ({
|
|
355
|
-
msgId: m.msgId,
|
|
356
|
-
threadId: m.threadId,
|
|
357
|
-
senderId: m.senderId || null,
|
|
358
|
-
senderName: m.senderName || null,
|
|
359
|
-
text: m.text,
|
|
360
|
-
timestamp: m.timestamp,
|
|
361
|
-
type: m.type,
|
|
362
|
-
localPath: m.localPath || undefined,
|
|
363
|
-
hasAttachment: m.has_attachment ? true : undefined,
|
|
364
|
-
msgStatus: m.msgStatus ?? undefined,
|
|
365
|
-
}))
|
|
366
|
-
.sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0));
|
|
605
|
+
const messages = rows.map(cachedHistoryRow).sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0));
|
|
367
606
|
|
|
368
607
|
const info = nameCache?.get(String(threadId));
|
|
369
608
|
if (info) for (const m of messages) m.threadName = info.name;
|
|
@@ -375,14 +614,23 @@ function cacheHistory(threadId, limit, before, nameCache) {
|
|
|
375
614
|
messages,
|
|
376
615
|
// Oldest returned timestamp: pass it back as `before` for the next page.
|
|
377
616
|
cursor: messages.length ? messages[0].timestamp : (before ?? null),
|
|
378
|
-
hasMore: rows.length >= limit,
|
|
617
|
+
hasMore: Number.isFinite(limit) && rows.length >= limit,
|
|
379
618
|
};
|
|
380
619
|
}
|
|
381
620
|
|
|
621
|
+
/** What zalo_get_messages and zalo_wait_for_message say about the system events in their list. */
|
|
622
|
+
const SYSTEM_EVENTS_NOTE =
|
|
623
|
+
"A system event arrives in the same list with `system: true` and `msgId` null, only to a read or wait that names no `threadId`; each has a `type` and a `text` to show a person. " +
|
|
624
|
+
"`account_state`: the account's connection state changed (`state` idle, connecting, connected, kicked, yielded, login_needed, signed_out or maintenance, `previous`, `detail`); yielded and signed_out refuse every call until a person acts, as `text` says; a park and the wake that ends it are not in the buffer. " +
|
|
625
|
+
"`group_gone`: the account left, was removed or blocked from, or saw the disbanding of the group in `threadId` (`reason`, `leftAt`, `mode` purge or keep, `purged` counts). " +
|
|
626
|
+
"`queue_overflow`: Zalo's offline queue overflowed and messages from `fromTs` to `toTs` were dropped (`queues`, `groups` repair counts, `pending`; when pending, `command` is the sync the owner runs, which taps the phone). " +
|
|
627
|
+
"`session_expiring`: the account's saved login ends by itself on `expiresAt` (`daysLeft`, `threshold` 14, 7, 3, 1 or 0 once `expired`); the owner renews it with a QR login (`command`), and once it ends every call is refused until then. " +
|
|
628
|
+
"`storage_quota`: this account's storage on the server is near or over its quota, or was purged, or is back within it (`level` warn, over, grace_ending, purged or ok; `usedBytes`, `limitBytes`, `purgeAt`); zalo_profile 'usage' reads the current usage. ";
|
|
629
|
+
|
|
382
630
|
/**
|
|
383
631
|
* Register all Zalo MCP tools on the server.
|
|
384
632
|
* @param {import("@modelcontextprotocol/sdk/server/mcp.js").McpServer} server
|
|
385
|
-
* @param {object} api -
|
|
633
|
+
* @param {object} api - session object
|
|
386
634
|
* @param {import("./message-buffer.js").MessageBuffer} buffer
|
|
387
635
|
* @param {import("./thread-filter.js").ThreadFilter} filter
|
|
388
636
|
* @param {object} config - MCP config
|
|
@@ -391,9 +639,23 @@ function cacheHistory(threadId, limit, before, nameCache) {
|
|
|
391
639
|
* @param {ReturnType<import("../core/daemon-channel.js").createStageLock>} [stageLock] - the
|
|
392
640
|
* daemon's one-stage-at-a-time lock; a server-side history fetch takes it, as `listen`'s does
|
|
393
641
|
* @param {object} [syncJobs] - the daemon's account-local sync job tracker
|
|
642
|
+
* @param {{presence?: object|null}} [extras] - `presence`: the daemon's on-demand presence
|
|
643
|
+
* (src/core/daemon-presence.js); every tool goes through it by its class (./tool-presence.js)
|
|
394
644
|
*/
|
|
395
|
-
export function registerTools(
|
|
396
|
-
|
|
645
|
+
export function registerTools(
|
|
646
|
+
server,
|
|
647
|
+
api,
|
|
648
|
+
buffer,
|
|
649
|
+
filter,
|
|
650
|
+
config,
|
|
651
|
+
nameCache,
|
|
652
|
+
accountDir,
|
|
653
|
+
stageLock,
|
|
654
|
+
syncJobs,
|
|
655
|
+
extras = {},
|
|
656
|
+
) {
|
|
657
|
+
// On-demand presence: refused while yielded or signed out, a hold per call, warming by the tool's class.
|
|
658
|
+
gateToolsByPresence(server, extras?.presence ?? null);
|
|
397
659
|
|
|
398
660
|
// Several bots can share one listener, each with its own read cursor
|
|
399
661
|
// (triage M7). A bot that names none reads as "default", as before.
|
|
@@ -408,6 +670,74 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
408
670
|
"so one bot's zalo_mark_read does not hide messages from another. Omit it for a single bot.",
|
|
409
671
|
);
|
|
410
672
|
|
|
673
|
+
// Every tool with an action Zalo asks about first takes `confirm` and `dryRun` (confirmInput, dryRunInput
|
|
674
|
+
// in action-tool.js), and settles it through gate() (src/core/confirm-guard.js) after its arguments are checked
|
|
675
|
+
// and before anything is sent.
|
|
676
|
+
// Over the stateless HTTP transport this server lives for one request (mcp-http-transport.js marks it), so
|
|
677
|
+
// "human" mode cannot ask there; the guard hands out a one-time approve page and the call is repeated with
|
|
678
|
+
// `ticket` (src/core/secure-page.js).
|
|
679
|
+
const gate = (key, target, { confirm, dryRun, ticket } = {}, extra, more = {}) =>
|
|
680
|
+
gateMcp(key, target, {
|
|
681
|
+
confirm,
|
|
682
|
+
dryRun,
|
|
683
|
+
ticket,
|
|
684
|
+
config,
|
|
685
|
+
accountId: ownIdOf(api),
|
|
686
|
+
server,
|
|
687
|
+
extra,
|
|
688
|
+
stateless: server?.statelessHttp === true,
|
|
689
|
+
// approval.secret: the approver password lives in the account folder, the PIN's hash in the hidden set.
|
|
690
|
+
accountDir: accountDir ?? null,
|
|
691
|
+
hidden: () => hiddenSet(),
|
|
692
|
+
...more,
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
// Hidden chats (src/core/hidden-chats.js), shown by the deployment's hiddenChats policy (src/core/deploy-policy.js):
|
|
696
|
+
// `exclude` (default) leaves them out of every list, search, history and event; `contentless` turns an event in
|
|
697
|
+
// one into `{event, hidden: true}`; `include` shows them.
|
|
698
|
+
const hiddenSet = () => hiddenChatsFor(ownIdOf(api) ?? "", { stateDir: accountDir ?? null });
|
|
699
|
+
const hiddenMode = () => resolveHiddenChats({ config, accountId: ownIdOf(api) ?? undefined }).mode;
|
|
700
|
+
const hiddenIds = () => (hiddenMode() === "include" ? [] : [...hiddenSet().ids]);
|
|
701
|
+
const isHiddenThread = (id) =>
|
|
702
|
+
id !== undefined && id !== null && hiddenMode() !== "include" && hiddenSet().isHidden(id);
|
|
703
|
+
const eventsView = (list) => {
|
|
704
|
+
const set = hiddenSet();
|
|
705
|
+
const mode = hiddenMode();
|
|
706
|
+
return list
|
|
707
|
+
.map((m) => hiddenEventView(m, set, mode, { name: m?.type === "undo" ? "undo" : "message" }))
|
|
708
|
+
.filter(Boolean);
|
|
709
|
+
};
|
|
710
|
+
const HIDDEN_THREAD =
|
|
711
|
+
"That conversation is one of the account's hidden chats, which this server leaves out (hiddenChats policy). " +
|
|
712
|
+
"The account owner can unhide it, or the deployment can set hiddenChats to include.";
|
|
713
|
+
|
|
714
|
+
// What an action table's rows read (src/mcp/action-tool.js): the session, the guard, and the helpers that type
|
|
715
|
+
// a thread and name this account, so a row resolves a thread the way every other tool here does.
|
|
716
|
+
const toolCtx = {
|
|
717
|
+
api,
|
|
718
|
+
ok,
|
|
719
|
+
err,
|
|
720
|
+
gate,
|
|
721
|
+
ownId: () => ownIdOf(api),
|
|
722
|
+
threadType: resolveThreadType,
|
|
723
|
+
threadTypeName,
|
|
724
|
+
onSelfName: (name) => syncJobs?.onSelfName?.(name),
|
|
725
|
+
// The hidden-chat actions: the deployment's policy, the PIN page, and a live elicitation where there is one.
|
|
726
|
+
config,
|
|
727
|
+
server,
|
|
728
|
+
stateless: server?.statelessHttp === true,
|
|
729
|
+
hidden: () => hiddenSet(),
|
|
730
|
+
hiddenMode: () => hiddenMode(),
|
|
731
|
+
securePage: () => getSecurePage(),
|
|
732
|
+
threadName: (id) => nameCache?.get?.(String(id))?.name ?? null,
|
|
733
|
+
// zalo_profile 'usage': the media folder this server downloads into.
|
|
734
|
+
mediaRoot: config.media?.downloadDir ?? null,
|
|
735
|
+
// zalo_profile 'presence_resume': the daemon's presence (null under a server that runs none).
|
|
736
|
+
presence: extras?.presence ?? null,
|
|
737
|
+
};
|
|
738
|
+
const friendExtra = actionTool("zalo_friend", FRIEND_EXTRA_ACTIONS, toolCtx);
|
|
739
|
+
const groupExtra = actionTool("zalo_group", GROUP_EXTRA_ACTIONS, toolCtx);
|
|
740
|
+
|
|
411
741
|
// --- zalo_get_messages ---
|
|
412
742
|
server.registerTool(
|
|
413
743
|
"zalo_get_messages",
|
|
@@ -416,8 +746,10 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
416
746
|
description:
|
|
417
747
|
"Read the new incoming Zalo messages (DMs and groups) from the live buffer, in order. It returns the messages this consumer has not yet marked read; when you have handled them, call zalo_mark_read with the reply's `cursor`. " +
|
|
418
748
|
"To continue exactly after the last reply, pass its `cursor` as `since`. To wait for the next message instead of polling, use zalo_wait_for_message. " +
|
|
419
|
-
"Each message has `msgId` (pass it as `msgId` or `quoteMsgId` to other tools
|
|
420
|
-
"`readOnZalo` is true or false when the account owner has or has not read the message on Zalo (phone or Zalo
|
|
749
|
+
"Each message has `msgId` (pass it as `msgId` or `quoteMsgId` to other tools), `threadId`, `threadType` (dm or group), `senderId`, `senderName` (the name to show: your alias for the sender when you set one, else the name the message carried), `senderAlias` (your alias, or null), `senderZaloName` (the name the message carried), `senderDisplayName` (the current name: your alias, else the phonebook name, else the Zalo name, else the display name, else the uid; `senderDisplayNameSource` says which: alias, phonebook, zalo, display or uid), `text`, `timestamp` (epoch ms), `type`, `threadName` and `readOnZalo`. " +
|
|
750
|
+
"`readOnZalo` is true or false when the account owner has or has not read the message on Zalo (on the phone or another Zalo app), and null when that is unknown; zalo_mark_read does not change it. " +
|
|
751
|
+
'A recall arrives in the same list with `type` "undo": its `msgId` is the recalled message (null when only its `cliMsgId` is known), its `text` is empty, and the earlier message is gone from the cache. ' +
|
|
752
|
+
SYSTEM_EVENTS_NOTE +
|
|
421
753
|
"Returns `{ messages, cursor, hasMore }`.",
|
|
422
754
|
inputSchema: z.object({
|
|
423
755
|
threadId: z
|
|
@@ -436,17 +768,21 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
436
768
|
.number()
|
|
437
769
|
.int()
|
|
438
770
|
.min(1)
|
|
439
|
-
.
|
|
440
|
-
.
|
|
441
|
-
.describe("Most messages to return in one call (1 to 100)."),
|
|
771
|
+
.optional()
|
|
772
|
+
.describe("Most messages to return in one call. Omit it for every unread message buffered."),
|
|
442
773
|
consumer: consumerSchema,
|
|
443
774
|
}),
|
|
444
775
|
},
|
|
445
776
|
async ({ threadId, since, limit, consumer }) => {
|
|
446
777
|
try {
|
|
778
|
+
if (isHiddenThread(threadId)) return err(HIDDEN_THREAD);
|
|
447
779
|
// An explicit cursor is honored as given; 0 starts after what this consumer marked read.
|
|
448
780
|
const from = since > 0 ? since : buffer.readCursor(consumer);
|
|
449
781
|
const result = buffer.read(threadId, from, limit);
|
|
782
|
+
// A system event (account_state, group_gone, queue_overflow, session_expiring, storage_quota) is passed on as it is.
|
|
783
|
+
const order = result.messages;
|
|
784
|
+
const system = new Map(order.filter((m) => m?.system).map((m) => [m._cursor, m]));
|
|
785
|
+
result.messages = order.filter((m) => !m?.system);
|
|
450
786
|
// Enrich messages with thread name from cache
|
|
451
787
|
if (nameCache) {
|
|
452
788
|
for (const msg of result.messages) {
|
|
@@ -475,8 +811,13 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
475
811
|
};
|
|
476
812
|
result.messages = result.messages.map((msg) => ({
|
|
477
813
|
...msg,
|
|
478
|
-
readOnZalo: readOnZalo(msg.
|
|
814
|
+
readOnZalo: readOnZalo(msg.msgId, watermarkOf(String(msg.threadId))),
|
|
479
815
|
}));
|
|
816
|
+
if (system.size) {
|
|
817
|
+
const byCursor = new Map(result.messages.map((m) => [m._cursor, m]));
|
|
818
|
+
result.messages = order.map((m) => system.get(m._cursor) ?? byCursor.get(m._cursor));
|
|
819
|
+
}
|
|
820
|
+
result.messages = eventsView(result.messages);
|
|
480
821
|
return ok(result);
|
|
481
822
|
} catch (e) {
|
|
482
823
|
console.error("[mcp-tools] zalo_get_messages error:", e.message);
|
|
@@ -491,12 +832,12 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
491
832
|
{
|
|
492
833
|
title: "Send Zalo Message",
|
|
493
834
|
description:
|
|
494
|
-
"Send a message to a Zalo conversation: text, files or images, a link preview card, or a
|
|
495
|
-
'Text: use real line breaks, never the two characters backslash and n (Zalo shows those as typed). Markdown is converted to Zalo formatting by default; `format: "plain"` sends the text exactly as written. A text over 3000 bytes (a Chinese, Japanese, Korean, Thai or Hindi character is 3, a Cyrillic or Arabic one 2) is split into several messages at paragraph or sentence ends, as Zalo
|
|
835
|
+
"Send a message to a Zalo conversation: text, files or images, a link preview card, a contact card, a sticker, a voice message or a video from a URL, a bank account card, or a VietQR transfer image. Give `threadId` and one kind of content: `text`, `filePath` or `files`, `link`, `cardUserId`, `sticker`, `voiceUrl`, `video`, `bankCard` or `qrTransfer`. With files, a link, a video or a QR transfer, `text` is an optional caption. " +
|
|
836
|
+
'Text: use real line breaks, never the two characters backslash and n (Zalo shows those as typed). Markdown is converted to Zalo formatting by default; `format: "plain"` sends the text exactly as written. A text over 3000 bytes (a Chinese, Japanese, Korean, Thai or Hindi character is 3, a Cyrillic or Arabic one 2) is split into several messages at paragraph or sentence ends, as Zalo does, and the reply then lists every part (`splitInto`, `parts`). ' +
|
|
496
837
|
"Mention in a group: put `@[userId]` in the text where the tag belongs (`@[-1]` is @All). Take the user id from a message's `senderId` (zalo_get_messages, zalo_get_history) or from zalo_get_group_members. It is sent as `@Their Name` and notifies that person; a user id the cache cannot name is tagged as the bare id and listed in `unresolvedMentions`. Mentions only work in groups. " +
|
|
497
838
|
"Reply to a message: pass its msgId as `quoteMsgId` (text messages only, and the message must be in the local cache). " +
|
|
498
839
|
'`urgency` marks the message Important or Urgent, as the apps do. `threadId: "me"` sends to the owner\'s My Documents. ' +
|
|
499
|
-
"Returns `{ success, msgId, cliMsgId, threadType }`
|
|
840
|
+
"Returns `{ success, msgId, cliMsgId, threadType }` and, when they apply, `parts` and `warnings`. Keep `msgId` and `cliMsgId` if you may need to react to or recall this message (zalo_react, zalo_undo).",
|
|
500
841
|
inputSchema: z
|
|
501
842
|
.object({
|
|
502
843
|
threadId: z
|
|
@@ -509,7 +850,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
509
850
|
.min(1)
|
|
510
851
|
.optional()
|
|
511
852
|
.describe(
|
|
512
|
-
"The message. Real line breaks only: never the two characters backslash and n. Markdown is converted unless `format` is 'plain'. Required unless
|
|
853
|
+
"The message. Real line breaks only: never the two characters backslash and n. Markdown is converted unless `format` is 'plain'. Required unless another kind of content is given; with files, a link, a video or a QR transfer it is the caption. `@[userId]` tokens become @-mentions (`@[-1]` is @All).",
|
|
513
854
|
),
|
|
514
855
|
filePath: z
|
|
515
856
|
.string()
|
|
@@ -535,14 +876,77 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
535
876
|
.min(1)
|
|
536
877
|
.optional()
|
|
537
878
|
.describe("The user id whose contact card to share in this conversation."),
|
|
879
|
+
sticker: z
|
|
880
|
+
.string()
|
|
881
|
+
.min(1)
|
|
882
|
+
.max(100)
|
|
883
|
+
.optional()
|
|
884
|
+
.describe(
|
|
885
|
+
"A keyword: sends the first sticker Zalo finds for it (zalo_sticker 'search' lists them).",
|
|
886
|
+
),
|
|
887
|
+
voiceUrl: z
|
|
888
|
+
.string()
|
|
889
|
+
.url()
|
|
890
|
+
.optional()
|
|
891
|
+
.describe("The URL of an audio file to send as a voice message (Zalo fetches it from there)."),
|
|
892
|
+
video: z
|
|
893
|
+
.object({
|
|
894
|
+
source: z
|
|
895
|
+
.string()
|
|
896
|
+
.min(1)
|
|
897
|
+
.describe(
|
|
898
|
+
"The video: an http(s) URL Zalo fetches, or a local file path on the machine this server runs on (uploaded)",
|
|
899
|
+
),
|
|
900
|
+
thumbnail: z
|
|
901
|
+
.string()
|
|
902
|
+
.min(1)
|
|
903
|
+
.describe("Its thumbnail: an image URL, or a local jpg/png/webp path (uploaded)"),
|
|
904
|
+
durationMs: z.number().int().min(0).optional().describe("Its length in milliseconds"),
|
|
905
|
+
width: z.number().int().min(1).optional().describe("Its width in pixels (default 1280)"),
|
|
906
|
+
height: z.number().int().min(1).optional().describe("Its height in pixels (default 720)"),
|
|
907
|
+
})
|
|
908
|
+
.strict()
|
|
909
|
+
.optional()
|
|
910
|
+
.describe(
|
|
911
|
+
"A video to send, from a URL or a local file, with its thumbnail. `text` is the caption.",
|
|
912
|
+
),
|
|
913
|
+
bankCard: z
|
|
914
|
+
.object({
|
|
915
|
+
bank: z
|
|
916
|
+
.string()
|
|
917
|
+
.min(1)
|
|
918
|
+
.describe("The bank: a short name such as vcb, ocb or bidv, or its BIN"),
|
|
919
|
+
accountNumber: z.string().min(1).max(40).describe("The account number"),
|
|
920
|
+
holderName: z.string().min(1).max(100).optional().describe("The account holder's name"),
|
|
921
|
+
})
|
|
922
|
+
.strict()
|
|
923
|
+
.optional()
|
|
924
|
+
.describe("A bank account card (số tài khoản) to send; zalo_bank 'banks' lists the banks."),
|
|
925
|
+
qrTransfer: z
|
|
926
|
+
.object({
|
|
927
|
+
bank: z
|
|
928
|
+
.string()
|
|
929
|
+
.min(1)
|
|
930
|
+
.describe("The bank: a short name such as vcb, ocb or bidv, or its BIN"),
|
|
931
|
+
accountNumber: z.string().min(1).max(40).describe("The account number to pay into"),
|
|
932
|
+
amount: z.number().int().min(1).optional().describe("The amount in VND"),
|
|
933
|
+
content: z.string().max(50).optional().describe("The transfer note, at most 50 characters"),
|
|
934
|
+
template: z
|
|
935
|
+
.enum(["compact", "print", "qronly"])
|
|
936
|
+
.optional()
|
|
937
|
+
.describe("The QR image's style (default compact)"),
|
|
938
|
+
})
|
|
939
|
+
.strict()
|
|
940
|
+
.optional()
|
|
941
|
+
.describe(
|
|
942
|
+
"A VietQR transfer image to generate and send. `text` replaces its default caption " +
|
|
943
|
+
"(bank, account, amount and note).",
|
|
944
|
+
),
|
|
538
945
|
threadType: z
|
|
539
|
-
.
|
|
540
|
-
.int()
|
|
541
|
-
.min(0)
|
|
542
|
-
.max(1)
|
|
946
|
+
.enum(["dm", "group"])
|
|
543
947
|
.optional()
|
|
544
948
|
.describe(
|
|
545
|
-
|
|
949
|
+
'The conversation type: "dm" or "group". Leave it out: the type stored for this thread is used. Pass it only to override that.',
|
|
546
950
|
),
|
|
547
951
|
quoteMsgId: z
|
|
548
952
|
.string()
|
|
@@ -568,22 +972,19 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
568
972
|
"for an ordinary message",
|
|
569
973
|
),
|
|
570
974
|
})
|
|
975
|
+
.strict()
|
|
571
976
|
.refine(
|
|
572
|
-
(val) =>
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
(Array.isArray(val.files) && val.files.length > 0),
|
|
579
|
-
),
|
|
580
|
-
"Provide at least one of text, filePath, files, link, or cardUserId",
|
|
977
|
+
(val) => Boolean(val.text) || sendModes(val).length > 0,
|
|
978
|
+
`Provide text, or one of ${SEND_MODES.join(", ")}`,
|
|
979
|
+
)
|
|
980
|
+
.refine(
|
|
981
|
+
(val) => sendModes(val).length <= 1,
|
|
982
|
+
`Send one kind of content per call: ${SEND_MODES.join(", ")} cannot be combined`,
|
|
581
983
|
)
|
|
582
|
-
.refine(
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
}, "Cannot combine link, cardUserId, and file attachments in a single call"),
|
|
984
|
+
.refine(
|
|
985
|
+
(val) => !(val.text && ["sticker", "voiceUrl", "bankCard"].includes(sendModes(val)[0])),
|
|
986
|
+
"A sticker, a voice message or a bank card carries no text: send the text as its own message",
|
|
987
|
+
),
|
|
587
988
|
},
|
|
588
989
|
async ({
|
|
589
990
|
threadId: threadIdIn,
|
|
@@ -592,6 +993,11 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
592
993
|
files,
|
|
593
994
|
link,
|
|
594
995
|
cardUserId,
|
|
996
|
+
sticker,
|
|
997
|
+
voiceUrl,
|
|
998
|
+
video,
|
|
999
|
+
bankCard,
|
|
1000
|
+
qrTransfer,
|
|
595
1001
|
threadType: threadTypeIn,
|
|
596
1002
|
quoteMsgId,
|
|
597
1003
|
urgency: urgencyIn,
|
|
@@ -605,7 +1011,118 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
605
1011
|
return err(thread.error);
|
|
606
1012
|
}
|
|
607
1013
|
const { threadId, threadType } = thread;
|
|
1014
|
+
// A group this account left or lost (src/core/group-exit.js): refused here, not at the server.
|
|
1015
|
+
const goneRefusal = sendRefusal(threadId);
|
|
1016
|
+
if (goneRefusal) return err(goneRefusal);
|
|
1017
|
+
// The reply every non-text send shares: the new message's ids, as a text send reports them.
|
|
1018
|
+
const sentReply = (kind, result, more = {}) => {
|
|
1019
|
+
const msgId = result?.msgId ?? result?.message?.msgId ?? null;
|
|
1020
|
+
const cliMsgId = result?.cliMsgId ?? result?.message?.cliMsgId ?? null;
|
|
1021
|
+
return ok({
|
|
1022
|
+
success: true,
|
|
1023
|
+
kind,
|
|
1024
|
+
...more,
|
|
1025
|
+
msgId: msgId === null ? null : String(msgId),
|
|
1026
|
+
...(cliMsgId !== null && { cliMsgId: String(cliMsgId) }),
|
|
1027
|
+
threadType: threadTypeName(threadType),
|
|
1028
|
+
...(thread.notice && { threadId, notice: thread.notice }),
|
|
1029
|
+
});
|
|
1030
|
+
};
|
|
608
1031
|
try {
|
|
1032
|
+
// The kinds `msg sticker`, `send-voice`, `send-video`, `send-bank` and `send-qr-transfer` send,
|
|
1033
|
+
// through the same session calls.
|
|
1034
|
+
if (sticker) {
|
|
1035
|
+
const found = (await api.searchSticker(sticker))?.[0];
|
|
1036
|
+
if (!found) return err(`No sticker found for "${sticker}".`);
|
|
1037
|
+
const stickerObj = {
|
|
1038
|
+
id: found.sticker_id || found.stickerId || found.id,
|
|
1039
|
+
cateId: found.cate_id || found.cateId,
|
|
1040
|
+
type: found.type || 7,
|
|
1041
|
+
};
|
|
1042
|
+
return sentReply("sticker", await api.sendSticker(stickerObj, threadId, Number(threadType)), {
|
|
1043
|
+
stickerId: String(stickerObj.id),
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
if (voiceUrl) {
|
|
1047
|
+
return sentReply("voice", await api.sendVoice({ voiceUrl, ttl: 0 }, threadId, Number(threadType)));
|
|
1048
|
+
}
|
|
1049
|
+
if (video) {
|
|
1050
|
+
// As `msg send-video`: a URL Zalo fetches, or a local file uploaded on this server's socket; a
|
|
1051
|
+
// thumbnail likewise.
|
|
1052
|
+
const isUrl = (v) => /^https?:\/\//i.test(v);
|
|
1053
|
+
const size = {
|
|
1054
|
+
duration: video.durationMs,
|
|
1055
|
+
width: video.width ?? 1280,
|
|
1056
|
+
height: video.height ?? 720,
|
|
1057
|
+
};
|
|
1058
|
+
if (isUrl(video.source) && isUrl(video.thumbnail)) {
|
|
1059
|
+
const result = await api.sendVideo(
|
|
1060
|
+
{ videoUrl: video.source, thumbnailUrl: video.thumbnail, msg: text ?? "", ...size },
|
|
1061
|
+
threadId,
|
|
1062
|
+
Number(threadType),
|
|
1063
|
+
);
|
|
1064
|
+
return sentReply("video", result);
|
|
1065
|
+
}
|
|
1066
|
+
if (isUrl(video.source)) {
|
|
1067
|
+
return err(
|
|
1068
|
+
"A video sent from a URL takes a thumbnail URL too; a local thumbnail goes with a local video.",
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
const file = resolve(video.source.trim());
|
|
1072
|
+
const thumb = isUrl(video.thumbnail) ? null : resolve(video.thumbnail.trim());
|
|
1073
|
+
const missing = [file, thumb].filter((p) => p && !existsSync(p));
|
|
1074
|
+
if (missing.length > 0) return err(`File not found: ${missing.join(", ")}`);
|
|
1075
|
+
const result = await api.sendVideoFile(
|
|
1076
|
+
{
|
|
1077
|
+
file,
|
|
1078
|
+
msg: text ?? "",
|
|
1079
|
+
...(thumb ? { thumbnailFile: thumb } : { thumbnailUrl: video.thumbnail }),
|
|
1080
|
+
...size,
|
|
1081
|
+
},
|
|
1082
|
+
threadId,
|
|
1083
|
+
Number(threadType),
|
|
1084
|
+
);
|
|
1085
|
+
return sentReply("video", result);
|
|
1086
|
+
}
|
|
1087
|
+
if (bankCard || qrTransfer) {
|
|
1088
|
+
const spec = bankCard || qrTransfer;
|
|
1089
|
+
const bin = resolveBankBin(spec.bank);
|
|
1090
|
+
if (!bin)
|
|
1091
|
+
return err(`Unknown bank: '${spec.bank}'. zalo_bank 'banks' lists the banks Zalo supports.`);
|
|
1092
|
+
if (bankCard) {
|
|
1093
|
+
const payload = { binBank: bin, numAccBank: bankCard.accountNumber };
|
|
1094
|
+
if (bankCard.holderName) payload.nameAccBank = bankCard.holderName;
|
|
1095
|
+
const result = await api.sendBankCard(payload, threadId, Number(threadType));
|
|
1096
|
+
return sentReply("bank_card", result, { bank: BIN_TO_DISPLAY[bin] || String(bin) });
|
|
1097
|
+
}
|
|
1098
|
+
const qrPath = await generateQrTransferImage(
|
|
1099
|
+
bin,
|
|
1100
|
+
qrTransfer.accountNumber,
|
|
1101
|
+
qrTransfer.amount,
|
|
1102
|
+
qrTransfer.content,
|
|
1103
|
+
qrTransfer.template ?? "compact",
|
|
1104
|
+
);
|
|
1105
|
+
if (!qrPath) return err("Could not generate the VietQR image; nothing was sent.");
|
|
1106
|
+
try {
|
|
1107
|
+
const caption = text || qrTransferCaption(bin, qrTransfer);
|
|
1108
|
+
const result = await api.sendMessage(
|
|
1109
|
+
{ msg: caption, attachments: [qrPath] },
|
|
1110
|
+
threadId,
|
|
1111
|
+
Number(threadType),
|
|
1112
|
+
);
|
|
1113
|
+
const att = Array.isArray(result?.attachment) ? result.attachment[0] : result?.attachment;
|
|
1114
|
+
return sentReply("qr_transfer", result?.message ?? att ?? result, {
|
|
1115
|
+
bank: BIN_TO_DISPLAY[bin] || String(bin),
|
|
1116
|
+
});
|
|
1117
|
+
} finally {
|
|
1118
|
+
try {
|
|
1119
|
+
unlinkSync(qrPath);
|
|
1120
|
+
} catch {
|
|
1121
|
+
/* a temp file left behind is harmless */
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
609
1126
|
if (cardUserId) {
|
|
610
1127
|
const result = await api.sendCard({ userId: cardUserId }, threadId, Number(threadType));
|
|
611
1128
|
const messageId = result?.msgId ?? result?.message?.msgId ?? null;
|
|
@@ -614,10 +1131,9 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
614
1131
|
success: true,
|
|
615
1132
|
kind: "card",
|
|
616
1133
|
cardUserId,
|
|
617
|
-
messageId,
|
|
618
1134
|
msgId: messageId,
|
|
619
1135
|
...(cliMsgId !== null && { cliMsgId: String(cliMsgId) }),
|
|
620
|
-
threadType,
|
|
1136
|
+
threadType: threadTypeName(threadType),
|
|
621
1137
|
...(thread.notice && { threadId, notice: thread.notice }),
|
|
622
1138
|
});
|
|
623
1139
|
}
|
|
@@ -631,10 +1147,9 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
631
1147
|
success: true,
|
|
632
1148
|
kind: "link",
|
|
633
1149
|
link,
|
|
634
|
-
messageId,
|
|
635
1150
|
msgId: messageId,
|
|
636
1151
|
...(cliMsgId !== null && { cliMsgId: String(cliMsgId) }),
|
|
637
|
-
threadType,
|
|
1152
|
+
threadType: threadTypeName(threadType),
|
|
638
1153
|
...(thread.notice && { threadId, notice: thread.notice }),
|
|
639
1154
|
});
|
|
640
1155
|
}
|
|
@@ -677,16 +1192,15 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
677
1192
|
kind: "attachment",
|
|
678
1193
|
files: absPaths,
|
|
679
1194
|
sent,
|
|
680
|
-
messageId,
|
|
681
1195
|
msgId: messageId,
|
|
682
1196
|
...(cliMsgId !== null && { cliMsgId: String(cliMsgId) }),
|
|
683
|
-
threadType,
|
|
1197
|
+
threadType: threadTypeName(threadType),
|
|
684
1198
|
...(thread.notice && { threadId, notice: thread.notice }),
|
|
685
1199
|
});
|
|
686
1200
|
}
|
|
687
1201
|
|
|
688
1202
|
if (!text) {
|
|
689
|
-
return err(
|
|
1203
|
+
return err(`Provide text, or one of ${SEND_MODES.join(", ")}.`);
|
|
690
1204
|
}
|
|
691
1205
|
|
|
692
1206
|
const warnings = [];
|
|
@@ -712,12 +1226,12 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
712
1226
|
const mentions = expanded.mentions;
|
|
713
1227
|
const styles = shiftStyles(converted.styles, expanded.edits);
|
|
714
1228
|
|
|
715
|
-
//
|
|
1229
|
+
// The session drops mentions outside a group, so a DM send would
|
|
716
1230
|
// quietly arrive with the names as plain text and nobody tagged.
|
|
717
1231
|
if (mentions.length > 0 && Number(threadType) !== THREAD_GROUP) {
|
|
718
1232
|
warnings.push(
|
|
719
1233
|
"Mentions only apply to group messages. This was sent with threadType " +
|
|
720
|
-
`${
|
|
1234
|
+
`${threadTypeName(threadType)}, so the names went out as plain text and nobody was tagged.`,
|
|
721
1235
|
);
|
|
722
1236
|
}
|
|
723
1237
|
|
|
@@ -728,12 +1242,13 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
728
1242
|
// open reads as "not cached", whose message names the fix.
|
|
729
1243
|
let row = null;
|
|
730
1244
|
try {
|
|
731
|
-
row =
|
|
1245
|
+
row = getMessageForAction(quoteMsgId);
|
|
732
1246
|
} catch (e) {
|
|
1247
|
+
if (e?.code === "ROW_MAC") return err(e.message);
|
|
733
1248
|
console.error("[mcp-tools] cache unavailable for quote:", e.message);
|
|
734
1249
|
}
|
|
735
1250
|
const built = buildQuote(row, { msgId: quoteMsgId, threadId });
|
|
736
|
-
// Reported through err() rather than letting
|
|
1251
|
+
// Reported through err() rather than letting the session raise a
|
|
737
1252
|
// raw ZaloApiError: "stickers can't be quoted" and "not
|
|
738
1253
|
// cached, fetch the thread" are different problems and the
|
|
739
1254
|
// agent can act on both.
|
|
@@ -760,11 +1275,11 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
760
1275
|
if (hasLiteralNewline(text)) warnings.push(LITERAL_NEWLINE_WARNING);
|
|
761
1276
|
|
|
762
1277
|
// 1 (important) or 2 (urgent), mapped exactly as `msg send
|
|
763
|
-
// --urgency` maps it;
|
|
764
|
-
// {urgency}` Zalo
|
|
1278
|
+
// --urgency` maps it; the session turns it into the `metaData:
|
|
1279
|
+
// {urgency}` Zalo sends. "normal" is no urgency at all.
|
|
765
1280
|
const urgency = urgencyIn ? urgencyLevel(urgencyIn) : null;
|
|
766
1281
|
|
|
767
|
-
// Zalo refuses one oversized message (114 plain, 112 styled), so a long text goes out as
|
|
1282
|
+
// Zalo refuses one oversized message (114 plain, 112 styled), so a long text goes out as Zalo sends
|
|
768
1283
|
// it: split at 3000 bytes of text plus styles, in order, 300 ms apart. The quote and the urgency
|
|
769
1284
|
// belong to the first part only.
|
|
770
1285
|
const parts = splitMessage({ text: expanded.text, styles, mentions });
|
|
@@ -795,10 +1310,9 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
795
1310
|
const cliMsgId = result?.message?.cliMsgId ?? result?.cliMsgId ?? null;
|
|
796
1311
|
return ok({
|
|
797
1312
|
success: true,
|
|
798
|
-
messageId,
|
|
799
1313
|
msgId: messageId,
|
|
800
1314
|
...(cliMsgId !== null && { cliMsgId: String(cliMsgId) }),
|
|
801
|
-
threadType,
|
|
1315
|
+
threadType: threadTypeName(threadType),
|
|
802
1316
|
// Only for `me`: the thread it really went to, which is
|
|
803
1317
|
// what a later zalo_get_history names.
|
|
804
1318
|
...(thread.notice && { threadId, notice: thread.notice }),
|
|
@@ -815,7 +1329,6 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
815
1329
|
const partCli = r?.message?.cliMsgId ?? r?.cliMsgId ?? null;
|
|
816
1330
|
return {
|
|
817
1331
|
msgId: partId,
|
|
818
|
-
messageId: partId,
|
|
819
1332
|
...(partCli !== null && { cliMsgId: String(partCli) }),
|
|
820
1333
|
};
|
|
821
1334
|
}),
|
|
@@ -848,7 +1361,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
848
1361
|
async ({ type, consumer }) => {
|
|
849
1362
|
try {
|
|
850
1363
|
// Unread is per consumer: after what this consumer marked read.
|
|
851
|
-
const stats = buffer.getStats(buffer.readCursor(consumer));
|
|
1364
|
+
const stats = withoutHidden(buffer.getStats(buffer.readCursor(consumer)), hiddenSet(), hiddenMode());
|
|
852
1365
|
const dmNames = await resolveCurrentUserNames(
|
|
853
1366
|
api,
|
|
854
1367
|
stats.filter((t) => buffer.getThreadType(t.threadId) === "dm").map((t) => t.threadId),
|
|
@@ -858,6 +1371,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
858
1371
|
stats.map((t) => String(t.threadId)),
|
|
859
1372
|
);
|
|
860
1373
|
// Enrich each stat entry with threadType, thread name and read state
|
|
1374
|
+
const gone = goneGroupMap();
|
|
861
1375
|
const enriched = stats.map((t) => {
|
|
862
1376
|
const threadType = buffer.getThreadType(t.threadId) ?? "unknown";
|
|
863
1377
|
const cached = nameCache?.get(t.threadId);
|
|
@@ -867,6 +1381,8 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
867
1381
|
name: dmNames.get(String(t.threadId))?.name ?? cached?.name ?? null,
|
|
868
1382
|
...(cached?.memberCount !== undefined && { memberCount: cached.memberCount }),
|
|
869
1383
|
readState: describeReadState(reads.get(String(t.threadId))),
|
|
1384
|
+
// Left, removed, blocked or disbanded (src/core/group-exit.js); sends to it are refused.
|
|
1385
|
+
...goneFields(gone.get(String(t.threadId)) ?? null),
|
|
870
1386
|
};
|
|
871
1387
|
});
|
|
872
1388
|
const filtered = type === "all" ? enriched : enriched.filter((t) => t.threadType === type);
|
|
@@ -884,7 +1400,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
884
1400
|
{
|
|
885
1401
|
title: "Search Zalo Threads",
|
|
886
1402
|
description:
|
|
887
|
-
"Find a conversation by name, to get its `threadId`. It is a fuzzy search that ignores case and Vietnamese accents, over the names this server knows (cached contacts and groups)
|
|
1403
|
+
"Find a conversation by name, to get its `threadId`. It is a fuzzy search that ignores case and Vietnamese accents, over the names this server knows (cached contacts and groups); every match is returned unless you pass `limit`. To find a person by phone number or username instead, use zalo_lookup_user. " +
|
|
888
1404
|
"Returns `{ results, total }`; use a result's `threadId` in zalo_send_message, zalo_get_history and the other tools.",
|
|
889
1405
|
inputSchema: z.object({
|
|
890
1406
|
query: z.string().min(1).describe("Search keyword (fuzzy match, case-insensitive, accent-insensitive)"),
|
|
@@ -892,7 +1408,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
892
1408
|
.enum(["group", "dm", "all"])
|
|
893
1409
|
.default("all")
|
|
894
1410
|
.describe("Filter by thread type: 'dm', 'group', or 'all'"),
|
|
895
|
-
limit: z.number().int().min(1).
|
|
1411
|
+
limit: z.number().int().min(1).optional().describe("Max results to return (omit for every match)"),
|
|
896
1412
|
}),
|
|
897
1413
|
},
|
|
898
1414
|
async ({ query, type, limit }) => {
|
|
@@ -901,7 +1417,13 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
901
1417
|
return err("Thread name cache not initialized yet. Try again shortly.");
|
|
902
1418
|
}
|
|
903
1419
|
await nameCache.refreshUsers?.(api);
|
|
904
|
-
|
|
1420
|
+
// Over-fetch by the hidden count, so a left-out conversation does not shorten the list.
|
|
1421
|
+
const all = withoutHidden(
|
|
1422
|
+
nameCache.search(query, type, limit ? limit + hiddenIds().length : null),
|
|
1423
|
+
hiddenSet(),
|
|
1424
|
+
hiddenMode(),
|
|
1425
|
+
);
|
|
1426
|
+
const results = limit ? all.slice(0, limit) : all;
|
|
905
1427
|
return ok({ results, total: results.length });
|
|
906
1428
|
} catch (e) {
|
|
907
1429
|
console.error("[mcp-tools] zalo_search_threads error:", e.message);
|
|
@@ -945,31 +1467,35 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
945
1467
|
{
|
|
946
1468
|
title: "Get Zalo Message History",
|
|
947
1469
|
description:
|
|
948
|
-
"Get the stored messages of one conversation (DM or group), for context older than the live buffer. It reads the local cache first (everything the listener and `zalo-agent sync` have saved, which can be the full history) and asks the Zalo server only when the cache has nothing for the thread. " +
|
|
949
|
-
"
|
|
950
|
-
"Each message has `msgId`, `senderId`, `senderDisplayName` (the current name: your alias, else the Zalo
|
|
951
|
-
"
|
|
1470
|
+
"Get the stored messages of one conversation (DM or group), for context older than the live buffer. It reads the local cache first (everything the listener and `zalo-agent sync` have saved, which can be the full history) and asks the Zalo server only when the cache has nothing for the thread: a group's message store, paged back until it has nothing older. A DM has no server history (Zalo's own apps show 1-1 history from the device's own store), so for a DM only `scan` asks Zalo, by scanning the socket's old-message stream. " +
|
|
1471
|
+
"Without `limit` the reply holds every message (all cached ones, or everything the group's store serves); pass `limit` to page, then page back with `before` (epoch ms: the `cursor` of the previous reply) or, on the server path, `lastMsgId` (the previous reply's `cursor`). Zalo's server serves only messages since this login: `filtered: true` in the reply means older ones exist that only `zalo-agent sync` can restore, and that needs the owner's phone. " +
|
|
1472
|
+
"Each message has `msgId`, `senderId`, `senderName` (your alias for the sender when you set one, else the name the message carried), `senderAlias`, `senderZaloName` (the name the message carried), `senderDisplayName` (the current name: your alias, else the phonebook name, else the Zalo name, else the display name, else the uid; `senderDisplayNameSource` says which), `text`, `timestamp` and `type`. Reply: `{ threadId, threadType, count, messages, cursor, hasMore }`. " +
|
|
1473
|
+
"For one period, pass `since` and/or `until` (epoch ms) or `last` (7d, 2w, 3m, 1y): the cached messages in it come oldest first, all of them, or `limit` per page with `hasMore` and `nextSince` (pass it back as `since`, same `until`) for the rest. Reply: `{ threadId, since, until, count, messages, hasMore, nextSince }`. It reads only the cache. " +
|
|
1474
|
+
"A long conversation is a large reply; pass `limit` to page through it. To find messages by their text, use zalo_search_messages.",
|
|
952
1475
|
inputSchema: z.object({
|
|
953
1476
|
threadId: z
|
|
954
1477
|
.string()
|
|
955
1478
|
.describe("The conversation: the other person's user id for a DM, the group id for a group."),
|
|
956
1479
|
threadType: z
|
|
957
|
-
.
|
|
958
|
-
.int()
|
|
959
|
-
.min(0)
|
|
960
|
-
.max(1)
|
|
1480
|
+
.enum(["dm", "group"])
|
|
961
1481
|
.optional()
|
|
962
1482
|
.describe(
|
|
963
|
-
|
|
964
|
-
"Pass it only to override that.",
|
|
1483
|
+
'The conversation type: "dm" or "group". Leave it out: the type stored for this thread is used. Pass it only to override that.',
|
|
965
1484
|
),
|
|
966
1485
|
limit: z
|
|
967
1486
|
.number()
|
|
968
1487
|
.int()
|
|
969
1488
|
.min(1)
|
|
970
|
-
.
|
|
971
|
-
.
|
|
972
|
-
|
|
1489
|
+
.optional()
|
|
1490
|
+
.describe("Page size: the most messages to return. Leave it out for every message."),
|
|
1491
|
+
scan: z
|
|
1492
|
+
.number()
|
|
1493
|
+
.int()
|
|
1494
|
+
.min(1)
|
|
1495
|
+
.optional()
|
|
1496
|
+
.describe(
|
|
1497
|
+
"Server path only, when the cache has nothing: also scan the socket's old-message stream, at most this many raw messages (a DM, or a group whose store failed). Off unless given.",
|
|
1498
|
+
),
|
|
973
1499
|
lastMsgId: z
|
|
974
1500
|
.string()
|
|
975
1501
|
.optional()
|
|
@@ -983,10 +1509,56 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
983
1509
|
.describe(
|
|
984
1510
|
"Cache path: only messages older than this epoch-ms timestamp (the `cursor` of the previous reply), to page back.",
|
|
985
1511
|
),
|
|
1512
|
+
since: z
|
|
1513
|
+
.number()
|
|
1514
|
+
.int()
|
|
1515
|
+
.nonnegative()
|
|
1516
|
+
.optional()
|
|
1517
|
+
.describe(
|
|
1518
|
+
"Only messages at or after this time (epoch ms), oldest first; or the `nextSince` of the previous reply.",
|
|
1519
|
+
),
|
|
1520
|
+
until: z
|
|
1521
|
+
.number()
|
|
1522
|
+
.int()
|
|
1523
|
+
.positive()
|
|
1524
|
+
.optional()
|
|
1525
|
+
.describe("Only messages at or before this time (epoch ms)."),
|
|
1526
|
+
last: z
|
|
1527
|
+
.string()
|
|
1528
|
+
.optional()
|
|
1529
|
+
.describe("Only the last period, ending now: 7d, 2w, 3m, 1y or 12h (replaces `since`)."),
|
|
986
1530
|
}),
|
|
987
1531
|
},
|
|
988
|
-
async ({ threadId, threadType: threadTypeIn, limit, lastMsgId, before }) => {
|
|
1532
|
+
async ({ threadId, threadType: threadTypeIn, limit: limitIn, scan, lastMsgId, before, since, until, last }) => {
|
|
1533
|
+
if (isHiddenThread(threadId)) return err(HIDDEN_THREAD);
|
|
989
1534
|
const threadType = resolveThreadType(threadId, threadTypeIn);
|
|
1535
|
+
// No limit: every message. A limit is a page.
|
|
1536
|
+
const limit = limitIn ?? Infinity;
|
|
1537
|
+
if (since !== undefined || until !== undefined || last !== undefined) {
|
|
1538
|
+
if (before !== undefined || lastMsgId) {
|
|
1539
|
+
return err("Use either a period (`since`, `until`, `last`) or `before`/`lastMsgId`, not both.");
|
|
1540
|
+
}
|
|
1541
|
+
let from;
|
|
1542
|
+
try {
|
|
1543
|
+
from = last !== undefined ? parsePeriod(last) : (since ?? null);
|
|
1544
|
+
} catch (e) {
|
|
1545
|
+
return err(e.message);
|
|
1546
|
+
}
|
|
1547
|
+
const to = until ?? null;
|
|
1548
|
+
if (from !== null && to !== null && from > to) return err("`since` is after `until`.");
|
|
1549
|
+
try {
|
|
1550
|
+
const page = cacheHistoryRange(threadId, { since: from, until: to, limit }, nameCache);
|
|
1551
|
+
page.threadType = threadType === THREAD_USER ? "dm" : "group";
|
|
1552
|
+
page.messages = await withCurrentSenderNames(
|
|
1553
|
+
api,
|
|
1554
|
+
page.messages,
|
|
1555
|
+
threadType === THREAD_USER ? [threadId] : [],
|
|
1556
|
+
);
|
|
1557
|
+
return ok(page);
|
|
1558
|
+
} catch (e) {
|
|
1559
|
+
return err(`The local cache could not be read: ${e.message}`);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
990
1562
|
try {
|
|
991
1563
|
// The cache is the better source and usually the only one that
|
|
992
1564
|
// answers: Zalo returns an empty set for the socket history
|
|
@@ -1021,7 +1593,9 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1021
1593
|
let fetched;
|
|
1022
1594
|
try {
|
|
1023
1595
|
fetched = await fetchAndCacheHistory(api, threadId, threadType, {
|
|
1024
|
-
limit,
|
|
1596
|
+
limit: Number.isFinite(limit) ? limit : null,
|
|
1597
|
+
// The socket scan is opt-in, as `msg history --scan`.
|
|
1598
|
+
...(scan && { scanLimit: scan }),
|
|
1025
1599
|
fromMsgId: lastMsgId || null,
|
|
1026
1600
|
});
|
|
1027
1601
|
} finally {
|
|
@@ -1034,12 +1608,14 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1034
1608
|
const isText = typeof rawContent === "string";
|
|
1035
1609
|
return {
|
|
1036
1610
|
msgId: d.msgId,
|
|
1611
|
+
cliMsgId: d.cliMsgId ? String(d.cliMsgId) : undefined,
|
|
1037
1612
|
threadId: f.threadId,
|
|
1038
1613
|
senderId: d.uidFrom || null,
|
|
1039
|
-
|
|
1614
|
+
...senderNameFields(d.uidFrom, d.dName),
|
|
1040
1615
|
text: isText ? rawContent : extractMessageText(rawContent, d.msgType),
|
|
1041
1616
|
timestamp: d.ts ? Number(d.ts) : null,
|
|
1042
1617
|
type: isText ? "text" : d.msgType || "attachment",
|
|
1618
|
+
replyTo: resolveReplyTo(quotedReply(d.quote), f.threadId),
|
|
1043
1619
|
};
|
|
1044
1620
|
});
|
|
1045
1621
|
|
|
@@ -1070,14 +1646,21 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1070
1646
|
cursor,
|
|
1071
1647
|
hasMore: Boolean(fetched.more) || (fetched.source === "socket" && allMessages.length >= limit),
|
|
1072
1648
|
filtered: fetched.filtered === true,
|
|
1073
|
-
...(fetched.
|
|
1649
|
+
...(fetched.source === "none" && threadType === THREAD_USER
|
|
1074
1650
|
? {
|
|
1075
1651
|
note:
|
|
1076
|
-
"
|
|
1077
|
-
"
|
|
1078
|
-
"
|
|
1652
|
+
"Nothing is cached for this conversation, and Zalo keeps no server history for a " +
|
|
1653
|
+
"1-1 conversation. `scan` asks the socket's old-message stream; `zalo-agent sync` " +
|
|
1654
|
+
"restores from the owner's phone (it asks for a tap).",
|
|
1079
1655
|
}
|
|
1080
|
-
:
|
|
1656
|
+
: fetched.filtered || allMessages.length === 0
|
|
1657
|
+
? {
|
|
1658
|
+
note:
|
|
1659
|
+
"Zalo serves a conversation's messages only since this login; older ones are " +
|
|
1660
|
+
"withheld. `zalo-agent sync` restores them from the owner's phone (it asks for a " +
|
|
1661
|
+
"tap), and zalo_get_history then reads them from the cache.",
|
|
1662
|
+
}
|
|
1663
|
+
: {}),
|
|
1081
1664
|
});
|
|
1082
1665
|
} catch (e) {
|
|
1083
1666
|
console.error("[mcp-tools] zalo_get_history error:", e.message);
|
|
@@ -1088,29 +1671,40 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1088
1671
|
|
|
1089
1672
|
// --- zalo_view_media ---
|
|
1090
1673
|
const mediaConfig = config.media || {};
|
|
1674
|
+
/** The account the cached media is sealed for (its folder holds the keyring). */
|
|
1675
|
+
const mediaScope = () => scopeOfDir(accountDir || getAccountDir(String(ownIdOf(api) ?? "")));
|
|
1091
1676
|
server.registerTool(
|
|
1092
1677
|
"zalo_view_media",
|
|
1093
1678
|
{
|
|
1094
1679
|
title: "View Zalo Media",
|
|
1095
1680
|
description:
|
|
1096
|
-
"Get a received photo, voice message, video or file
|
|
1097
|
-
"
|
|
1681
|
+
"Get a received photo, sticker, voice message, video or file. The cached file is encrypted; it reaches you one of three ways (`deliver`): " +
|
|
1682
|
+
'"inline" (the picture or voice itself, as image or audio content, up to about 5 MB), "link" (`url`, a link to this server that works for 10 minutes; ' +
|
|
1683
|
+
'it may need the same Authorization as this server), or "tempfile" (`path`, a private decrypted copy on the machine this server runs on, deleted at `expiresAt`; only for a client on that machine). ' +
|
|
1684
|
+
"By default pictures and voice come inline and videos and files as a link, as the server is configured. Media not downloaded yet is downloaded first. " +
|
|
1685
|
+
"Returns `{ success, msgId, mediaType, delivery, mimeType, size }` plus `url`/`path` and `expiresAt`, and `notes` when the delivery differs from the one asked for.",
|
|
1098
1686
|
inputSchema: z.object({
|
|
1099
1687
|
msgId: z
|
|
1100
1688
|
.string()
|
|
1101
1689
|
.describe(
|
|
1102
|
-
"msgId of a message that has a photo, voice message, video or file (from zalo_get_messages, zalo_wait_for_message or zalo_get_history).",
|
|
1690
|
+
"msgId of a message that has a photo, sticker, voice message, video or file (from zalo_get_messages, zalo_wait_for_message or zalo_get_history).",
|
|
1103
1691
|
),
|
|
1104
1692
|
threadId: z.string().optional().describe("Only look in this conversation. Omit to search all of them."),
|
|
1693
|
+
deliver: z
|
|
1694
|
+
.enum(["inline", "link", "tempfile"])
|
|
1695
|
+
.optional()
|
|
1696
|
+
.describe(
|
|
1697
|
+
'How to get it: "inline", "link" or "tempfile". Omit for the server\'s default for this kind of media. The server may forbid a mode (media.allowDeliver).',
|
|
1698
|
+
),
|
|
1105
1699
|
open: z
|
|
1106
1700
|
.boolean()
|
|
1107
|
-
.
|
|
1701
|
+
.optional()
|
|
1108
1702
|
.describe(
|
|
1109
|
-
"Also open
|
|
1703
|
+
"Also open it with the viewer of the machine this server runs on (a local stdio server only; it delivers a tempfile). Omit for the server's default (media.autoOpen).",
|
|
1110
1704
|
),
|
|
1111
1705
|
}),
|
|
1112
1706
|
},
|
|
1113
|
-
async ({ msgId, threadId, open }) => {
|
|
1707
|
+
async ({ msgId, threadId, deliver, open }) => {
|
|
1114
1708
|
try {
|
|
1115
1709
|
// The cached row is authoritative: it records where a fetched
|
|
1116
1710
|
// file actually landed, so a message that arrived before this
|
|
@@ -1118,12 +1712,64 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1118
1712
|
// fallback for a thread id.
|
|
1119
1713
|
let row = null;
|
|
1120
1714
|
try {
|
|
1121
|
-
row =
|
|
1715
|
+
row = getMessageForAction(msgId);
|
|
1122
1716
|
} catch (e) {
|
|
1717
|
+
if (e?.code === "ROW_MAC") return err(e.message);
|
|
1123
1718
|
console.error("[mcp-tools] cache unavailable:", e.message);
|
|
1124
1719
|
}
|
|
1125
|
-
const buffered = buffer.read(threadId, 0
|
|
1720
|
+
const buffered = buffer.read(threadId, 0).messages.find((m) => m.msgId === msgId) || null;
|
|
1126
1721
|
if (!row && !buffered) return err(`Message ${msgId} not found in cache or buffer`);
|
|
1722
|
+
const kind = String(row?.type || buffered?.type || "");
|
|
1723
|
+
const msgThread = row?.threadId ?? buffered?.threadId ?? threadId ?? null;
|
|
1724
|
+
// A hidden chat's media is left out like its messages: no inline content, no link, no copy.
|
|
1725
|
+
if (isHiddenThread(msgThread)) return err(HIDDEN_THREAD);
|
|
1726
|
+
|
|
1727
|
+
const accountId = String(ownIdOf(api) ?? "");
|
|
1728
|
+
const policy = resolveMediaDelivery({ config, accountId: accountId || undefined });
|
|
1729
|
+
const stdio = server?.statelessHttp !== true;
|
|
1730
|
+
const choose = (size, mime) =>
|
|
1731
|
+
chooseDelivery({
|
|
1732
|
+
kind,
|
|
1733
|
+
size,
|
|
1734
|
+
mime,
|
|
1735
|
+
requested: deliver ?? null,
|
|
1736
|
+
open,
|
|
1737
|
+
policy,
|
|
1738
|
+
stdio,
|
|
1739
|
+
clientLoopback: server?.clientLoopback === true,
|
|
1740
|
+
});
|
|
1741
|
+
|
|
1742
|
+
// A sticker is not downloaded with the messages: its picture is fetched now, shown inline and not kept.
|
|
1743
|
+
if (kind === "sticker" && !row?.localPath) {
|
|
1744
|
+
const sticker = await stickerPicture(api, row, buffered);
|
|
1745
|
+
if (sticker.error) return err(sticker.error);
|
|
1746
|
+
const pick = choose(sticker.bytes.length, sticker.mime);
|
|
1747
|
+
if (pick.error) return err(pick.error);
|
|
1748
|
+
if (pick.mode !== "inline") {
|
|
1749
|
+
return err(
|
|
1750
|
+
"A sticker is not stored on this server, so it can only be sent inline" +
|
|
1751
|
+
(pick.notes.length ? ` (${pick.notes.join("; ")})` : "") +
|
|
1752
|
+
".",
|
|
1753
|
+
);
|
|
1754
|
+
}
|
|
1755
|
+
return {
|
|
1756
|
+
content: [
|
|
1757
|
+
{
|
|
1758
|
+
type: "text",
|
|
1759
|
+
text: JSON.stringify({
|
|
1760
|
+
success: true,
|
|
1761
|
+
msgId,
|
|
1762
|
+
mediaType: kind,
|
|
1763
|
+
delivery: "inline",
|
|
1764
|
+
mimeType: sticker.mime,
|
|
1765
|
+
size: sticker.bytes.length,
|
|
1766
|
+
}),
|
|
1767
|
+
},
|
|
1768
|
+
inlineContent(sticker.bytes, kind, sticker.mime),
|
|
1769
|
+
],
|
|
1770
|
+
};
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1127
1773
|
if (row && !row.has_attachment && !buffered?.attachment?.url) {
|
|
1128
1774
|
return err(`Message ${msgId} has no media attachment`);
|
|
1129
1775
|
}
|
|
@@ -1131,13 +1777,15 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1131
1777
|
let localPath = row?.localPath || null;
|
|
1132
1778
|
if (!localPath) {
|
|
1133
1779
|
// Same downloader as the CLI, so the file lands in the one
|
|
1134
|
-
// per-conversation folder every other command reads from.
|
|
1780
|
+
// per-conversation folder every other command reads from. It is asked for this message by
|
|
1781
|
+
// id: a scan of the thread's newest pending attachments could leave an older one out.
|
|
1135
1782
|
const stats = await downloadSyncedMedia({
|
|
1136
1783
|
api,
|
|
1137
1784
|
accountDir,
|
|
1138
|
-
threadId: String(
|
|
1139
|
-
|
|
1140
|
-
|
|
1785
|
+
threadId: String(msgThread || ""),
|
|
1786
|
+
msgIds: [String(row?.msgId ?? msgId)],
|
|
1787
|
+
limit: 1,
|
|
1788
|
+
concurrency: 1,
|
|
1141
1789
|
mediaRoot: process.env.ZALO_MEDIA_DIR || mediaConfig.downloadDir || undefined,
|
|
1142
1790
|
});
|
|
1143
1791
|
localPath = getMessageById(msgId)?.localPath || null;
|
|
@@ -1152,9 +1800,42 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1152
1800
|
}
|
|
1153
1801
|
}
|
|
1154
1802
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1803
|
+
// The cached file stays sealed (keystore/media-seal.js): it is delivered inline, as a link served from
|
|
1804
|
+
// the sealed file, or as a private decrypted copy (src/core/media-deliver.js).
|
|
1805
|
+
const info = mediaInfo(localPath);
|
|
1806
|
+
const pick = choose(info.size, info.mime);
|
|
1807
|
+
if (pick.error) return err(pick.error);
|
|
1808
|
+
const out = await deliverCachedMedia({
|
|
1809
|
+
mode: pick.mode,
|
|
1810
|
+
file: localPath,
|
|
1811
|
+
scope: mediaScope(),
|
|
1812
|
+
msgId: row?.msgId ?? msgId,
|
|
1813
|
+
threadId: msgThread,
|
|
1814
|
+
accountId,
|
|
1815
|
+
info,
|
|
1816
|
+
policy,
|
|
1817
|
+
ensureServed: ensureMediaServed,
|
|
1818
|
+
});
|
|
1819
|
+
if (pick.open && out.path) openFile(out.path);
|
|
1820
|
+
const reply = {
|
|
1821
|
+
success: true,
|
|
1822
|
+
msgId,
|
|
1823
|
+
mediaType: kind || null,
|
|
1824
|
+
delivery: out.mode,
|
|
1825
|
+
mimeType: out.mimeType,
|
|
1826
|
+
size: out.size,
|
|
1827
|
+
...(out.url ? { url: out.url, auth: out.auth } : {}),
|
|
1828
|
+
...(out.path ? { path: out.path, opened: pick.open } : {}),
|
|
1829
|
+
...(out.expiresAt ? { expiresAt: new Date(out.expiresAt).toISOString() } : {}),
|
|
1830
|
+
...(pick.notes.length ? { notes: pick.notes } : {}),
|
|
1831
|
+
};
|
|
1832
|
+
if (out.mode !== "inline") return ok(reply);
|
|
1833
|
+
return {
|
|
1834
|
+
content: [
|
|
1835
|
+
{ type: "text", text: JSON.stringify(reply) },
|
|
1836
|
+
inlineContent(out.bytes, kind, out.mimeType),
|
|
1837
|
+
],
|
|
1838
|
+
};
|
|
1158
1839
|
} catch (e) {
|
|
1159
1840
|
console.error("[mcp-tools] zalo_view_media error:", e.message);
|
|
1160
1841
|
return err(e.message);
|
|
@@ -1164,14 +1845,10 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1164
1845
|
|
|
1165
1846
|
// The threadType parameter of the message actions, worded as the send's is.
|
|
1166
1847
|
const threadTypeSchema = z
|
|
1167
|
-
.
|
|
1168
|
-
.int()
|
|
1169
|
-
.min(0)
|
|
1170
|
-
.max(1)
|
|
1848
|
+
.enum(["dm", "group"])
|
|
1171
1849
|
.optional()
|
|
1172
1850
|
.describe(
|
|
1173
|
-
|
|
1174
|
-
"Pass it only to override that.",
|
|
1851
|
+
'The conversation type: "dm" or "group". Leave it out: the type stored for this thread is used. Pass it only to override that.',
|
|
1175
1852
|
);
|
|
1176
1853
|
const cliMsgIdSchema = z
|
|
1177
1854
|
.string()
|
|
@@ -1238,7 +1915,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1238
1915
|
msgId,
|
|
1239
1916
|
cliMsgId: target.cliMsgId,
|
|
1240
1917
|
threadId,
|
|
1241
|
-
threadType,
|
|
1918
|
+
threadType: threadTypeName(threadType),
|
|
1242
1919
|
...(thread.notice && { notice: thread.notice }),
|
|
1243
1920
|
});
|
|
1244
1921
|
} catch (e) {
|
|
@@ -1254,7 +1931,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1254
1931
|
{
|
|
1255
1932
|
title: "Recall a Zalo Message",
|
|
1256
1933
|
description:
|
|
1257
|
-
'Recall (unsend) one of your own messages for everyone in the conversation, as the apps\' "Thu hồi" does. Zalo accepts a recall only for a while after the message was sent. ' +
|
|
1934
|
+
'Recall (unsend) one of your own messages for everyone in the conversation, as the apps\' "Thu hồi" does. Zalo accepts a recall only for a while after the message was sent. It cannot be undone, so it is asked about first (`confirm`, `dryRun`). ' +
|
|
1258
1935
|
"Give the message's `msgId` (from the zalo_send_message reply, or from zalo_get_history) and its `cliMsgId` (also in the send reply; read from the local cache when you leave it out); with neither, nothing is sent. To remove a message from your own view only, or someone else's message in a group as an admin, use zalo_delete_message. `threadId` may be `me` for My Documents.",
|
|
1259
1936
|
inputSchema: z.object({
|
|
1260
1937
|
msgId: z
|
|
@@ -1271,9 +1948,12 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1271
1948
|
),
|
|
1272
1949
|
threadType: threadTypeSchema,
|
|
1273
1950
|
cliMsgId: cliMsgIdSchema,
|
|
1951
|
+
confirm: confirmInput("the recall"),
|
|
1952
|
+
ticket: ticketInput(),
|
|
1953
|
+
dryRun: dryRunInput("the recall"),
|
|
1274
1954
|
}),
|
|
1275
1955
|
},
|
|
1276
|
-
async ({ msgId, threadId: threadIdIn, threadType: threadTypeIn, cliMsgId }) => {
|
|
1956
|
+
async ({ msgId, threadId: threadIdIn, threadType: threadTypeIn, cliMsgId, confirm, dryRun, ticket }, extra) => {
|
|
1277
1957
|
const thread = actionThread(api, threadIdIn, threadTypeIn);
|
|
1278
1958
|
if (thread.error) {
|
|
1279
1959
|
console.error("[mcp-tools] zalo_undo refused:", thread.error);
|
|
@@ -1287,13 +1967,30 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1287
1967
|
console.error("[mcp-tools] zalo_undo refused:", target.error);
|
|
1288
1968
|
return err(target.error);
|
|
1289
1969
|
}
|
|
1290
|
-
|
|
1970
|
+
const held = await gate(
|
|
1971
|
+
"msg.undo",
|
|
1972
|
+
{ msgId, threadId, cliMsgId: target.cliMsgId },
|
|
1973
|
+
{ confirm, dryRun, ticket },
|
|
1974
|
+
extra,
|
|
1975
|
+
);
|
|
1976
|
+
if (held) return held;
|
|
1977
|
+
// A group recall carries the group's own visibility, from the thread cache or Zalo, as `msg undo`.
|
|
1978
|
+
const payload = await undoPayload(
|
|
1979
|
+
api,
|
|
1980
|
+
{ msgId, cliMsgId: target.cliMsgId },
|
|
1981
|
+
threadId,
|
|
1982
|
+
Number(threadType),
|
|
1983
|
+
{
|
|
1984
|
+
cache: nameCache,
|
|
1985
|
+
},
|
|
1986
|
+
);
|
|
1987
|
+
await api.undo(payload, threadId, Number(threadType));
|
|
1291
1988
|
return ok({
|
|
1292
1989
|
success: true,
|
|
1293
1990
|
msgId,
|
|
1294
1991
|
cliMsgId: target.cliMsgId,
|
|
1295
1992
|
threadId,
|
|
1296
|
-
threadType,
|
|
1993
|
+
threadType: threadTypeName(threadType),
|
|
1297
1994
|
...(thread.notice && { notice: thread.notice }),
|
|
1298
1995
|
});
|
|
1299
1996
|
} catch (e) {
|
|
@@ -1309,7 +2006,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1309
2006
|
{
|
|
1310
2007
|
title: "List Zalo Group Members",
|
|
1311
2008
|
description:
|
|
1312
|
-
"List the members of a group: each member's `userId
|
|
2009
|
+
"List the members of a group: each member's `userId`, `displayName` (your alias for them when you set one, else their name from the cache, or from Zalo for members the cache cannot name), `alias` and `zaloName`, and `totalMember`, Zalo's own count (it can be larger than the members listed). Use a `userId` as `@[userId]` in zalo_send_message to mention that member.",
|
|
1313
2010
|
inputSchema: z.object({
|
|
1314
2011
|
groupId: z
|
|
1315
2012
|
.string()
|
|
@@ -1330,12 +2027,13 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1330
2027
|
// The cache first, as a mention is named; one batched lookup
|
|
1331
2028
|
// (the one `msg send` uses) for the members it cannot name.
|
|
1332
2029
|
// Nothing is written back: zalo.db has three writers.
|
|
2030
|
+
// `names` holds the name each member goes by on Zalo; the owner's alias is applied below.
|
|
1333
2031
|
const names = new Map();
|
|
1334
2032
|
const unnamed = [];
|
|
1335
2033
|
for (const uid of group.uids) {
|
|
1336
|
-
const name =
|
|
2034
|
+
const name = cachedStoredName(uid);
|
|
1337
2035
|
if (name) names.set(uid, name);
|
|
1338
|
-
else unnamed.push(uid);
|
|
2036
|
+
else if (!aliasFor(uid)) unnamed.push(uid);
|
|
1339
2037
|
}
|
|
1340
2038
|
const warnings = [];
|
|
1341
2039
|
if (unnamed.length > 0) {
|
|
@@ -1348,7 +2046,12 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1348
2046
|
}
|
|
1349
2047
|
for (const w of warnings) console.error("[mcp-tools] zalo_get_group_members warning:", w);
|
|
1350
2048
|
|
|
1351
|
-
|
|
2049
|
+
// `displayName` alias first, as Zalo's member list shows them; `alias` and `zaloName` beside it.
|
|
2050
|
+
const members = group.uids.map((uid) => {
|
|
2051
|
+
const alias = aliasFor(uid);
|
|
2052
|
+
const zaloName = names.get(uid) ?? null;
|
|
2053
|
+
return { userId: uid, displayName: alias ?? zaloName, alias, zaloName };
|
|
2054
|
+
});
|
|
1352
2055
|
return ok({
|
|
1353
2056
|
groupId,
|
|
1354
2057
|
name: group.name,
|
|
@@ -1371,18 +2074,18 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1371
2074
|
title: "List Recent Zalo Conversations",
|
|
1372
2075
|
description:
|
|
1373
2076
|
"List the conversations this account was most recently active in, newest first, from the local cache, to get a `threadId` or to see what is current. Unlike zalo_list_threads it is not limited to messages that arrived since this server started. " +
|
|
1374
|
-
"Each has its
|
|
2077
|
+
"Each has its `threadId`, `threadType`, `name` and last activity, plus `readState`: how far the account owner has read it on Zalo (on any device), meaning the newest message read, how many cached messages from others came after it, and whether it is marked unread (null when unknown). Every cached conversation is returned unless you pass `limit`, which is per type: with `type` 'all' that is up to `limit` DMs and `limit` groups.",
|
|
1375
2078
|
inputSchema: z.object({
|
|
1376
2079
|
type: z
|
|
1377
2080
|
.enum(["group", "dm", "all"])
|
|
1378
2081
|
.default("all")
|
|
1379
2082
|
.describe("Filter by thread type: 'dm', 'group', or 'all'"),
|
|
1380
|
-
limit: z.number().int().min(1).
|
|
2083
|
+
limit: z.number().int().min(1).optional().describe("Max conversations of each type (omit for all)"),
|
|
1381
2084
|
}),
|
|
1382
2085
|
},
|
|
1383
2086
|
async ({ type, limit }) => {
|
|
1384
2087
|
try {
|
|
1385
|
-
const threads = recentConversations(limit, type);
|
|
2088
|
+
const threads = recentConversations(limit, type, { excludeThreadIds: hiddenIds() });
|
|
1386
2089
|
const dmNames = await resolveCurrentUserNames(
|
|
1387
2090
|
api,
|
|
1388
2091
|
threads.filter((t) => t.type !== "group").map((t) => String(t.threadId)),
|
|
@@ -1396,8 +2099,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1396
2099
|
const ts = Number(t.lastUpdate) || null;
|
|
1397
2100
|
return {
|
|
1398
2101
|
threadId: String(t.threadId),
|
|
1399
|
-
|
|
1400
|
-
threadType: isGroup ? THREAD_GROUP : THREAD_USER,
|
|
2102
|
+
threadType: isGroup ? "group" : "dm",
|
|
1401
2103
|
name:
|
|
1402
2104
|
dmNames.get(String(t.threadId))?.name ||
|
|
1403
2105
|
t.name ||
|
|
@@ -1406,6 +2108,8 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1406
2108
|
lastActivity: ts,
|
|
1407
2109
|
lastActivityAt: ts ? new Date(ts).toISOString() : null,
|
|
1408
2110
|
readState: describeReadState(reads.get(String(t.threadId))),
|
|
2111
|
+
// A group this account left or lost, kept by groups.onLeave "keep" (src/core/group-exit.js).
|
|
2112
|
+
...(t.gone && { gone: true, leftAt: t.leftAt, goneReason: t.goneReason }),
|
|
1409
2113
|
};
|
|
1410
2114
|
});
|
|
1411
2115
|
return ok({
|
|
@@ -1450,7 +2154,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1450
2154
|
{
|
|
1451
2155
|
title: "Request Zalo Sync",
|
|
1452
2156
|
description:
|
|
1453
|
-
"OWNER ONLY: call it only when the owner explicitly asks. Start a restore of messages
|
|
2157
|
+
"OWNER ONLY: call it only when the owner explicitly asks. Start a restore of messages, or another sync stage (the reaction backlog, the zCloud index, attachment downloads, group boards), on this server's existing Zalo connection. The `messages` stage makes the owner's phone ask for a confirmation, which the owner must tap; the other stages do not. " +
|
|
1454
2158
|
"It returns a job at once: poll zalo_sync_status every few seconds. Reuse the same `requestId` and arguments when retrying, so a retry does not start a second sync. It updates the local cache, not Zalo itself. `messages` restores every conversation in the window; it is not per conversation, and it downloads no media, boards, cloud index or conversation state.",
|
|
1455
2159
|
inputSchema: z
|
|
1456
2160
|
.object({
|
|
@@ -1463,10 +2167,10 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1463
2167
|
"Unique request key; reuse the same key and arguments after a timeout to avoid duplicate sync.",
|
|
1464
2168
|
),
|
|
1465
2169
|
stage: z
|
|
1466
|
-
.enum(
|
|
2170
|
+
.enum(SYNC_STAGES)
|
|
1467
2171
|
.default("messages")
|
|
1468
2172
|
.describe(
|
|
1469
|
-
"`messages` restores chat history from the owner's phone (the phone asks for a confirmation); `reactions` drains Zalo's backlog of reactions (
|
|
2173
|
+
"`messages` restores chat history from the owner's phone (the phone asks for a confirmation); `reactions` drains Zalo's backlog of reactions; `cloud` walks the zCloud index (zalo_cloud reads it); `media` downloads the attachments a restore recorded; `boards` stores notes, pinned messages, polls and reminders. Only `messages` taps the phone.",
|
|
1470
2174
|
),
|
|
1471
2175
|
days: z
|
|
1472
2176
|
.number()
|
|
@@ -1474,7 +2178,34 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1474
2178
|
.min(1)
|
|
1475
2179
|
.max(36500)
|
|
1476
2180
|
.optional()
|
|
1477
|
-
.describe(
|
|
2181
|
+
.describe(
|
|
2182
|
+
"Messages: restore the last N days (omit both days and from for full phone history). Media: only attachments from the last N days (default: the window the last restore covered).",
|
|
2183
|
+
),
|
|
2184
|
+
threadId: z
|
|
2185
|
+
.string()
|
|
2186
|
+
.min(1)
|
|
2187
|
+
.optional()
|
|
2188
|
+
.describe("Media and boards only: just this conversation (default: all cached ones)."),
|
|
2189
|
+
kinds: z
|
|
2190
|
+
.array(z.enum([...DOWNLOADABLE_KINDS]))
|
|
2191
|
+
.min(1)
|
|
2192
|
+
.optional()
|
|
2193
|
+
.describe("Media only: just these kinds of attachment (default: all)."),
|
|
2194
|
+
limit: z
|
|
2195
|
+
.number()
|
|
2196
|
+
.int()
|
|
2197
|
+
.min(1)
|
|
2198
|
+
.max(10000)
|
|
2199
|
+
.optional()
|
|
2200
|
+
.describe(
|
|
2201
|
+
"Media: download at most this many files (the rest wait for the next run). Boards: visit at most this many threads, most recent first (default: every thread).",
|
|
2202
|
+
),
|
|
2203
|
+
full: z
|
|
2204
|
+
.boolean()
|
|
2205
|
+
.optional()
|
|
2206
|
+
.describe(
|
|
2207
|
+
"Cloud only: walk from the top and drop every indexed item no page lists (corrects a stale index).",
|
|
2208
|
+
),
|
|
1478
2209
|
from: z
|
|
1479
2210
|
.string()
|
|
1480
2211
|
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
@@ -1495,20 +2226,48 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1495
2226
|
.boolean()
|
|
1496
2227
|
.optional()
|
|
1497
2228
|
.describe("Reactions only: apply observed removals; defaults to true."),
|
|
2229
|
+
fullResync: z
|
|
2230
|
+
.boolean()
|
|
2231
|
+
.optional()
|
|
2232
|
+
.describe(
|
|
2233
|
+
"Messages only: ask the phone for every conversation in full, ignoring what earlier runs " +
|
|
2234
|
+
"settled. A long run; use it when the cache looks incomplete, not by default.",
|
|
2235
|
+
),
|
|
2236
|
+
shardSize: z
|
|
2237
|
+
.number()
|
|
2238
|
+
.int()
|
|
2239
|
+
.min(1)
|
|
2240
|
+
.max(30)
|
|
2241
|
+
.optional()
|
|
2242
|
+
.describe(
|
|
2243
|
+
"Messages only: conversations per batch (1 to 30, default 30). Fewer means more, smaller " +
|
|
2244
|
+
"batches: the first comes back sooner and less is lost if the connection drops.",
|
|
2245
|
+
),
|
|
1498
2246
|
})
|
|
1499
2247
|
.strict()
|
|
1500
2248
|
.refine(
|
|
1501
2249
|
(value) => !(value.days !== undefined && value.from !== undefined),
|
|
1502
2250
|
"Choose days or from, not both",
|
|
1503
2251
|
)
|
|
1504
|
-
.refine(
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
2252
|
+
.refine((value) => {
|
|
2253
|
+
// Each option belongs to the stages named in its description; any other stage refuses it.
|
|
2254
|
+
const only = {
|
|
2255
|
+
days: ["messages", "media"],
|
|
2256
|
+
from: ["messages"],
|
|
2257
|
+
waitMs: ["messages", "reactions"],
|
|
2258
|
+
applyRemovals: ["reactions"],
|
|
2259
|
+
fullResync: ["messages"],
|
|
2260
|
+
shardSize: ["messages"],
|
|
2261
|
+
threadId: ["media", "boards"],
|
|
2262
|
+
kinds: ["media"],
|
|
2263
|
+
limit: ["media", "boards"],
|
|
2264
|
+
full: ["cloud"],
|
|
2265
|
+
};
|
|
2266
|
+
const stage = value.stage ?? "messages";
|
|
2267
|
+
return Object.entries(only).every(
|
|
2268
|
+
([k, stages]) => value[k] === undefined || stages.includes(stage),
|
|
2269
|
+
);
|
|
2270
|
+
}, "An option was given for a stage it does not apply to: each option's description names its stages"),
|
|
1512
2271
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
1513
2272
|
},
|
|
1514
2273
|
async (args) => {
|
|
@@ -1554,10 +2313,16 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1554
2313
|
{
|
|
1555
2314
|
title: "Search Zalo Messages",
|
|
1556
2315
|
description:
|
|
1557
|
-
"Search the text of messages in the local cache
|
|
1558
|
-
"Narrow it with `threadId`, `senderId`, `since`
|
|
2316
|
+
"Search the text of messages in the local cache, across all conversations or one. No network call. Accents and case are ignored, as in Zalo's own search ('duoc' finds 'được'; set `accents` to 'exact' to require them). " +
|
|
2317
|
+
"Narrow it with `threadId`, `senderId`, `since` / `until` (epoch ms) or `last` (7d, 2w, 3m, 1y), and `types` (text, photo, video, file, link, sticker...; files and links match on their titles). Results are newest first, every hit unless you pass `limit`; with a `limit`, pass the reply's `nextCursor` back as `cursor` for the next page. " +
|
|
2318
|
+
"Each message carries a `snippet` (70 characters before the match, 30 after, with its position); `context` adds that many messages around each hit. `counts` gives the matches by type, and `coverage` says how far back the cache reaches and which `sync` command extends it.",
|
|
1559
2319
|
inputSchema: z.object({
|
|
1560
|
-
query: z
|
|
2320
|
+
query: z
|
|
2321
|
+
.string()
|
|
2322
|
+
.min(1)
|
|
2323
|
+
.describe(
|
|
2324
|
+
"Text to search for in cached messages (cut to 100 characters; accents and case ignored)",
|
|
2325
|
+
),
|
|
1561
2326
|
threadId: z
|
|
1562
2327
|
.string()
|
|
1563
2328
|
.min(1)
|
|
@@ -1580,21 +2345,64 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1580
2345
|
.positive()
|
|
1581
2346
|
.optional()
|
|
1582
2347
|
.describe("Only messages with timestamp <= this epoch-ms value"),
|
|
2348
|
+
last: z
|
|
2349
|
+
.string()
|
|
2350
|
+
.regex(/^\d{1,4}\s*[hdwmyHDWMY]$/)
|
|
2351
|
+
.optional()
|
|
2352
|
+
.describe("Only the last period: 7d, 2w, 3m, 1y (replaces `since`)"),
|
|
2353
|
+
types: z
|
|
2354
|
+
.array(z.string().min(1))
|
|
2355
|
+
.max(12)
|
|
2356
|
+
.optional()
|
|
2357
|
+
.describe("Only these message types, e.g. ['file','link']; 'media' means photo and video"),
|
|
2358
|
+
accents: z
|
|
2359
|
+
.enum(["fold", "exact"])
|
|
2360
|
+
.default("fold")
|
|
2361
|
+
.describe(
|
|
2362
|
+
"fold (default): accents and case ignored; exact: accents must match, case still does not",
|
|
2363
|
+
),
|
|
1583
2364
|
limit: z
|
|
1584
2365
|
.number()
|
|
1585
2366
|
.int()
|
|
1586
2367
|
.min(1)
|
|
1587
|
-
.
|
|
1588
|
-
.
|
|
1589
|
-
|
|
2368
|
+
.optional()
|
|
2369
|
+
.describe("Max matching messages per page (omit for every hit, in one page)"),
|
|
2370
|
+
cursor: z.string().min(1).optional().describe("The nextCursor of the previous page, unchanged"),
|
|
2371
|
+
context: z
|
|
2372
|
+
.number()
|
|
2373
|
+
.int()
|
|
2374
|
+
.min(0)
|
|
2375
|
+
.max(10)
|
|
2376
|
+
.default(0)
|
|
2377
|
+
.describe("Messages to show before and after each hit (default 0, max 10)"),
|
|
1590
2378
|
}),
|
|
1591
2379
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
1592
2380
|
},
|
|
1593
|
-
async ({ query, threadId, senderId, since, until, limit }) => {
|
|
2381
|
+
async ({ query, threadId, senderId, since, until, last, types, accents, limit, cursor, context }) => {
|
|
1594
2382
|
try {
|
|
1595
|
-
const
|
|
2383
|
+
const page = searchPage({
|
|
2384
|
+
query,
|
|
2385
|
+
accents,
|
|
2386
|
+
threadId,
|
|
2387
|
+
senderId,
|
|
2388
|
+
since: last ? parsePeriod(last) : since,
|
|
2389
|
+
until,
|
|
2390
|
+
types,
|
|
2391
|
+
limit,
|
|
2392
|
+
cursor,
|
|
2393
|
+
context,
|
|
2394
|
+
excludeThreadIds: hiddenIds(),
|
|
2395
|
+
});
|
|
1596
2396
|
const threadNames = getThreadNames();
|
|
1597
|
-
const
|
|
2397
|
+
const lite = (m) => ({
|
|
2398
|
+
msgId: m.msgId,
|
|
2399
|
+
senderId: m.senderId,
|
|
2400
|
+
...senderNameFields(m.senderId, m.senderName),
|
|
2401
|
+
text: m.text,
|
|
2402
|
+
timestamp: m.timestamp,
|
|
2403
|
+
type: m.type,
|
|
2404
|
+
});
|
|
2405
|
+
const messages = page.hits.map(({ row: r, snippet, context: around }) => {
|
|
1598
2406
|
let cliMsgId = null;
|
|
1599
2407
|
try {
|
|
1600
2408
|
cliMsgId = cachedCliMsgId(r);
|
|
@@ -1608,15 +2416,29 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1608
2416
|
threadName:
|
|
1609
2417
|
threadNames.get(String(r.threadId))?.name ?? nameCache?.get(r.threadId)?.name ?? null,
|
|
1610
2418
|
senderId: r.senderId,
|
|
1611
|
-
|
|
2419
|
+
// Alias first (src/core/contact-names.js); `senderZaloName` is the name the message carried.
|
|
2420
|
+
...senderNameFields(r.senderId, r.senderName),
|
|
1612
2421
|
text: r.text,
|
|
2422
|
+
snippet,
|
|
1613
2423
|
timestamp: r.timestamp,
|
|
1614
2424
|
type: r.type,
|
|
1615
2425
|
hasAttachment: Boolean(r.has_attachment),
|
|
1616
|
-
|
|
2426
|
+
mediaCached: Boolean(r.localPath),
|
|
2427
|
+
replyTo: cachedReplyTo(r),
|
|
2428
|
+
...(around && { context: { before: around.before.map(lite), after: around.after.map(lite) } }),
|
|
1617
2429
|
};
|
|
1618
2430
|
});
|
|
1619
|
-
return ok({
|
|
2431
|
+
return ok({
|
|
2432
|
+
query: page.query,
|
|
2433
|
+
accents: page.accents,
|
|
2434
|
+
...(page.truncatedKeyword && { truncatedKeyword: true }),
|
|
2435
|
+
count: messages.length,
|
|
2436
|
+
hasMore: page.hasMore,
|
|
2437
|
+
nextCursor: page.nextCursor,
|
|
2438
|
+
...(page.counts && { counts: page.counts }),
|
|
2439
|
+
coverage: page.coverage,
|
|
2440
|
+
messages,
|
|
2441
|
+
});
|
|
1620
2442
|
} catch (e) {
|
|
1621
2443
|
console.error("[mcp-tools] zalo_search_messages error:", e.message);
|
|
1622
2444
|
return err(e.message);
|
|
@@ -1630,7 +2452,8 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1630
2452
|
{
|
|
1631
2453
|
title: "Lookup Zalo User",
|
|
1632
2454
|
description:
|
|
1633
|
-
"Look up a Zalo user by phone number (`phone`), username (`username`) or user id (`userId`), or read this logged-in account's own profile (`self: true`). Use it to find someone's `userId`, which is also the `threadId` of your 1-1 conversation with them, before sending a message or a contact card."
|
|
2455
|
+
"Look up a Zalo user by phone number (`phone`), username (`username`) or user id (`userId`), or read this logged-in account's own profile (`self: true`). Use it to find someone's `userId`, which is also the `threadId` of your 1-1 conversation with them, before sending a message or a contact card. " +
|
|
2456
|
+
"A found user's reply also has `mutualGroups`: `{count, groups: [{groupId, name}]}`, the groups you share with them as Zalo shows on a profile (friends and strangers alike; groups in hidden chats are left out unless hidden chats are included), or `{error}` when that read failed.",
|
|
1634
2457
|
inputSchema: z
|
|
1635
2458
|
.object({
|
|
1636
2459
|
self: z
|
|
@@ -1670,28 +2493,38 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1670
2493
|
profile: p,
|
|
1671
2494
|
});
|
|
1672
2495
|
}
|
|
2496
|
+
// The groups shared with a found user, as Zalo shows on a profile (src/core/mutual-groups.js).
|
|
2497
|
+
const shared = (id) =>
|
|
2498
|
+
mutualGroupsOrError(api, id, {
|
|
2499
|
+
ownId: ownIdOf(api) || null,
|
|
2500
|
+
hidden: hiddenMode() === "include" ? null : hiddenSet(),
|
|
2501
|
+
});
|
|
1673
2502
|
if (phone) {
|
|
1674
2503
|
const phoneNumber = phone;
|
|
1675
2504
|
const user = await api.findUser(phoneNumber);
|
|
2505
|
+
const found = user?.uid || user?.userId || null;
|
|
1676
2506
|
return ok({
|
|
1677
2507
|
mode: "phone",
|
|
1678
2508
|
query: phoneNumber,
|
|
1679
2509
|
userId: user?.uid || user?.userId || null,
|
|
1680
|
-
|
|
1681
|
-
|
|
2510
|
+
// Alias first, as Zalo shows the person to this account (src/core/contact-names.js).
|
|
2511
|
+
...personNameFields(user?.uid || user?.userId, user),
|
|
1682
2512
|
avatar: user?.avatar || null,
|
|
2513
|
+
mutualGroups: await shared(found),
|
|
1683
2514
|
user: user || null,
|
|
1684
2515
|
});
|
|
1685
2516
|
}
|
|
1686
2517
|
if (username) {
|
|
1687
2518
|
const user = await api.findUserByUsername(username);
|
|
2519
|
+
const found = user?.uid || user?.userId || null;
|
|
1688
2520
|
return ok({
|
|
1689
2521
|
mode: "username",
|
|
1690
2522
|
query: username,
|
|
1691
2523
|
userId: user?.uid || user?.userId || null,
|
|
1692
|
-
|
|
1693
|
-
|
|
2524
|
+
// Alias first, as Zalo shows the person to this account (src/core/contact-names.js).
|
|
2525
|
+
...personNameFields(user?.uid || user?.userId, user),
|
|
1694
2526
|
avatar: user?.avatar || null,
|
|
2527
|
+
mutualGroups: await shared(found),
|
|
1695
2528
|
user: user || null,
|
|
1696
2529
|
});
|
|
1697
2530
|
}
|
|
@@ -1700,9 +2533,11 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1700
2533
|
return ok({
|
|
1701
2534
|
mode: "userId",
|
|
1702
2535
|
userId,
|
|
1703
|
-
|
|
1704
|
-
|
|
2536
|
+
// Alias first, as Zalo shows the person to this account (src/core/contact-names.js).
|
|
2537
|
+
...personNameFields(userId, changed),
|
|
2538
|
+
displayName: personNameFields(userId, changed).displayName ?? (cachedDisplayName(userId) || null),
|
|
1705
2539
|
avatar: changed?.avatar || null,
|
|
2540
|
+
mutualGroups: await shared(userId),
|
|
1706
2541
|
profile: changed || info || null,
|
|
1707
2542
|
});
|
|
1708
2543
|
} catch (e) {
|
|
@@ -1729,12 +2564,11 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1729
2564
|
.min(1)
|
|
1730
2565
|
.describe("Destination thread ID (`me` or your own uid resolves to My Documents)"),
|
|
1731
2566
|
threadType: z
|
|
1732
|
-
.
|
|
1733
|
-
.int()
|
|
1734
|
-
.min(0)
|
|
1735
|
-
.max(1)
|
|
2567
|
+
.enum(["dm", "group"])
|
|
1736
2568
|
.optional()
|
|
1737
|
-
.describe(
|
|
2569
|
+
.describe(
|
|
2570
|
+
'The destination conversation type: "dm" or "group". Inferred from the cache when omitted.',
|
|
2571
|
+
),
|
|
1738
2572
|
}),
|
|
1739
2573
|
},
|
|
1740
2574
|
async ({ msgId, threadId: threadIdIn, threadType: threadTypeIn }) => {
|
|
@@ -1747,9 +2581,9 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1747
2581
|
try {
|
|
1748
2582
|
let row = null;
|
|
1749
2583
|
try {
|
|
1750
|
-
row =
|
|
2584
|
+
row = getMessageForAction(msgId);
|
|
1751
2585
|
} catch (e) {
|
|
1752
|
-
return err(`Local cache unavailable (${e.message}).`);
|
|
2586
|
+
return err(e?.code === "ROW_MAC" ? e.message : `Local cache unavailable (${e.message}).`);
|
|
1753
2587
|
}
|
|
1754
2588
|
if (!row) {
|
|
1755
2589
|
return err(
|
|
@@ -1771,11 +2605,20 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1771
2605
|
`Message ${msgId} is "${row.type}" but its media is not downloaded locally. Call zalo_view_media with msgId="${msgId}" first.`,
|
|
1772
2606
|
);
|
|
1773
2607
|
}
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
);
|
|
2608
|
+
// Sealed on disk: the upload gets a private decrypted copy for the send only (media-deliver.js).
|
|
2609
|
+
const copy = decryptToTempfile(resolve(row.localPath), mediaScope(), {
|
|
2610
|
+
msgId: row.msgId,
|
|
2611
|
+
ttlMs: 0,
|
|
2612
|
+
});
|
|
2613
|
+
try {
|
|
2614
|
+
return await api.sendMessage(
|
|
2615
|
+
{ msg: "", attachments: [copy.path] },
|
|
2616
|
+
threadId,
|
|
2617
|
+
Number(threadType),
|
|
2618
|
+
);
|
|
2619
|
+
} finally {
|
|
2620
|
+
removeMediaTemp(copy);
|
|
2621
|
+
}
|
|
1779
2622
|
};
|
|
1780
2623
|
|
|
1781
2624
|
const forwarders = {
|
|
@@ -1788,26 +2631,14 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1788
2631
|
Number(threadType),
|
|
1789
2632
|
),
|
|
1790
2633
|
link: async () => api.sendLink({ link: c?.href }, threadId, Number(threadType)),
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
} catch {
|
|
1796
|
-
/* default geometry */
|
|
1797
|
-
}
|
|
1798
|
-
return api.sendVideo(
|
|
1799
|
-
{
|
|
1800
|
-
videoUrl: c?.href,
|
|
1801
|
-
thumbnailUrl: c?.thumb || "",
|
|
1802
|
-
duration: Number(p.duration) || 0,
|
|
1803
|
-
width: Number(p.video_width || p.video_original_width) || 1280,
|
|
1804
|
-
height: Number(p.video_height || p.video_original_height) || 720,
|
|
1805
|
-
},
|
|
2634
|
+
// As `msg forward`: a size the cache knows spares the HEAD, and one still needed is bounded.
|
|
2635
|
+
video: async () =>
|
|
2636
|
+
api.sendVideo(
|
|
2637
|
+
videoResendOptions(c, mediaPlainSize(row.localPath)),
|
|
1806
2638
|
threadId,
|
|
1807
2639
|
Number(threadType),
|
|
1808
|
-
)
|
|
1809
|
-
|
|
1810
|
-
voice: async () => api.sendVoice({ voiceUrl: c?.href }, threadId, Number(threadType)),
|
|
2640
|
+
),
|
|
2641
|
+
voice: async () => api.sendVoice(voiceResendOptions(c), threadId, Number(threadType)),
|
|
1811
2642
|
photo: resendLocal,
|
|
1812
2643
|
file: resendLocal,
|
|
1813
2644
|
gif: resendLocal,
|
|
@@ -1825,7 +2656,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1825
2656
|
success: true,
|
|
1826
2657
|
kind,
|
|
1827
2658
|
threadId,
|
|
1828
|
-
threadType,
|
|
2659
|
+
threadType: threadTypeName(threadType),
|
|
1829
2660
|
...(thread.notice && { notice: thread.notice }),
|
|
1830
2661
|
result: res,
|
|
1831
2662
|
});
|
|
@@ -1861,7 +2692,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1861
2692
|
success: true,
|
|
1862
2693
|
kind: "text",
|
|
1863
2694
|
threadId,
|
|
1864
|
-
threadType,
|
|
2695
|
+
threadType: threadTypeName(threadType),
|
|
1865
2696
|
...(thread.notice && { notice: thread.notice }),
|
|
1866
2697
|
sent,
|
|
1867
2698
|
});
|
|
@@ -1878,7 +2709,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1878
2709
|
{
|
|
1879
2710
|
title: "Delete Zalo Message",
|
|
1880
2711
|
description:
|
|
1881
|
-
"Delete a message from your own view only (`everyone: false`, the default), or, as a group admin, delete someone else's message for everyone in the group (`everyone: true`). To recall your own message for both sides, use zalo_undo. `cliMsgId` and `uidFrom` are read from the local cache when you leave them out.",
|
|
2712
|
+
"Delete a message from your own view only (`everyone: false`, the default), or, as a group admin, delete someone else's message for everyone in the group (`everyone: true`). To recall your own message for both sides, use zalo_undo. `cliMsgId` and `uidFrom` are read from the local cache when you leave them out. A delete cannot be undone, so it is asked about first (`confirm`, `dryRun`).",
|
|
1882
2713
|
inputSchema: z.object({
|
|
1883
2714
|
msgId: z
|
|
1884
2715
|
.string()
|
|
@@ -1889,12 +2720,9 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1889
2720
|
.min(1)
|
|
1890
2721
|
.describe("The conversation the message is in: the user id for a DM, the group id for a group."),
|
|
1891
2722
|
threadType: z
|
|
1892
|
-
.
|
|
1893
|
-
.int()
|
|
1894
|
-
.min(0)
|
|
1895
|
-
.max(1)
|
|
2723
|
+
.enum(["dm", "group"])
|
|
1896
2724
|
.optional()
|
|
1897
|
-
.describe(
|
|
2725
|
+
.describe('The conversation type: "dm" or "group". Inferred from the cache when omitted.'),
|
|
1898
2726
|
cliMsgId: z
|
|
1899
2727
|
.string()
|
|
1900
2728
|
.min(1)
|
|
@@ -1911,16 +2739,25 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1911
2739
|
.boolean()
|
|
1912
2740
|
.default(false)
|
|
1913
2741
|
.describe("Set true to delete someone else's message for everyone in a group (admin/owner)"),
|
|
2742
|
+
confirm: confirmInput("the delete"),
|
|
2743
|
+
ticket: ticketInput(),
|
|
2744
|
+
dryRun: dryRunInput("the delete"),
|
|
1914
2745
|
}),
|
|
1915
2746
|
},
|
|
1916
|
-
async (
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
2747
|
+
async (
|
|
2748
|
+
{
|
|
2749
|
+
msgId,
|
|
2750
|
+
threadId: threadIdIn,
|
|
2751
|
+
threadType: threadTypeIn,
|
|
2752
|
+
cliMsgId: cliMsgIdIn,
|
|
2753
|
+
senderId: senderIdIn,
|
|
2754
|
+
everyone,
|
|
2755
|
+
confirm,
|
|
2756
|
+
dryRun,
|
|
2757
|
+
ticket,
|
|
2758
|
+
},
|
|
2759
|
+
extra,
|
|
2760
|
+
) => {
|
|
1924
2761
|
const thread = actionThread(api, threadIdIn, threadTypeIn);
|
|
1925
2762
|
if (thread.error) {
|
|
1926
2763
|
console.error("[mcp-tools] zalo_delete_message refused:", thread.error);
|
|
@@ -1947,13 +2784,20 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1947
2784
|
type: Number(threadType),
|
|
1948
2785
|
};
|
|
1949
2786
|
const onlyMe = Boolean(everyone) === false;
|
|
2787
|
+
const held = await gate(
|
|
2788
|
+
"msg.delete",
|
|
2789
|
+
{ msgId, threadId, cliMsgId: String(cliMsgId), senderId: String(uidFrom), everyone: !onlyMe },
|
|
2790
|
+
{ confirm, dryRun, ticket },
|
|
2791
|
+
extra,
|
|
2792
|
+
);
|
|
2793
|
+
if (held) return held;
|
|
1950
2794
|
const result = await api.deleteMessage(dest, onlyMe);
|
|
1951
2795
|
return ok({
|
|
1952
2796
|
success: true,
|
|
1953
2797
|
msgId,
|
|
1954
2798
|
cliMsgId: String(cliMsgId),
|
|
1955
2799
|
threadId,
|
|
1956
|
-
threadType,
|
|
2800
|
+
threadType: threadTypeName(threadType),
|
|
1957
2801
|
everyone: Boolean(everyone),
|
|
1958
2802
|
...(thread.notice && { notice: thread.notice }),
|
|
1959
2803
|
result,
|
|
@@ -1974,19 +2818,16 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
1974
2818
|
"Create, list, inspect, view responses, edit, or remove reminders in a Zalo DM or group thread. " +
|
|
1975
2819
|
"Actions: 'create' (requires threadId, title), 'list' (requires threadId), 'info' (requires reminderId, group only), " +
|
|
1976
2820
|
"'responses' (requires reminderId, group only), 'edit' (requires reminderId, threadId, title), " +
|
|
1977
|
-
"'remove' (requires reminderId, threadId).",
|
|
2821
|
+
"'remove' (requires reminderId, threadId; it cannot be undone, so it is asked about first: `confirm`, `dryRun`).",
|
|
1978
2822
|
inputSchema: z.object({
|
|
1979
2823
|
action: z
|
|
1980
2824
|
.enum(["create", "list", "info", "responses", "edit", "remove"])
|
|
1981
2825
|
.describe("Reminder operation to perform"),
|
|
1982
2826
|
threadId: z.string().min(1).optional().describe("Thread ID (required for create, list, edit, remove)"),
|
|
1983
2827
|
threadType: z
|
|
1984
|
-
.
|
|
1985
|
-
.int()
|
|
1986
|
-
.min(0)
|
|
1987
|
-
.max(1)
|
|
2828
|
+
.enum(["dm", "group"])
|
|
1988
2829
|
.optional()
|
|
1989
|
-
.describe(
|
|
2830
|
+
.describe('The conversation type: "dm" or "group". Inferred from the cache when omitted.'),
|
|
1990
2831
|
reminderId: z
|
|
1991
2832
|
.string()
|
|
1992
2833
|
.min(1)
|
|
@@ -2004,28 +2845,44 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2004
2845
|
.enum(["none", "daily", "weekly", "monthly"])
|
|
2005
2846
|
.optional()
|
|
2006
2847
|
.describe("Repeat schedule: 'none', 'daily', 'weekly', or 'monthly'"),
|
|
2007
|
-
page: z
|
|
2848
|
+
page: z
|
|
2849
|
+
.number()
|
|
2850
|
+
.int()
|
|
2851
|
+
.min(1)
|
|
2852
|
+
.optional()
|
|
2853
|
+
.describe("Only this page for 'list' (omit both page and count for every reminder)"),
|
|
2008
2854
|
count: z
|
|
2009
2855
|
.number()
|
|
2010
2856
|
.int()
|
|
2011
2857
|
.min(1)
|
|
2012
2858
|
.max(100)
|
|
2013
|
-
.
|
|
2014
|
-
.describe(
|
|
2859
|
+
.optional()
|
|
2860
|
+
.describe(
|
|
2861
|
+
"Reminders per page for 'list' (one page is read when page or count is given; 20 a page)",
|
|
2862
|
+
),
|
|
2863
|
+
confirm: confirmInput("'remove'"),
|
|
2864
|
+
ticket: ticketInput(),
|
|
2865
|
+
dryRun: dryRunInput("'remove'"),
|
|
2015
2866
|
}),
|
|
2016
2867
|
},
|
|
2017
|
-
async (
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2868
|
+
async (
|
|
2869
|
+
{
|
|
2870
|
+
action,
|
|
2871
|
+
threadId: threadIdIn,
|
|
2872
|
+
threadType: threadTypeIn,
|
|
2873
|
+
reminderId,
|
|
2874
|
+
title,
|
|
2875
|
+
time,
|
|
2876
|
+
emoji,
|
|
2877
|
+
repeat,
|
|
2878
|
+
page,
|
|
2879
|
+
count,
|
|
2880
|
+
confirm,
|
|
2881
|
+
dryRun,
|
|
2882
|
+
ticket,
|
|
2883
|
+
},
|
|
2884
|
+
extra,
|
|
2885
|
+
) => {
|
|
2029
2886
|
try {
|
|
2030
2887
|
if (action === "info") {
|
|
2031
2888
|
if (!reminderId) return err("reminderId is required for action='info'.");
|
|
@@ -2060,7 +2917,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2060
2917
|
action,
|
|
2061
2918
|
success: true,
|
|
2062
2919
|
threadId,
|
|
2063
|
-
threadType,
|
|
2920
|
+
threadType: threadTypeName(threadType),
|
|
2064
2921
|
reminderId: result?.reminderId ?? result?.id ?? null,
|
|
2065
2922
|
startTime,
|
|
2066
2923
|
repeat: REMINDER_REPEAT_LABELS[repeatMode],
|
|
@@ -2070,13 +2927,37 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2070
2927
|
|
|
2071
2928
|
if (action === "list") {
|
|
2072
2929
|
let result = null;
|
|
2930
|
+
let note = null;
|
|
2073
2931
|
try {
|
|
2074
|
-
|
|
2932
|
+
if (page === undefined && count === undefined) {
|
|
2933
|
+
// No page asked: every page, one request at a time (src/core/list-all.js).
|
|
2934
|
+
const all = await allReminders(api, threadId, Number(threadType));
|
|
2935
|
+
result = all.reminders;
|
|
2936
|
+
note = all.paging.note;
|
|
2937
|
+
} else {
|
|
2938
|
+
// A group's page 2 and later carry the cursor of the page before, as Zalo pages them;
|
|
2939
|
+
// a DM's have none (Zalo always sends 0 there) and go by page number.
|
|
2940
|
+
result =
|
|
2941
|
+
Number(threadType) === THREAD_GROUP
|
|
2942
|
+
? await groupReminderPage(api, threadId, page ?? 1, count ?? 20)
|
|
2943
|
+
: await api.getListReminder(
|
|
2944
|
+
{ page: page ?? 1, count: count ?? 20 },
|
|
2945
|
+
threadId,
|
|
2946
|
+
Number(threadType),
|
|
2947
|
+
);
|
|
2948
|
+
}
|
|
2075
2949
|
} catch {
|
|
2076
2950
|
result = null;
|
|
2077
2951
|
}
|
|
2078
2952
|
const reminders = Array.isArray(result) ? result : [];
|
|
2079
|
-
return ok({
|
|
2953
|
+
return ok({
|
|
2954
|
+
action,
|
|
2955
|
+
threadId,
|
|
2956
|
+
threadType: threadTypeName(threadType),
|
|
2957
|
+
count: reminders.length,
|
|
2958
|
+
reminders,
|
|
2959
|
+
...(note && { note }),
|
|
2960
|
+
});
|
|
2080
2961
|
}
|
|
2081
2962
|
|
|
2082
2963
|
if (action === "edit") {
|
|
@@ -2097,13 +2978,34 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2097
2978
|
editOpts.repeat = REMINDER_REPEAT_MODES[repeat];
|
|
2098
2979
|
}
|
|
2099
2980
|
const result = await api.editReminder(editOpts, threadId, Number(threadType));
|
|
2100
|
-
return ok({
|
|
2981
|
+
return ok({
|
|
2982
|
+
action,
|
|
2983
|
+
success: true,
|
|
2984
|
+
reminderId,
|
|
2985
|
+
threadId,
|
|
2986
|
+
threadType: threadTypeName(threadType),
|
|
2987
|
+
result,
|
|
2988
|
+
});
|
|
2101
2989
|
}
|
|
2102
2990
|
|
|
2103
2991
|
if (action === "remove") {
|
|
2104
2992
|
if (!reminderId) return err("reminderId is required for action='remove'.");
|
|
2993
|
+
const held = await gate(
|
|
2994
|
+
"reminder.remove",
|
|
2995
|
+
{ reminderId, threadId },
|
|
2996
|
+
{ confirm, dryRun, ticket },
|
|
2997
|
+
extra,
|
|
2998
|
+
);
|
|
2999
|
+
if (held) return held;
|
|
2105
3000
|
const result = await api.removeReminder(reminderId, threadId, Number(threadType));
|
|
2106
|
-
return ok({
|
|
3001
|
+
return ok({
|
|
3002
|
+
action,
|
|
3003
|
+
success: true,
|
|
3004
|
+
reminderId,
|
|
3005
|
+
threadId,
|
|
3006
|
+
threadType: threadTypeName(threadType),
|
|
3007
|
+
result,
|
|
3008
|
+
});
|
|
2107
3009
|
}
|
|
2108
3010
|
|
|
2109
3011
|
return err(`Unsupported reminder action: ${action}`);
|
|
@@ -2123,7 +3025,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2123
3025
|
"Create or edit group notes, list group board items (notes, pinned messages, polls), or pin/unpin " +
|
|
2124
3026
|
"a cached text message at the top of a conversation. " +
|
|
2125
3027
|
"Actions: 'create' (requires groupId, title), 'edit' (requires groupId, noteId, title), " +
|
|
2126
|
-
"'list' (requires groupId), 'pin_message' (requires msgId; threadId optional if cached), " +
|
|
3028
|
+
"'list' (requires groupId; every board item unless page or count is given), 'pin_message' (requires msgId; threadId optional if cached), " +
|
|
2127
3029
|
"'unpin_message' (requires msgId; threadId optional if cached).",
|
|
2128
3030
|
inputSchema: z.object({
|
|
2129
3031
|
action: z
|
|
@@ -2142,13 +3044,10 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2142
3044
|
"Thread ID for 'pin_message' / 'unpin_message' (defaults to the message's cached threadId)",
|
|
2143
3045
|
),
|
|
2144
3046
|
threadType: z
|
|
2145
|
-
.
|
|
2146
|
-
.int()
|
|
2147
|
-
.min(0)
|
|
2148
|
-
.max(1)
|
|
3047
|
+
.enum(["dm", "group"])
|
|
2149
3048
|
.optional()
|
|
2150
3049
|
.describe(
|
|
2151
|
-
"
|
|
3050
|
+
"The conversation type for 'pin_message' / 'unpin_message': \"dm\" or \"group\". Inferred from the cache when omitted.",
|
|
2152
3051
|
),
|
|
2153
3052
|
noteId: z
|
|
2154
3053
|
.string()
|
|
@@ -2167,8 +3066,19 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2167
3066
|
.describe(
|
|
2168
3067
|
"msgId of a cached text message to pin or unpin (required for 'pin_message' and 'unpin_message').",
|
|
2169
3068
|
),
|
|
2170
|
-
page: z
|
|
2171
|
-
|
|
3069
|
+
page: z
|
|
3070
|
+
.number()
|
|
3071
|
+
.int()
|
|
3072
|
+
.min(1)
|
|
3073
|
+
.optional()
|
|
3074
|
+
.describe("Only this page for 'list' (omit both page and count for every board item)"),
|
|
3075
|
+
count: z
|
|
3076
|
+
.number()
|
|
3077
|
+
.int()
|
|
3078
|
+
.min(1)
|
|
3079
|
+
.max(100)
|
|
3080
|
+
.optional()
|
|
3081
|
+
.describe("Items per page for 'list' (one page is read when page or count is given; 20 a page)"),
|
|
2172
3082
|
}),
|
|
2173
3083
|
},
|
|
2174
3084
|
async ({
|
|
@@ -2204,7 +3114,19 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2204
3114
|
|
|
2205
3115
|
if (action === "list") {
|
|
2206
3116
|
if (!groupId) return err("groupId is required for action='list'.");
|
|
2207
|
-
|
|
3117
|
+
if (page === undefined && count === undefined) {
|
|
3118
|
+
// No page asked: every page, one request at a time (src/core/list-all.js).
|
|
3119
|
+
const all = await allBoardItems(api, groupId);
|
|
3120
|
+
return ok({
|
|
3121
|
+
action,
|
|
3122
|
+
groupId,
|
|
3123
|
+
items: all.items,
|
|
3124
|
+
count: all.items.length,
|
|
3125
|
+
...(all.paging.note && { note: all.paging.note }),
|
|
3126
|
+
});
|
|
3127
|
+
}
|
|
3128
|
+
// Page 2 and later carry the cursor of the page before, as Zalo pages the board.
|
|
3129
|
+
const result = await boardPage(api, groupId, page ?? 1, count ?? 20);
|
|
2208
3130
|
return ok({
|
|
2209
3131
|
action,
|
|
2210
3132
|
groupId,
|
|
@@ -2217,8 +3139,9 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2217
3139
|
if (!msgId) return err("msgId is required for action='pin_message'.");
|
|
2218
3140
|
let row = null;
|
|
2219
3141
|
try {
|
|
2220
|
-
row =
|
|
2221
|
-
} catch {
|
|
3142
|
+
row = getMessageForAction(msgId);
|
|
3143
|
+
} catch (e) {
|
|
3144
|
+
if (e?.code === "ROW_MAC") return err(e.message);
|
|
2222
3145
|
row = null;
|
|
2223
3146
|
}
|
|
2224
3147
|
if (!row) {
|
|
@@ -2259,8 +3182,9 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2259
3182
|
if (!msgId) return err("msgId is required for action='unpin_message'.");
|
|
2260
3183
|
let row = null;
|
|
2261
3184
|
try {
|
|
2262
|
-
row =
|
|
2263
|
-
} catch {
|
|
3185
|
+
row = getMessageForAction(msgId);
|
|
3186
|
+
} catch (e) {
|
|
3187
|
+
if (e?.code === "ROW_MAC") return err(e.message);
|
|
2264
3188
|
row = null;
|
|
2265
3189
|
}
|
|
2266
3190
|
const targetThread = threadIdIn || groupId;
|
|
@@ -2299,7 +3223,8 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2299
3223
|
"Create, inspect, vote, unvote, add options, lock, or share a poll in a Zalo group. " +
|
|
2300
3224
|
"Actions: 'create' (requires groupId, question, options with >=2 items), 'info' (requires pollId), " +
|
|
2301
3225
|
"'vote' (requires pollId, optionIds), 'unvote' (requires pollId), " +
|
|
2302
|
-
"'add_options' (requires pollId, options), 'lock' (requires pollId
|
|
3226
|
+
"'add_options' (requires pollId, options), 'lock' (requires pollId; closing a poll cannot be undone, so it is " +
|
|
3227
|
+
"asked about first: `confirm`, `dryRun`), 'share' (requires pollId).",
|
|
2303
3228
|
inputSchema: z.object({
|
|
2304
3229
|
action: z
|
|
2305
3230
|
.enum(["create", "info", "vote", "unvote", "add_options", "lock", "share"])
|
|
@@ -2341,22 +3266,31 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2341
3266
|
.boolean()
|
|
2342
3267
|
.default(false)
|
|
2343
3268
|
.describe("Also cast your vote for the newly added options ('add_options' only)"),
|
|
3269
|
+
confirm: confirmInput("'lock'"),
|
|
3270
|
+
ticket: ticketInput(),
|
|
3271
|
+
dryRun: dryRunInput("'lock'"),
|
|
2344
3272
|
}),
|
|
2345
3273
|
},
|
|
2346
|
-
async (
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
3274
|
+
async (
|
|
3275
|
+
{
|
|
3276
|
+
action,
|
|
3277
|
+
groupId,
|
|
3278
|
+
pollId,
|
|
3279
|
+
question,
|
|
3280
|
+
options,
|
|
3281
|
+
optionIds,
|
|
3282
|
+
multi,
|
|
3283
|
+
allowAddOptions,
|
|
3284
|
+
anonymous,
|
|
3285
|
+
hidePreview,
|
|
3286
|
+
expireMinutes,
|
|
3287
|
+
voteNewOptions,
|
|
3288
|
+
confirm,
|
|
3289
|
+
dryRun,
|
|
3290
|
+
ticket,
|
|
3291
|
+
},
|
|
3292
|
+
extra,
|
|
3293
|
+
) => {
|
|
2360
3294
|
try {
|
|
2361
3295
|
if (action === "create") {
|
|
2362
3296
|
if (!groupId) return err("groupId is required for action='create'.");
|
|
@@ -2424,6 +3358,8 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2424
3358
|
}
|
|
2425
3359
|
|
|
2426
3360
|
if (action === "lock") {
|
|
3361
|
+
const held = await gate("poll.lock", { pollId: numericPollId }, { confirm, dryRun, ticket }, extra);
|
|
3362
|
+
if (held) return held;
|
|
2427
3363
|
const result = await api.lockPoll(numericPollId);
|
|
2428
3364
|
return ok({ action, success: true, pollId: numericPollId, result });
|
|
2429
3365
|
}
|
|
@@ -2448,7 +3384,9 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2448
3384
|
title: "Wait for Incoming Zalo Message",
|
|
2449
3385
|
description:
|
|
2450
3386
|
'Wait for the next incoming message, without polling. It returns at once when a buffered message newer than `since` is already waiting; otherwise it waits up to `timeoutSec` seconds (default 55, max 300) and then returns `status: "timeout"` with no message. Call it in a loop to listen, and call zalo_mark_read with the `cursor` when a message is handled. ' +
|
|
2451
|
-
"
|
|
3387
|
+
"It returns every message already waiting, in order, in `messages` (`message` is the first, `cursor` is the last, so `since: cursor` continues where the batch ended); `limit` caps how many (then `hasMore` says more are already waiting); `settleMs` waits that long after the first message for the rest of a burst. A message's `id` is its msgId. " +
|
|
3388
|
+
SYSTEM_EVENTS_NOTE +
|
|
3389
|
+
"Mirrors GET /events/wait for remote HTTPS/OAuth2 MCP clients.",
|
|
2452
3390
|
inputSchema: z.object({
|
|
2453
3391
|
threadId: z
|
|
2454
3392
|
.string()
|
|
@@ -2475,9 +3413,8 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2475
3413
|
.number()
|
|
2476
3414
|
.int()
|
|
2477
3415
|
.min(1)
|
|
2478
|
-
.
|
|
2479
|
-
.
|
|
2480
|
-
.describe(`Most messages to return in one call (default 1, max ${MAX_BATCH})`),
|
|
3416
|
+
.optional()
|
|
3417
|
+
.describe("Most messages to return in one call (omit for every message already waiting)"),
|
|
2481
3418
|
settleMs: z
|
|
2482
3419
|
.number()
|
|
2483
3420
|
.int()
|
|
@@ -2489,7 +3426,7 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2489
3426
|
),
|
|
2490
3427
|
}),
|
|
2491
3428
|
},
|
|
2492
|
-
async ({ threadId, since, timeoutSec = 55, limit
|
|
3429
|
+
async ({ threadId, since, timeoutSec = 55, limit, settleMs = 0 }) => {
|
|
2493
3430
|
try {
|
|
2494
3431
|
if (typeof buffer?.waitForMessages !== "function") {
|
|
2495
3432
|
return err("Live message buffer does not support waitForMessages in this context.");
|
|
@@ -2497,22 +3434,27 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2497
3434
|
const cleanThreadId = typeof threadId === "string" && threadId.trim() ? threadId.trim() : null;
|
|
2498
3435
|
const clampedSec = Math.max(1, Math.min(300, Number(timeoutSec) || 55));
|
|
2499
3436
|
const batch = batchParams({ limit, settleMs });
|
|
2500
|
-
|
|
3437
|
+
if (isHiddenThread(cleanThreadId)) return err(HIDDEN_THREAD);
|
|
3438
|
+
const waited = await buffer.waitForMessages({
|
|
2501
3439
|
threadId: cleanThreadId,
|
|
2502
3440
|
since: typeof since === "number" && Number.isFinite(since) ? since : undefined,
|
|
2503
3441
|
timeoutMs: clampedSec * 1000,
|
|
2504
3442
|
...batch,
|
|
2505
3443
|
});
|
|
3444
|
+
const messages = eventsView(waited.messages);
|
|
3445
|
+
const hasMore = waited.hasMore;
|
|
2506
3446
|
return ok(
|
|
2507
3447
|
waitResult({
|
|
2508
3448
|
messages,
|
|
2509
3449
|
hasMore,
|
|
2510
3450
|
cursorWhenEmpty: Math.max(
|
|
3451
|
+
Number(waited.messages.at(-1)?._cursor) || 0,
|
|
2511
3452
|
typeof since === "number" && Number.isFinite(since) ? since : 0,
|
|
2512
3453
|
Number(buffer._globalCursor) || 0,
|
|
2513
3454
|
typeof buffer.readCursor === "function" ? buffer.readCursor() : 0,
|
|
2514
3455
|
),
|
|
2515
3456
|
decorate: (msg) => {
|
|
3457
|
+
if (msg.hidden || msg.system) return msg;
|
|
2516
3458
|
const tid = String(msg.threadId || "");
|
|
2517
3459
|
let threadName = nameCache?.get(tid)?.name || null;
|
|
2518
3460
|
if (!threadName && tid) {
|
|
@@ -2543,7 +3485,9 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2543
3485
|
"Actions: 'list' (returns all labels with their IDs, text, colors, conversations array, and version), " +
|
|
2544
3486
|
"'assign' (adds threadId or threadIds to a label identified by labelId or labelText), " +
|
|
2545
3487
|
"'unassign' (removes threadId or threadIds from a label identified by labelId or labelText), " +
|
|
2546
|
-
"'update' (raw update with full labelData array and version, matching 'label update'
|
|
3488
|
+
"'update' (raw update with full labelData array and version, matching 'label update'; the list " +
|
|
3489
|
+
"replaces the current one, so a label left out of it is deleted: that is asked about first, " +
|
|
3490
|
+
"`confirm`, `dryRun`).",
|
|
2547
3491
|
inputSchema: z.object({
|
|
2548
3492
|
action: z
|
|
2549
3493
|
.enum(["list", "assign", "unassign", "update"])
|
|
@@ -2569,6 +3513,12 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2569
3513
|
.array(z.string().min(1))
|
|
2570
3514
|
.optional()
|
|
2571
3515
|
.describe("Multiple thread IDs to assign or unassign in one call"),
|
|
3516
|
+
threadType: z
|
|
3517
|
+
.enum(["dm", "group"])
|
|
3518
|
+
.optional()
|
|
3519
|
+
.describe(
|
|
3520
|
+
'The type of every threadId/threadIds given: "dm" or "group". Leave it out: the type stored for each thread is used. A label stores a group as "g<groupId>".',
|
|
3521
|
+
),
|
|
2572
3522
|
labelData: z
|
|
2573
3523
|
.array(z.any())
|
|
2574
3524
|
.optional()
|
|
@@ -2578,9 +3528,27 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2578
3528
|
.int()
|
|
2579
3529
|
.optional()
|
|
2580
3530
|
.describe("Label version integer from action='list' (required for raw action='update')"),
|
|
3531
|
+
confirm: confirmInput("an 'update' that removes labels"),
|
|
3532
|
+
ticket: ticketInput(),
|
|
3533
|
+
dryRun: dryRunInput("'update'"),
|
|
2581
3534
|
}),
|
|
2582
3535
|
},
|
|
2583
|
-
async (
|
|
3536
|
+
async (
|
|
3537
|
+
{
|
|
3538
|
+
action,
|
|
3539
|
+
labelId,
|
|
3540
|
+
labelText,
|
|
3541
|
+
threadId,
|
|
3542
|
+
threadIds,
|
|
3543
|
+
threadType: threadTypeIn,
|
|
3544
|
+
labelData,
|
|
3545
|
+
version,
|
|
3546
|
+
confirm,
|
|
3547
|
+
dryRun,
|
|
3548
|
+
ticket,
|
|
3549
|
+
},
|
|
3550
|
+
extra,
|
|
3551
|
+
) => {
|
|
2584
3552
|
try {
|
|
2585
3553
|
if (action === "list") {
|
|
2586
3554
|
const res = await api.getLabels();
|
|
@@ -2596,6 +3564,16 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2596
3564
|
if (!Array.isArray(labelData) || typeof version !== "number" || !Number.isFinite(version)) {
|
|
2597
3565
|
return err("labelData (array) and version (number) are required for action='update'.");
|
|
2598
3566
|
}
|
|
3567
|
+
// Only a label dropped from the list is asked about; knowing which takes the current list.
|
|
3568
|
+
const removed = removedLabels((await api.getLabels())?.labelData, labelData);
|
|
3569
|
+
const held = await gate(
|
|
3570
|
+
"label.update",
|
|
3571
|
+
{ removedLabels: removed, version: Number(version) },
|
|
3572
|
+
{ confirm, dryRun, ticket },
|
|
3573
|
+
extra,
|
|
3574
|
+
{ applies: removed.length > 0 },
|
|
3575
|
+
);
|
|
3576
|
+
if (held) return held;
|
|
2599
3577
|
const updated = await api.updateLabels({
|
|
2600
3578
|
labelData,
|
|
2601
3579
|
version: Number(version),
|
|
@@ -2647,15 +3625,24 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2647
3625
|
);
|
|
2648
3626
|
}
|
|
2649
3627
|
|
|
2650
|
-
|
|
3628
|
+
// A label names a group as "g<groupId>" and a user by the bare id (spec-actions 9): a bare
|
|
3629
|
+
// group id would be stored as a user conversation. Unassign drops both forms, so it also
|
|
3630
|
+
// clears a bare group id an earlier version stored (a user id is never a group's).
|
|
3631
|
+
const convIds = targets.map((t) => labelConversationId(t, threadTypeIn));
|
|
3632
|
+
const dropped = new Set(
|
|
3633
|
+
convIds.flatMap((c) => {
|
|
3634
|
+
const bare = LABEL_GROUP_ID.test(c) ? c.slice(1) : c;
|
|
3635
|
+
return [bare, `g${bare}`];
|
|
3636
|
+
}),
|
|
3637
|
+
);
|
|
2651
3638
|
let updatedConvList = [];
|
|
2652
3639
|
const nextLabelData = list.map((lbl) => {
|
|
2653
3640
|
if (Number(lbl.id) !== Number(matched.id)) return lbl;
|
|
2654
3641
|
const existing = Array.isArray(lbl.conversations) ? lbl.conversations.map(String) : [];
|
|
2655
3642
|
const nextConvs =
|
|
2656
3643
|
action === "assign"
|
|
2657
|
-
? [...new Set([...existing, ...
|
|
2658
|
-
: existing.filter((c) => !
|
|
3644
|
+
? [...new Set([...existing, ...convIds])]
|
|
3645
|
+
: existing.filter((c) => !dropped.has(String(c)));
|
|
2659
3646
|
updatedConvList = nextConvs;
|
|
2660
3647
|
return { ...lbl, conversations: nextConvs };
|
|
2661
3648
|
});
|
|
@@ -2690,43 +3677,85 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2690
3677
|
{
|
|
2691
3678
|
title: "Manage Zalo Friends and Friend Requests",
|
|
2692
3679
|
description:
|
|
2693
|
-
"
|
|
3680
|
+
"Friends and friend requests: check, list and answer requests, list, remove and block friends. Actions: " +
|
|
2694
3681
|
"'status' (the relationship with userId: is_friend, and is_requested / is_requesting, Zalo's two flags " +
|
|
2695
3682
|
"for a request pending between you and them; to tell which direction a request goes, use the two lists), " +
|
|
2696
3683
|
"'sent_requests' (requests you sent that are still pending), " +
|
|
2697
3684
|
"'received_requests' (requests others sent you, newest first, with their message), " +
|
|
2698
3685
|
"'send' (friend request to userId, with an optional message), " +
|
|
2699
|
-
"'accept' / 'reject' (the request from userId), " +
|
|
2700
|
-
"'undo' (cancel the request you sent to userId), " +
|
|
2701
|
-
"'list' (your friends, most recently active first
|
|
3686
|
+
"'accept' / 'reject' (the request from userId; 'reject' is asked about first), " +
|
|
3687
|
+
"'undo' (cancel the request you sent to userId; asked about first: `confirm`, `dryRun`), " +
|
|
3688
|
+
"'list' (your friends, most recently active first: all of them unless limit is given), " +
|
|
3689
|
+
"'alias' (set the nickname this account shows for userId to `alias`; an empty alias removes it; " +
|
|
3690
|
+
"the nickname is what `senderDisplayName` and `@[userId]` mentions then use), " +
|
|
3691
|
+
"'alias_list' (the nicknames set on this account: all of them unless limit is given), " +
|
|
3692
|
+
"'online' (friends online now: dead in practice, Zalo answers 404 and Zalo's own apps discard it too), " +
|
|
3693
|
+
"'close' (close friends), 'last_online' (when userId was last seen, with hiddenBy \"you\" or \"them\" " +
|
|
3694
|
+
"when hidden; nothing is asked when this account hides its own status, unless `askAnyway`; " +
|
|
3695
|
+
"`cached` reads the listener's presence cache instead), " +
|
|
3696
|
+
"'remove' (unfriend userId), 'block' / 'unblock' (userId), 'block_feed' (hide userId's posts from the " +
|
|
3697
|
+
"feed; `unblock: true` shows them again), 'find_phones' (users by `phones`), 'qr' (the QR code URL of " +
|
|
3698
|
+
"each of userIds), 'common_groups' (the groups you share with each of userIds), 'biz' (userId's " +
|
|
3699
|
+
"business account details). 'reject', 'undo', 'remove' and 'block' are asked about first: " +
|
|
3700
|
+
"`confirm`, `dryRun`. " +
|
|
2702
3701
|
"userId is the numeric Zalo id (zalo_lookup_user finds one from a phone number). " +
|
|
2703
3702
|
"Zalo restricts accounts that send many friend requests, so send sparingly.",
|
|
2704
|
-
inputSchema: z
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
3703
|
+
inputSchema: z
|
|
3704
|
+
.object({
|
|
3705
|
+
action: z
|
|
3706
|
+
.enum([
|
|
3707
|
+
"status",
|
|
3708
|
+
"sent_requests",
|
|
3709
|
+
"received_requests",
|
|
3710
|
+
"send",
|
|
3711
|
+
"accept",
|
|
3712
|
+
"reject",
|
|
3713
|
+
"undo",
|
|
3714
|
+
"list",
|
|
3715
|
+
"alias",
|
|
3716
|
+
"alias_list",
|
|
3717
|
+
...Object.keys(FRIEND_EXTRA_ACTIONS),
|
|
3718
|
+
])
|
|
3719
|
+
.describe("Friend operation to perform"),
|
|
3720
|
+
userId: z
|
|
3721
|
+
.string()
|
|
3722
|
+
.min(1)
|
|
3723
|
+
.optional()
|
|
3724
|
+
.describe(
|
|
3725
|
+
"Numeric Zalo user id (required for status, send, accept, reject, undo, alias, remove, block, " +
|
|
3726
|
+
"unblock, last_online, biz and block_feed)",
|
|
3727
|
+
),
|
|
3728
|
+
message: z
|
|
3729
|
+
.string()
|
|
3730
|
+
.optional()
|
|
3731
|
+
.describe("Message sent with the friend request (only for 'send'; default: none)"),
|
|
3732
|
+
alias: z
|
|
3733
|
+
.string()
|
|
3734
|
+
.max(200)
|
|
3735
|
+
.optional()
|
|
3736
|
+
.describe(
|
|
3737
|
+
"Only for 'alias': the nickname to show for userId; an empty string removes the nickname",
|
|
3738
|
+
),
|
|
3739
|
+
limit: z
|
|
3740
|
+
.number()
|
|
3741
|
+
.int()
|
|
3742
|
+
.min(1)
|
|
3743
|
+
.optional()
|
|
3744
|
+
.describe(
|
|
3745
|
+
"Most entries to return for 'list' and 'alias_list' (omit for all); 'list' says how many there are in all",
|
|
3746
|
+
),
|
|
3747
|
+
...FRIEND_EXTRA_INPUTS,
|
|
3748
|
+
confirm: confirmInput("'reject', 'undo', 'remove' and 'block'"),
|
|
3749
|
+
ticket: ticketInput(),
|
|
3750
|
+
dryRun: dryRunInput("'reject', 'undo', 'remove' and 'block'"),
|
|
3751
|
+
})
|
|
3752
|
+
.strict(),
|
|
2727
3753
|
},
|
|
2728
|
-
async (
|
|
2729
|
-
|
|
3754
|
+
async (args, extra) => {
|
|
3755
|
+
// The actions added with the action tools run through the shared runner (src/mcp/action-tool.js).
|
|
3756
|
+
if (Object.hasOwn(FRIEND_EXTRA_ACTIONS, args.action)) return friendExtra(args, extra);
|
|
3757
|
+
const { action, userId, message, limit, alias, confirm, dryRun, ticket } = args;
|
|
3758
|
+
const needsUser = ["status", "send", "accept", "reject", "undo", "alias"].includes(action);
|
|
2730
3759
|
const target = userId === undefined ? "" : String(userId).trim();
|
|
2731
3760
|
if (needsUser) {
|
|
2732
3761
|
if (!target) return err(`userId is required for action='${action}'.`);
|
|
@@ -2736,19 +3765,18 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2736
3765
|
);
|
|
2737
3766
|
}
|
|
2738
3767
|
}
|
|
3768
|
+
if (action === "reject" || action === "undo") {
|
|
3769
|
+
const key = action === "reject" ? "friend.reject" : "friend.undoRequest";
|
|
3770
|
+
const held = await gate(key, { userId: target }, { confirm, dryRun, ticket }, extra);
|
|
3771
|
+
if (held) return held;
|
|
3772
|
+
}
|
|
2739
3773
|
try {
|
|
2740
3774
|
switch (action) {
|
|
2741
3775
|
case "status":
|
|
2742
3776
|
return ok({ action, ...friendStatusFrom(await api.getFriendRequestStatus(target), target) });
|
|
2743
3777
|
case "sent_requests": {
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
res = await api.getSentFriendRequest();
|
|
2747
|
-
} catch (e) {
|
|
2748
|
-
// Zalo answers code 112 when there are none, which is an empty list, not a failure.
|
|
2749
|
-
if (!/\b112\b/.test(String(e?.message))) throw e;
|
|
2750
|
-
}
|
|
2751
|
-
const requests = sentRequestsFrom(res);
|
|
3778
|
+
// Zalo's "none sent" (112) is an empty list, not a failure.
|
|
3779
|
+
const requests = sentRequestsFrom(await readSentRequests(api));
|
|
2752
3780
|
return ok({ action, count: requests.length, requests });
|
|
2753
3781
|
}
|
|
2754
3782
|
case "received_requests": {
|
|
@@ -2768,17 +3796,66 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2768
3796
|
await api.undoFriendRequest(target);
|
|
2769
3797
|
return ok({ action, success: true, userId: target });
|
|
2770
3798
|
case "list": {
|
|
2771
|
-
const { total, friends } = friendsFrom(await api.getAllFriends(), limit
|
|
3799
|
+
const { total, friends } = friendsFrom(await api.getAllFriends(), limit);
|
|
2772
3800
|
return ok({ action, total, count: friends.length, truncated: friends.length < total, friends });
|
|
2773
3801
|
}
|
|
3802
|
+
case "alias": {
|
|
3803
|
+
const nick = alias === undefined ? "" : String(alias).trim();
|
|
3804
|
+
if (nick) {
|
|
3805
|
+
// The same call as the CLI's `friend alias` (the session takes the alias first).
|
|
3806
|
+
await api.changeFriendAlias(nick, target);
|
|
3807
|
+
// `contacts.name` is what senderDisplayName and mentions read (db.getDisplayName);
|
|
3808
|
+
// the nickname is the name Zalo will show from now on, so it is written there at once.
|
|
3809
|
+
rememberContactName(target, nick);
|
|
3810
|
+
noteAliasSet(target, nick);
|
|
3811
|
+
return ok({ action, success: true, userId: target, alias: nick });
|
|
3812
|
+
}
|
|
3813
|
+
await api.removeFriendAlias(target);
|
|
3814
|
+
noteAliasSet(target, null);
|
|
3815
|
+
// Without the nickname the contact is shown by their profile name again; fetch it so the
|
|
3816
|
+
// cached name does not stay the removed nickname. Best effort: the removal already stuck.
|
|
3817
|
+
try {
|
|
3818
|
+
const info = await api.getUserInfo(target);
|
|
3819
|
+
const p = info?.changed_profiles?.[target] || info?.unchanged_profiles?.[target] || null;
|
|
3820
|
+
const shown = p?.displayName || p?.zaloName || null;
|
|
3821
|
+
if (shown) rememberContactName(target, shown);
|
|
3822
|
+
} catch (e) {
|
|
3823
|
+
console.error(`[mcp-tools] zalo_friend alias: profile name not refreshed: ${e.message}`);
|
|
3824
|
+
}
|
|
3825
|
+
return ok({ action, success: true, userId: target, alias: null });
|
|
3826
|
+
}
|
|
3827
|
+
case "alias_list": {
|
|
3828
|
+
// No limit: every page, as Zalo pages its alias list (src/core/list-all.js); a limit is
|
|
3829
|
+
// one page of that size.
|
|
3830
|
+
let items;
|
|
3831
|
+
let note = null;
|
|
3832
|
+
if (limit === undefined) {
|
|
3833
|
+
const all = await allAliases(api);
|
|
3834
|
+
items = all.items;
|
|
3835
|
+
note = all.paging.note;
|
|
3836
|
+
} else {
|
|
3837
|
+
const res = await api.getAliasList(limit, 1);
|
|
3838
|
+
items = Array.isArray(res?.items) ? res.items : [];
|
|
3839
|
+
}
|
|
3840
|
+
const aliases = items
|
|
3841
|
+
.filter((i) => i && i.userId !== undefined && i.userId !== null)
|
|
3842
|
+
.map((i) => ({ userId: String(i.userId), alias: i.alias ?? null }));
|
|
3843
|
+
return ok({ action, count: aliases.length, aliases, ...(note && { note }) });
|
|
3844
|
+
}
|
|
2774
3845
|
default:
|
|
2775
3846
|
return err(`Unsupported friend action: ${action}`);
|
|
2776
3847
|
}
|
|
2777
3848
|
} catch (e) {
|
|
2778
3849
|
console.error("[mcp-tools] zalo_friend error:", e.message);
|
|
2779
|
-
// 'send'
|
|
3850
|
+
// 'send' and 'undo' keep the CLI's wording for Zalo's refusal codes (already friends, blocked,
|
|
3851
|
+
// too many requests taken back, ...), read from the error's code.
|
|
3852
|
+
const code = errorCodeOf(e);
|
|
2780
3853
|
const known =
|
|
2781
|
-
action === "send"
|
|
3854
|
+
action === "send"
|
|
3855
|
+
? describeFriendAddError(code, target)
|
|
3856
|
+
: action === "undo"
|
|
3857
|
+
? describeFriendUndoError(code, target)
|
|
3858
|
+
: null;
|
|
2782
3859
|
return err(known || e.message);
|
|
2783
3860
|
}
|
|
2784
3861
|
},
|
|
@@ -2797,48 +3874,101 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2797
3874
|
"'create' (a new group named `name` with the members in userIds), " +
|
|
2798
3875
|
"'add_members' (add userIds to the group), " +
|
|
2799
3876
|
"'remove_member' (remove the one member userId from the group), " +
|
|
2800
|
-
"'leave' (
|
|
3877
|
+
"'leave' (only this account leaves; `silent` hides the usual notice from ordinary members, the owner " +
|
|
3878
|
+
"still sees it; the owner of a group with other members must give `newOwner` (a member's userId: " +
|
|
3879
|
+
"ownership is handed over first, as Zalo does) or `randomOwner: true` (Zalo picks a member)), " +
|
|
3880
|
+
"'rename' (set the group's name to `name`; every member sees the change), " +
|
|
3881
|
+
"'avatar' (set the group's avatar from a local image, `filePath`), " +
|
|
3882
|
+
"'add_admin' / 'remove_admin' (userIds), 'transfer_owner' (to userId), " +
|
|
3883
|
+
"'block_member' / 'unblock_member' (userIds; a blocked member cannot rejoin), 'blocked' (the blocked " +
|
|
3884
|
+
"members), 'settings' (change `settings`; the rest keep their values), 'upgrade_community', " +
|
|
3885
|
+
"'disperse' (owner only: disband the group, deleting it for every member), 'pending' / 'approve' / " +
|
|
3886
|
+
"'reject_member' (join requests, " +
|
|
3887
|
+
"admins only), 'enable_link' / 'disable_link' / 'link_info' (the invite link), 'link_preview' / " +
|
|
3888
|
+
"'join' (a group by its invite `link`), 'invite_boxes' (invitations you received), 'invite_info' / " +
|
|
3889
|
+
"'join_invite' (one of them, by groupId), 'delete_invite' (groupIds), 'invite_to' (invite userId to " +
|
|
3890
|
+
"groupIds), 'members_info' (profiles of userIds). " +
|
|
2801
3891
|
"groupId is the group's thread id (zalo_search_threads or zalo_list_conversations finds it); " +
|
|
2802
3892
|
"user ids are numeric Zalo ids (zalo_lookup_user finds one from a phone number). " +
|
|
2803
|
-
"'leave'
|
|
2804
|
-
"
|
|
2805
|
-
"
|
|
3893
|
+
"'leave', 'remove_member', 'remove_admin', 'transfer_owner', 'block_member', 'disperse', " +
|
|
3894
|
+
"'disable_link', and 'settings' when it turns join approval off, are asked about first: " +
|
|
3895
|
+
"`confirm` and `dryRun`, as the deployment's confirmMode decides. Zalo can refuse some members " +
|
|
2806
3896
|
"of a create or add_members: the reply lists the members it did and did not take.",
|
|
2807
|
-
inputSchema: z
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
3897
|
+
inputSchema: z
|
|
3898
|
+
.object({
|
|
3899
|
+
action: z
|
|
3900
|
+
.enum([
|
|
3901
|
+
"leave",
|
|
3902
|
+
"info",
|
|
3903
|
+
"create",
|
|
3904
|
+
"add_members",
|
|
3905
|
+
"remove_member",
|
|
3906
|
+
"rename",
|
|
3907
|
+
...Object.keys(GROUP_EXTRA_ACTIONS),
|
|
3908
|
+
])
|
|
3909
|
+
.describe("Group operation to perform"),
|
|
3910
|
+
groupId: z
|
|
3911
|
+
.string()
|
|
3912
|
+
.min(1)
|
|
3913
|
+
.optional()
|
|
3914
|
+
.describe(
|
|
3915
|
+
"The group's id (required for every action except create, link_preview, join, invite_boxes, " +
|
|
3916
|
+
"delete_invite, invite_to and members_info)",
|
|
3917
|
+
),
|
|
3918
|
+
name: z
|
|
3919
|
+
.string()
|
|
3920
|
+
.optional()
|
|
3921
|
+
.describe("The group's name: the new group's for 'create', the name to set for 'rename'"),
|
|
3922
|
+
userIds: z
|
|
3923
|
+
.array(z.string().min(1))
|
|
3924
|
+
.min(1)
|
|
3925
|
+
.max(100)
|
|
3926
|
+
.optional()
|
|
3927
|
+
.describe(
|
|
3928
|
+
"Numeric Zalo user ids (required for 'create', 'add_members', 'add_admin', 'remove_admin', " +
|
|
3929
|
+
"'block_member', 'unblock_member', 'approve', 'reject_member' and 'members_info')",
|
|
3930
|
+
),
|
|
3931
|
+
userId: z
|
|
3932
|
+
.string()
|
|
3933
|
+
.min(1)
|
|
3934
|
+
.optional()
|
|
3935
|
+
.describe(
|
|
3936
|
+
"Numeric Zalo user id (required for 'remove_member', 'transfer_owner' and 'invite_to')",
|
|
3937
|
+
),
|
|
3938
|
+
silent: z
|
|
3939
|
+
.boolean()
|
|
3940
|
+
.optional()
|
|
3941
|
+
.describe(
|
|
3942
|
+
"Only for 'leave': hide the usual notice from ordinary members; the owner still sees it (default false)",
|
|
3943
|
+
),
|
|
3944
|
+
newOwner: z
|
|
3945
|
+
.string()
|
|
3946
|
+
.min(1)
|
|
3947
|
+
.optional()
|
|
3948
|
+
.describe(
|
|
3949
|
+
"Only for 'leave' by the group's owner: the member (numeric user id) who owns the group next; " +
|
|
3950
|
+
"ownership is handed over, then the account leaves",
|
|
3951
|
+
),
|
|
3952
|
+
randomOwner: z
|
|
3953
|
+
.boolean()
|
|
3954
|
+
.optional()
|
|
3955
|
+
.describe(
|
|
3956
|
+
"Only for 'leave' by the group's owner: leave and let Zalo give ownership to a random member",
|
|
3957
|
+
),
|
|
3958
|
+
...GROUP_EXTRA_INPUTS,
|
|
3959
|
+
confirm: confirmInput("the actions asked about first (listed above)"),
|
|
3960
|
+
ticket: ticketInput(),
|
|
3961
|
+
dryRun: dryRunInput("the actions asked about first (listed above)"),
|
|
3962
|
+
})
|
|
3963
|
+
.strict(),
|
|
2838
3964
|
},
|
|
2839
|
-
async (
|
|
3965
|
+
async (args, extra) => {
|
|
3966
|
+
// The actions added with the action tools run through the shared runner (src/mcp/action-tool.js).
|
|
3967
|
+
if (Object.hasOwn(GROUP_EXTRA_ACTIONS, args.action)) return groupExtra(args, extra);
|
|
3968
|
+
const { action, groupId, name, userIds, userId, silent, newOwner, randomOwner, confirm, dryRun, ticket } =
|
|
3969
|
+
args;
|
|
2840
3970
|
const gid = groupId === undefined ? "" : String(groupId).trim();
|
|
2841
|
-
if (["leave", "info", "add_members", "remove_member"].includes(action)) {
|
|
3971
|
+
if (["leave", "info", "add_members", "remove_member", "rename"].includes(action)) {
|
|
2842
3972
|
if (!gid) return err(`groupId is required for action='${action}'.`);
|
|
2843
3973
|
if (!/^\d{1,30}$/.test(gid)) {
|
|
2844
3974
|
return err(
|
|
@@ -2868,22 +3998,54 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2868
3998
|
}
|
|
2869
3999
|
}
|
|
2870
4000
|
const groupName = name === undefined ? "" : String(name).trim();
|
|
2871
|
-
if (action === "create"
|
|
4001
|
+
if ((action === "create" || action === "rename") && !groupName) {
|
|
4002
|
+
return err(`name is required for action='${action}'.`);
|
|
4003
|
+
}
|
|
4004
|
+
|
|
4005
|
+
if ((newOwner !== undefined || randomOwner !== undefined) && action !== "leave") {
|
|
4006
|
+
return err("newOwner and randomOwner are only for action='leave'.");
|
|
4007
|
+
}
|
|
4008
|
+
// A leave is read first: the owner's leave without a successor, or a successor who is not a member, is
|
|
4009
|
+
// refused before the guard and before anything is sent (src/core/group-departure.js).
|
|
4010
|
+
let leavePlan = null;
|
|
4011
|
+
if (action === "leave") {
|
|
4012
|
+
try {
|
|
4013
|
+
leavePlan = await planLeave(api, {
|
|
4014
|
+
groupId: gid,
|
|
4015
|
+
ownId: ownIdOf(api) || null,
|
|
4016
|
+
newOwner,
|
|
4017
|
+
randomOwner: randomOwner === true,
|
|
4018
|
+
});
|
|
4019
|
+
} catch (e) {
|
|
4020
|
+
return err(departureMessage(e, "mcp"));
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
2872
4023
|
|
|
2873
4024
|
// After validation, before Zalo: a refused call changes nothing and says exactly how to retry.
|
|
2874
|
-
if (
|
|
2875
|
-
const
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
4025
|
+
if (action === "leave" || action === "remove_member") {
|
|
4026
|
+
const held = await gate(
|
|
4027
|
+
action === "leave" ? "group.leave" : "group.removeMember",
|
|
4028
|
+
action === "leave"
|
|
4029
|
+
? {
|
|
4030
|
+
groupId: gid,
|
|
4031
|
+
silent: silent === true,
|
|
4032
|
+
newOwner: leavePlan.newOwner,
|
|
4033
|
+
randomOwner: leavePlan.handOver === "random",
|
|
4034
|
+
}
|
|
4035
|
+
: { groupId: gid, userIds: [target] },
|
|
4036
|
+
{ confirm, dryRun, ticket },
|
|
4037
|
+
extra,
|
|
2880
4038
|
);
|
|
4039
|
+
if (held) return held;
|
|
2881
4040
|
}
|
|
2882
4041
|
|
|
2883
4042
|
try {
|
|
2884
4043
|
switch (action) {
|
|
2885
4044
|
case "info": {
|
|
2886
|
-
const info = groupInfoFrom(
|
|
4045
|
+
const info = groupInfoFrom(
|
|
4046
|
+
await getGroupInfoWatched(api, ownIdOf(api) || null, [String(gid)]),
|
|
4047
|
+
gid,
|
|
4048
|
+
);
|
|
2887
4049
|
if (!info) {
|
|
2888
4050
|
return err(
|
|
2889
4051
|
`Zalo's answer does not include group ${gid}: this account is not in it, or it is not ` +
|
|
@@ -2932,16 +4094,26 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2932
4094
|
}
|
|
2933
4095
|
return ok({ action, success: true, groupId: gid, userId: target });
|
|
2934
4096
|
}
|
|
4097
|
+
case "rename": {
|
|
4098
|
+
// The same call as the CLI's `group rename` (the session takes the name first).
|
|
4099
|
+
await api.changeGroupName(groupName, gid);
|
|
4100
|
+
return ok({ action, success: true, groupId: gid, name: groupName });
|
|
4101
|
+
}
|
|
2935
4102
|
case "leave": {
|
|
2936
4103
|
const quiet = silent === true;
|
|
2937
|
-
const res = await api
|
|
4104
|
+
const res = await runLeave(api, leavePlan, { silent: quiet });
|
|
2938
4105
|
const memberError = Array.isArray(res?.memberError) ? res.memberError : [];
|
|
4106
|
+
// As Zalo does on the API's success: the group's local history goes now (or is kept flagged,
|
|
4107
|
+
// groups.onLeave), whether or not a listener sees the echo.
|
|
4108
|
+
const exit = await recordOwnExit({ ownId: ownIdOf(api), groupId: gid, reason: "leave" });
|
|
2939
4109
|
return ok({
|
|
2940
4110
|
action,
|
|
2941
4111
|
success: true,
|
|
2942
4112
|
groupId: gid,
|
|
2943
4113
|
silent: quiet,
|
|
4114
|
+
...(res.handOver && { ownership: res.handOver, newOwner: res.newOwner }),
|
|
2944
4115
|
...(memberError.length > 0 && { memberError }),
|
|
4116
|
+
...exit,
|
|
2945
4117
|
});
|
|
2946
4118
|
}
|
|
2947
4119
|
default:
|
|
@@ -2966,4 +4138,134 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
2966
4138
|
}
|
|
2967
4139
|
},
|
|
2968
4140
|
);
|
|
4141
|
+
|
|
4142
|
+
// --- The action tools: one per area, each action the call its CLI command makes (src/mcp/actions-*.js) ---
|
|
4143
|
+
server.registerTool(
|
|
4144
|
+
"zalo_conversation",
|
|
4145
|
+
CONVERSATION_META,
|
|
4146
|
+
actionTool("zalo_conversation", CONVERSATION_ACTIONS, toolCtx),
|
|
4147
|
+
);
|
|
4148
|
+
server.registerTool("zalo_profile", PROFILE_META, actionTool("zalo_profile", PROFILE_ACTIONS, toolCtx));
|
|
4149
|
+
server.registerTool("zalo_auto_reply", AUTO_REPLY_META, actionTool("zalo_auto_reply", AUTO_REPLY_ACTIONS, toolCtx));
|
|
4150
|
+
server.registerTool(
|
|
4151
|
+
"zalo_quick_message",
|
|
4152
|
+
QUICK_MESSAGE_META,
|
|
4153
|
+
actionTool("zalo_quick_message", QUICK_MESSAGE_ACTIONS, toolCtx),
|
|
4154
|
+
);
|
|
4155
|
+
server.registerTool("zalo_catalog", CATALOG_META, actionTool("zalo_catalog", CATALOG_ACTIONS, toolCtx));
|
|
4156
|
+
server.registerTool("zalo_bank", BANK_META, actionTool("zalo_bank", BANK_ACTIONS, toolCtx));
|
|
4157
|
+
server.registerTool("zalo_cloud", CLOUD_META, actionTool("zalo_cloud", CLOUD_ACTIONS, toolCtx));
|
|
4158
|
+
server.registerTool("zalo_sticker", STICKER_META, actionTool("zalo_sticker", STICKER_ACTIONS, toolCtx));
|
|
4159
|
+
server.registerTool("zalo_link", LINK_META, actionTool("zalo_link", LINK_ACTIONS, toolCtx));
|
|
4160
|
+
|
|
4161
|
+
// --- zalo_official: the oa / zbs / social commands, run as the CLI runs them (./official-tool.js) ---
|
|
4162
|
+
server.registerTool("zalo_official", officialMeta(), officialTool(toolCtx));
|
|
4163
|
+
|
|
4164
|
+
// --- zalo_read ---
|
|
4165
|
+
server.registerTool(
|
|
4166
|
+
"zalo_read",
|
|
4167
|
+
{
|
|
4168
|
+
title: "Read From Zalo's API",
|
|
4169
|
+
description:
|
|
4170
|
+
"Ask Zalo one of the read-only endpoints Zalo calls that no other tool covers: the sticker and GIF " +
|
|
4171
|
+
"catalogs and GIF search, a profile's rank and extra fields, the block list, the nickname list, the " +
|
|
4172
|
+
"search history Zalo keeps, delivery and seen status, the group quota and the account's role in a " +
|
|
4173
|
+
"group, friend profile checks, the emoji statuses of friends, the server's client settings, and " +
|
|
4174
|
+
"more. Omit `name` to list every read with what it takes and whether a live account has answered it; " +
|
|
4175
|
+
"give `name` and `args` to run one. It only reads: nothing here sends, marks, changes or removes " +
|
|
4176
|
+
"anything. `args` is an object named by the read's own argument list (ids are strings).",
|
|
4177
|
+
inputSchema: z.object({
|
|
4178
|
+
name: z
|
|
4179
|
+
.enum(READ_NAMES)
|
|
4180
|
+
.optional()
|
|
4181
|
+
.describe("The read to run (omit to list them all, with their arguments)"),
|
|
4182
|
+
args: z
|
|
4183
|
+
.record(z.string(), z.any())
|
|
4184
|
+
.optional()
|
|
4185
|
+
.describe('The read\'s arguments by name, e.g. {"id": "123"} for profile-rank'),
|
|
4186
|
+
}),
|
|
4187
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
4188
|
+
},
|
|
4189
|
+
async ({ name, args }) => {
|
|
4190
|
+
if (!name) return ok({ reads: describeReads() });
|
|
4191
|
+
// A read about one conversation names it in its args; a hidden one is left out like everywhere else.
|
|
4192
|
+
if (readThreadIds(args).some(isHiddenThread)) return err(HIDDEN_THREAD);
|
|
4193
|
+
try {
|
|
4194
|
+
// A paged read with no page chosen is read to its end (READ_PAGERS in src/zalo/reads.js).
|
|
4195
|
+
const { data, paging } = await callReadAll(api, name, args || {});
|
|
4196
|
+
return ok({ name, data: data ?? null, ...(paging?.note && { note: paging.note }) });
|
|
4197
|
+
} catch (e) {
|
|
4198
|
+
if (!(e instanceof ReadUsageError)) console.error("[mcp-tools] zalo_read error:", e.message);
|
|
4199
|
+
return err(e.message);
|
|
4200
|
+
}
|
|
4201
|
+
},
|
|
4202
|
+
);
|
|
4203
|
+
|
|
4204
|
+
// --- zalo_write ---
|
|
4205
|
+
server.registerTool(
|
|
4206
|
+
"zalo_write",
|
|
4207
|
+
{
|
|
4208
|
+
title: "Change Something Through Zalo's API",
|
|
4209
|
+
description:
|
|
4210
|
+
"Make one of the state-changing calls Zalo makes that no other tool covers: reminder RSVP, creating " +
|
|
4211
|
+
"or changing a group note or reminder with a repeat rule, pinning and unpinning board items, removing a " +
|
|
4212
|
+
"topic, recalling several messages at once, suggested-friend cleanup, blocking an " +
|
|
4213
|
+
"Official Account, removing one account from several groups, the search history. Omit `name` to list " +
|
|
4214
|
+
"every write with what it touches (`risk`: private, visible to others, or destructive), what it takes, " +
|
|
4215
|
+
"whether a live success was seen (`verified`) and, if not, why (`note`). EVERY write changes " +
|
|
4216
|
+
'something, so a real call is asked about first, even where the deployment\'s confirmMode is "off" ' +
|
|
4217
|
+
'(`confirm: true`; in "human" mode the server asks the user), and `dryRun: true` ' +
|
|
4218
|
+
"returns the request that would be sent without sending anything: use it first, and try an unverified " +
|
|
4219
|
+
"write on something disposable. Enum-like arguments take Zalo's own names or numbers (`list` " +
|
|
4220
|
+
"shows them). `args` is an object named by the write's own argument list (ids are strings).",
|
|
4221
|
+
inputSchema: z.object({
|
|
4222
|
+
name: z
|
|
4223
|
+
.enum(WRITE_NAMES)
|
|
4224
|
+
.optional()
|
|
4225
|
+
.describe("The write to make (omit to list them all, with their arguments and risk)"),
|
|
4226
|
+
args: z
|
|
4227
|
+
.record(z.string(), z.any())
|
|
4228
|
+
.optional()
|
|
4229
|
+
.describe('The write\'s arguments by name, e.g. {"groupId": "123", "topicId": "45"}'),
|
|
4230
|
+
dryRun: z
|
|
4231
|
+
.boolean()
|
|
4232
|
+
.optional()
|
|
4233
|
+
.describe("Return the request that would be sent, with its body decrypted, and send nothing"),
|
|
4234
|
+
confirm: confirmInput("a real call (not needed with dryRun)"),
|
|
4235
|
+
ticket: ticketInput(),
|
|
4236
|
+
}),
|
|
4237
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
|
|
4238
|
+
},
|
|
4239
|
+
async ({ name, args, dryRun, confirm, ticket }, extra) => {
|
|
4240
|
+
if (!name) return ok({ writes: describeWrites() });
|
|
4241
|
+
// Arguments first, as for every guarded action: a call missing one is refused as the typo it is, before
|
|
4242
|
+
// anyone is asked to confirm a request that could not be sent. Building the request sends nothing; a
|
|
4243
|
+
// failure that is not about the arguments is left to the call itself.
|
|
4244
|
+
try {
|
|
4245
|
+
buildWrite(api, name, args || {});
|
|
4246
|
+
} catch (e) {
|
|
4247
|
+
if (e instanceof ReadUsageError) return err(e.message);
|
|
4248
|
+
}
|
|
4249
|
+
// dryRun is the write's own: it returns the request itself, so only a real call is gated. A raw
|
|
4250
|
+
// endpoint runner stays gated even in confirmMode "off".
|
|
4251
|
+
if (!dryRun) {
|
|
4252
|
+
const def = WRITES[name];
|
|
4253
|
+
const held = await gate(
|
|
4254
|
+
"write.run",
|
|
4255
|
+
{ name, risk: def?.risk, verified: def?.verified, args: args || {} },
|
|
4256
|
+
{ confirm, ticket },
|
|
4257
|
+
extra,
|
|
4258
|
+
{ always: true },
|
|
4259
|
+
);
|
|
4260
|
+
if (held) return held;
|
|
4261
|
+
}
|
|
4262
|
+
try {
|
|
4263
|
+
const data = await callWrite(api, name, args || {}, { dryRun: dryRun === true });
|
|
4264
|
+
return ok(dryRun ? data : { name, data: data ?? null });
|
|
4265
|
+
} catch (e) {
|
|
4266
|
+
if (!(e instanceof ReadUsageError)) console.error("[mcp-tools] zalo_write error:", e.message);
|
|
4267
|
+
return err(e.message);
|
|
4268
|
+
}
|
|
4269
|
+
},
|
|
4270
|
+
);
|
|
2969
4271
|
}
|