miaw-core 1.9.1 → 1.12.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 +78 -0
- package/CHANGELOG.md +367 -0
- package/README.md +116 -26
- package/bin/miaw-cli.ts +100 -9
- package/dist/cli/commands/call.d.ts +16 -0
- package/dist/cli/commands/call.d.ts.map +1 -0
- package/dist/cli/commands/call.js +29 -0
- package/dist/cli/commands/call.js.map +1 -0
- package/dist/cli/commands/chat.d.ts +14 -0
- package/dist/cli/commands/chat.d.ts.map +1 -1
- package/dist/cli/commands/chat.js +48 -0
- package/dist/cli/commands/chat.js.map +1 -1
- package/dist/cli/commands/commands-index.d.ts +8 -5
- package/dist/cli/commands/commands-index.d.ts.map +1 -1
- package/dist/cli/commands/commands-index.js +12 -5
- package/dist/cli/commands/commands-index.js.map +1 -1
- package/dist/cli/commands/community.d.ts +28 -0
- package/dist/cli/commands/community.d.ts.map +1 -1
- package/dist/cli/commands/community.js +83 -0
- package/dist/cli/commands/community.js.map +1 -1
- package/dist/cli/commands/group.d.ts +49 -0
- package/dist/cli/commands/group.d.ts.map +1 -1
- package/dist/cli/commands/group.js +151 -0
- package/dist/cli/commands/group.js.map +1 -1
- package/dist/cli/commands/index.d.ts +15 -5
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +491 -46
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/instance.d.ts +46 -7
- package/dist/cli/commands/instance.d.ts.map +1 -1
- package/dist/cli/commands/instance.js +224 -34
- package/dist/cli/commands/instance.js.map +1 -1
- package/dist/cli/commands/privacy.d.ts +83 -0
- package/dist/cli/commands/privacy.d.ts.map +1 -0
- package/dist/cli/commands/privacy.js +167 -0
- package/dist/cli/commands/privacy.js.map +1 -0
- package/dist/cli/commands/proxy.d.ts +59 -0
- package/dist/cli/commands/proxy.d.ts.map +1 -0
- package/dist/cli/commands/proxy.js +418 -0
- package/dist/cli/commands/proxy.js.map +1 -0
- package/dist/cli/commands/send.d.ts +12 -0
- package/dist/cli/commands/send.d.ts.map +1 -1
- package/dist/cli/commands/send.js +44 -0
- package/dist/cli/commands/send.js.map +1 -1
- package/dist/cli/repl.d.ts +8 -6
- package/dist/cli/repl.d.ts.map +1 -1
- package/dist/cli/repl.js +501 -81
- package/dist/cli/repl.js.map +1 -1
- package/dist/cli/utils/client-cache.d.ts +8 -0
- package/dist/cli/utils/client-cache.d.ts.map +1 -1
- package/dist/cli/utils/client-cache.js +66 -7
- package/dist/cli/utils/client-cache.js.map +1 -1
- package/dist/cli/utils/instance-config.d.ts +89 -0
- package/dist/cli/utils/instance-config.d.ts.map +1 -0
- package/dist/cli/utils/instance-config.js +224 -0
- package/dist/cli/utils/instance-config.js.map +1 -0
- package/dist/cli/utils/instance-registry.d.ts +7 -0
- package/dist/cli/utils/instance-registry.d.ts.map +1 -1
- package/dist/cli/utils/instance-registry.js +2 -0
- package/dist/cli/utils/instance-registry.js.map +1 -1
- package/dist/cli/utils/parse-args.d.ts +41 -0
- package/dist/cli/utils/parse-args.d.ts.map +1 -0
- package/dist/cli/utils/parse-args.js +84 -0
- package/dist/cli/utils/parse-args.js.map +1 -0
- package/dist/cli/utils/proxy-config.d.ts +46 -0
- package/dist/cli/utils/proxy-config.d.ts.map +1 -0
- package/dist/cli/utils/proxy-config.js +93 -0
- package/dist/cli/utils/proxy-config.js.map +1 -0
- package/dist/cli/utils/proxy-resolver.d.ts +91 -0
- package/dist/cli/utils/proxy-resolver.d.ts.map +1 -0
- package/dist/cli/utils/proxy-resolver.js +180 -0
- package/dist/cli/utils/proxy-resolver.js.map +1 -0
- package/dist/cli/utils/session.d.ts +24 -1
- package/dist/cli/utils/session.d.ts.map +1 -1
- package/dist/cli/utils/session.js +5 -0
- package/dist/cli/utils/session.js.map +1 -1
- package/dist/client/MiawClient.d.ts +333 -9
- package/dist/client/MiawClient.d.ts.map +1 -1
- package/dist/client/MiawClient.js +874 -30
- package/dist/client/MiawClient.js.map +1 -1
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +234 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +22 -0
- package/dist/types/index.js.map +1 -1
- package/dist/utils/browser-presets.d.ts +51 -0
- package/dist/utils/browser-presets.d.ts.map +1 -0
- package/dist/utils/browser-presets.js +53 -0
- package/dist/utils/browser-presets.js.map +1 -0
- package/dist/utils/proxy-agent.d.ts +47 -11
- package/dist/utils/proxy-agent.d.ts.map +1 -1
- package/dist/utils/proxy-agent.js +65 -12
- package/dist/utils/proxy-agent.js.map +1 -1
- package/dist/utils/proxy-loader.d.ts +114 -0
- package/dist/utils/proxy-loader.d.ts.map +1 -0
- package/dist/utils/proxy-loader.js +379 -0
- package/dist/utils/proxy-loader.js.map +1 -0
- package/dist/utils/proxy-rotator.d.ts +132 -0
- package/dist/utils/proxy-rotator.d.ts.map +1 -0
- package/dist/utils/proxy-rotator.js +268 -0
- package/dist/utils/proxy-rotator.js.map +1 -0
- package/docs/API_STABILITY_REVIEW.md +10 -0
- package/docs/BAILEYS_MIGRATION_v7.md +10 -1
- package/docs/BAILEYS_VS_MIAW_COMPARISON.md +69 -48
- package/docs/CLI-ANALYSIS.md +10 -0
- package/docs/CLI.md +381 -4
- package/docs/CLI_INTEGRATION_TEST_PLAN.md +58 -24
- package/docs/CODE_REVIEW_REPORT.md +10 -0
- package/docs/DEFERRED_FEATURES.md +34 -38
- package/docs/DEPLOYMENT_INSTANCE_PROXY.md +168 -0
- package/docs/DEPLOYMENT_PROXY.md +151 -0
- package/docs/DEPLOYMENT_V1.12.0.md +163 -0
- package/docs/FOLLOW_UPS.md +320 -0
- package/docs/MIGRATION.md +147 -2
- package/docs/PROXY.md +706 -0
- package/docs/TEST_COVERAGE_ANALYSIS.md +29 -5
- package/docs/USAGE.md +340 -59
- package/package.json +8 -4
- package/sessions-cli/.cli_history +2 -0
- package/docs/PROXY_SUPPORT_PLAN.md +0 -1442
package/.env.example
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# miaw-core / miaw-cli runtime configuration
|
|
2
|
+
#
|
|
3
|
+
# Copy to .env and edit. Every value here is optional — each has a default and
|
|
4
|
+
# each can also be supplied as a CLI flag. Flags win over environment variables.
|
|
5
|
+
#
|
|
6
|
+
# cp .env.example .env
|
|
7
|
+
#
|
|
8
|
+
# .env is gitignored. Prefer this file over CLI flags for anything containing a
|
|
9
|
+
# password: flags land in your shell history and in the process list, where any
|
|
10
|
+
# other user on the machine can read them.
|
|
11
|
+
|
|
12
|
+
# ─── Instance ────────────────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
# Instance ID. Sessions are isolated per instance. (flag: --instance-id)
|
|
15
|
+
MIAW_INSTANCE_ID=default
|
|
16
|
+
|
|
17
|
+
# Where session credentials are stored, as {MIAW_SESSION_PATH}/{MIAW_INSTANCE_ID}/
|
|
18
|
+
# (flag: --session-path)
|
|
19
|
+
MIAW_SESSION_PATH=./sessions-cli
|
|
20
|
+
|
|
21
|
+
# ─── Proxy (all optional; added in v1.10.0) ──────────────────────────────────
|
|
22
|
+
#
|
|
23
|
+
# Precedence, highest first (v1.11.0):
|
|
24
|
+
# 1. MIAW_PROXY / --proxy always wins; warns when it shadows a pin
|
|
25
|
+
# 2. a pin in <MIAW_SESSION_PATH>/instances.json, per instance
|
|
26
|
+
# 3. MIAW_PROXY_FILE + strategy hashed on the TARGET instanceId
|
|
27
|
+
# 4. direct
|
|
28
|
+
#
|
|
29
|
+
# The pin store is written by `miaw-cli instance set-proxy <id> ...`, not by
|
|
30
|
+
# env vars - it is per-instance state, so it belongs with the sessions rather
|
|
31
|
+
# than with process config. It holds credentials when a URL is pinned, so it is
|
|
32
|
+
# written 0600 and must live on the same persistent, secret-grade volume as the
|
|
33
|
+
# session directories. See docs/DEPLOYMENT_INSTANCE_PROXY.md.
|
|
34
|
+
|
|
35
|
+
# A single proxy for this instance. (flag: --proxy)
|
|
36
|
+
# Schemes: http, https, socks4, socks4a, socks5, socks5h
|
|
37
|
+
#
|
|
38
|
+
# Prefer the h/a variants (socks5h, socks4a): plain socks5/socks4 resolve DNS
|
|
39
|
+
# locally, so the destination hostname leaks to your resolver even though the
|
|
40
|
+
# connection itself is tunnelled.
|
|
41
|
+
#
|
|
42
|
+
# Passwords containing @ : / ? # or % must be percent-encoded here
|
|
43
|
+
# ("p@ss#1" becomes "p%40ss%231"), or use the ProxyConfig object form in code.
|
|
44
|
+
#
|
|
45
|
+
# MIAW_PROXY=socks5h://user:password@proxy.example.com:1080
|
|
46
|
+
|
|
47
|
+
# A proxy list file instead of a single proxy — TXT (one per line) or JSON
|
|
48
|
+
# array. A proxy is selected per instance using MIAW_PROXY_STRATEGY, keyed on
|
|
49
|
+
# the instance the command targets (v1.11.0; before that, once per process
|
|
50
|
+
# against the startup instance).
|
|
51
|
+
# Ignored when MIAW_PROXY is also set, and outranked by a per-instance pin.
|
|
52
|
+
# (flag: --proxy-file)
|
|
53
|
+
#
|
|
54
|
+
# Also required when an instance is pinned by label (`instance set-proxy <id>
|
|
55
|
+
# --label eu`): the label names an entry in THIS file. A label pin that cannot
|
|
56
|
+
# be resolved refuses to connect rather than silently going direct.
|
|
57
|
+
#
|
|
58
|
+
# See examples/proxies.example.txt for the format.
|
|
59
|
+
#
|
|
60
|
+
# MIAW_PROXY_FILE=./proxies.txt
|
|
61
|
+
|
|
62
|
+
# How a proxy is picked from MIAW_PROXY_FILE. (flag: --proxy-strategy)
|
|
63
|
+
# deterministic same instanceId always maps to the same proxy [default]
|
|
64
|
+
# round-robin next in the list, wrapping
|
|
65
|
+
# random uniform random
|
|
66
|
+
# weighted random, biased by each entry's weight=
|
|
67
|
+
#
|
|
68
|
+
# Leave this as deterministic for anything with a persisted WhatsApp session.
|
|
69
|
+
# WhatsApp treats a session's source IP as a trust signal, so a session whose
|
|
70
|
+
# egress IP jumps between runs looks like an account takeover. Rotation is for
|
|
71
|
+
# spreading instances across proxies, never for rotating a live session's IP.
|
|
72
|
+
#
|
|
73
|
+
# MIAW_PROXY_STRATEGY=deterministic
|
|
74
|
+
|
|
75
|
+
# ─── Logging ─────────────────────────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
# Verbose Baileys logging. (flag: --debug)
|
|
78
|
+
# DEBUG=false
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,330 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.12.0] - 2026-09-02
|
|
9
|
+
|
|
10
|
+
**Baileys 7.0.0-rc14, and the deferred feature backlog cleared.** All additive;
|
|
11
|
+
no breaking changes.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **Operator notes:** [docs/DEPLOYMENT_V1.12.0.md](docs/DEPLOYMENT_V1.12.0.md) —
|
|
16
|
+
no env, migration or state-format changes; rollback does not require re-pairing.
|
|
17
|
+
- **Upgraded `@whiskeysockets/baileys` from `7.0.0-rc13` to `7.0.0-rc14`** (pinned
|
|
18
|
+
exactly, as before). Four substantive upstream commits:
|
|
19
|
+
- WhatsApp Web version `2.3000.1035194821` → `2.3000.1043857760`. Low impact —
|
|
20
|
+
`resolveWAVersion()` already prefers the live version from `web.whatsapp.com`,
|
|
21
|
+
so the bundled constant is only the third-tier fallback — but a fresher
|
|
22
|
+
fallback is still worth having.
|
|
23
|
+
- **`profilePictureUrl` fix.** The privacy `tctoken` now nests under the
|
|
24
|
+
`picture` query node and carries a `t` attribute, matching WA Web. This
|
|
25
|
+
affects `getContactInfo()`, `getProfilePicture()` and `getChatInfo()` when
|
|
26
|
+
the target has profile-picture privacy enabled.
|
|
27
|
+
- New `Browsers.android()` identity (see below).
|
|
28
|
+
- An internal `Long` type import fix.
|
|
29
|
+
|
|
30
|
+
No public API changed; miaw-core's whole Baileys surface — including the
|
|
31
|
+
`updateBussinesProfile` typo, `signalRepository.lidMapping`, the hand-built
|
|
32
|
+
`remove-companion-device` node, `messaging-history.set` `lidPnMappings`, the
|
|
33
|
+
`resyncAppState` collection names, and the dispatcher passed into
|
|
34
|
+
`downloadMediaMessage` — is byte-identical between the two releases.
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- **`BrowserPresets`** — `macOS`, `windows`, `ubuntu` and `android` browser
|
|
39
|
+
identities for the `browser` option, which was previously undocumented outside
|
|
40
|
+
its JSDoc. The default is unchanged (`macOS("Chrome")`).
|
|
41
|
+
- **Android connection identity.** `BrowserPresets.android()` negotiates as an
|
|
42
|
+
Android client rather than a web one. Baileys reports this is required to
|
|
43
|
+
**receive view-once media**, which a web session is never sent
|
|
44
|
+
([#2201](https://github.com/WhiskeySockets/Baileys/pull/2201)); miaw-core
|
|
45
|
+
already normalizes view-once messages, so if that holds,
|
|
46
|
+
`message.media.viewOnce` and `downloadMedia()` work with no further change.
|
|
47
|
+
The handshake is verified here; the view-once receipt itself is upstream's
|
|
48
|
+
claim and is **not** confirmed end-to-end — see `tests/verify-viewonce.ts` to
|
|
49
|
+
check it on your own account. Baileys marks the identity experimental; prefer
|
|
50
|
+
a dedicated `instanceId` over switching an established session.
|
|
51
|
+
- **Group & community administration.** `setGroupAnnounceOnly`,
|
|
52
|
+
`setGroupRestrictInfo`, `setGroupMemberAddMode`, `setGroupJoinApproval`,
|
|
53
|
+
`setGroupEphemeral`, `getGroupJoinRequests`, `approveGroupJoinRequests`,
|
|
54
|
+
`rejectGroupJoinRequests`, and the eight `setCommunity*` /
|
|
55
|
+
`*CommunityJoinRequests` equivalents.
|
|
56
|
+
- **Privacy settings.** `getPrivacySettings()` plus `setLastSeenPrivacy`,
|
|
57
|
+
`setOnlinePrivacy`, `setProfilePicturePrivacy`, `setStatusPrivacy`,
|
|
58
|
+
`setReadReceiptsPrivacy`, `setGroupAddPrivacy`, `setMessagesPrivacy`,
|
|
59
|
+
`setCallPrivacy`, `setDefaultDisappearingMode` and `setLinkPreviewsDisabled`.
|
|
60
|
+
- **Blocklist.** `blockContact()`, `unblockContact()`, `getBlocklist()`,
|
|
61
|
+
`isBlocked()`.
|
|
62
|
+
- **Calls.** A new `call` event carrying a normalized `MiawCall`, plus
|
|
63
|
+
`rejectCall()` and `createCallLink()`. A single call fires the event several
|
|
64
|
+
times as it progresses; `status === "offer"` is the only stage at which
|
|
65
|
+
`rejectCall()` still works.
|
|
66
|
+
- **Disappearing messages.** `setChatEphemeral()` for 1:1 chats alongside the
|
|
67
|
+
group and community variants, with an `EphemeralDuration` constant for the four
|
|
68
|
+
durations the WhatsApp UI offers.
|
|
69
|
+
- **Group invite cards.** `sendGroupInvite()` sends the rich "join my group" card
|
|
70
|
+
rather than a pasted link. Its payload type is `GroupInviteMessage` — distinct
|
|
71
|
+
from the existing `GroupInviteInfo`, which is the *preview* returned by
|
|
72
|
+
`getGroupInviteInfo()` before joining.
|
|
73
|
+
- **Pin-in-chat.** `pinMessage()` / `unpinMessage()`, with a `PinDuration`
|
|
74
|
+
constant. WhatsApp accepts only 24h, 7d and 30d here — a different set from the
|
|
75
|
+
disappearing-message durations.
|
|
76
|
+
- **CLI:** `group|community announce|restrict|add-mode|approval|ephemeral`,
|
|
77
|
+
`group|community requests list|approve|reject`, `privacy
|
|
78
|
+
show|set|disappearing|link-previews`, `block list|add|remove`, `call link`,
|
|
79
|
+
`chat ephemeral|pin-message|unpin-message`, and `send group-invite`. All with
|
|
80
|
+
tab completion and `help` topics.
|
|
81
|
+
- **`tests/unit/baileys-export-surface.test.ts`** — imports Baileys unmocked and
|
|
82
|
+
asserts every symbol the two import sites destructure still exists. Seventeen
|
|
83
|
+
unit suites replace the module wholesale with hand-written factories, so
|
|
84
|
+
without this a renamed or removed upstream export stays invisible until
|
|
85
|
+
runtime.
|
|
86
|
+
|
|
87
|
+
### Fixed
|
|
88
|
+
|
|
89
|
+
- **`community invite-link` was advertised but never worked.** The subcommand
|
|
90
|
+
list printed by `community` has named it since v1.9.0, but the dispatch
|
|
91
|
+
switch had no `case` for it, so it fell through to the unknown-command
|
|
92
|
+
branch and always errored. `group invite-link` has existed since v1.4.
|
|
93
|
+
- **Five `help` topics tab-completed and then failed.** `help chat|story|
|
|
94
|
+
community|call|business` were offered by completion but had no case in
|
|
95
|
+
`showReplHelp()`, printing "Unknown help topic". The completion tree, the
|
|
96
|
+
dispatch and two "available topics" lines were four hand-maintained copies
|
|
97
|
+
of the same list; they are now all derived from one `HELP_TOPIC_HANDLERS`
|
|
98
|
+
map, and the five missing help screens were written.
|
|
99
|
+
- **`test:manual:build` never worked and has been removed.** It ran
|
|
100
|
+
`node dist/tests/interactive-test.js`, but `tsconfig.json` sets
|
|
101
|
+
`rootDir: ./src` and excludes `tests/`, so `dist/tests/` is never emitted.
|
|
102
|
+
- **`sendGroupInvite()` failed for any group without a profile picture.** Baileys
|
|
103
|
+
embeds a thumbnail on the invite card by calling `getProfilePicUrl(groupJid)`
|
|
104
|
+
and does not guard it; WhatsApp answers `item-not-found` for a pictureless
|
|
105
|
+
group, which throws and aborts the whole send. Since most groups have no
|
|
106
|
+
picture, the unguarded path failed more often than it worked. `sendGroupInvite`
|
|
107
|
+
now passes its own guarded hook — Baileys spreads caller options last, so it
|
|
108
|
+
wins — and sends the card without a thumbnail rather than not at all. Found by
|
|
109
|
+
live testing; it is invisible to unit tests because the mock never throws.
|
|
110
|
+
- **Omitting a disappearing-message duration silently disabled it.**
|
|
111
|
+
`miaw-cli group ephemeral <jid>` with no duration turned disappearing messages
|
|
112
|
+
**off** for the whole group instead of printing a usage line — `Number("")` is
|
|
113
|
+
`0`, and `0` is a valid duration meaning "off", so the missing argument parsed
|
|
114
|
+
as a successful request to disable. Same for `community ephemeral`,
|
|
115
|
+
`chat ephemeral`, and `privacy disappearing` (which changed an account-wide
|
|
116
|
+
default). Found in review of this release, before any of it shipped.
|
|
117
|
+
- **`--force` could swallow the following token.** It was missing from
|
|
118
|
+
`BOOLEAN_FLAGS` in `bin/miaw-cli.ts`, the same class of bug that `--json` hit
|
|
119
|
+
previously.
|
|
120
|
+
- **CLI docs gap.** `chat` commands were entirely undocumented in
|
|
121
|
+
[CLI.md](docs/CLI.md) despite shipping in v1.7.0; they now have a section.
|
|
122
|
+
|
|
123
|
+
### Verified live
|
|
124
|
+
|
|
125
|
+
Against a real WhatsApp connection (Baileys rc14):
|
|
126
|
+
|
|
127
|
+
- **`profilePictureUrl`** — the upstream tctoken-nesting fix. 2 of 5 real
|
|
128
|
+
contacts resolved to live URLs; the rest correctly returned `null`.
|
|
129
|
+
- **`getPrivacySettings()`** — WhatsApp returned 16 categories; the 8 with
|
|
130
|
+
Baileys setters map onto typed fields and the other 8 survive under `raw`.
|
|
131
|
+
- **All 19 v1.12.0 write paths** — every group setting toggled and restored with
|
|
132
|
+
a read-back confirming the change landed, plus 1:1 ephemeral, privacy
|
|
133
|
+
round-trips, `sendGroupInvite`, pin/unpin, and `createCallLink`. 19/19.
|
|
134
|
+
- **`BrowserPresets.android()`** — WhatsApp issued a QR rather than a 428, so
|
|
135
|
+
the `Platform.ANDROID` handshake is accepted. End-to-end view-once *receipt*
|
|
136
|
+
is not yet confirmed; see [FOLLOW_UPS.md](docs/FOLLOW_UPS.md) section 7.
|
|
137
|
+
- **No regressions from rc14.** The CLI integration suite has 15 pre-existing
|
|
138
|
+
failures, unrelated to this release — running the same six suites against
|
|
139
|
+
rc13 produced a byte-identical failure set. They are catalogued in
|
|
140
|
+
[FOLLOW_UPS.md](docs/FOLLOW_UPS.md) section 9.
|
|
141
|
+
|
|
142
|
+
### Internal
|
|
143
|
+
|
|
144
|
+
- `jest.config.js` sets `maxWorkers: 1`. The live-connection suites share a
|
|
145
|
+
single WhatsApp session, and forking one worker per core for a full run is
|
|
146
|
+
memory-hungry; `test:cli` already passed `--runInBand` for the first reason.
|
|
147
|
+
- CLI integration teardown moved from `10-business-commands.test.ts` to the new
|
|
148
|
+
`13-privacy-call-commands.test.ts`. Files run in name order and 13 is now the
|
|
149
|
+
last one needing a connection (11 and 12 are deliberately offline), so
|
|
150
|
+
disconnecting at 10 would pull the socket out from under it.
|
|
151
|
+
- 615 unit tests across 29 suites (up from 417), 105 CLI router tests (up from
|
|
152
|
+
26), 278 CLI integration tests across 13 files (up from 238).
|
|
153
|
+
- New `tests/unit/cli-help-consistency.test.ts` and a dispatchability sweep in
|
|
154
|
+
`01-command-router.test.ts`, both verified to fail against the previous code.
|
|
155
|
+
- The manual runner grew from 82 to 96 entries, and gained a `community` group:
|
|
156
|
+
all 19 community methods, v1.9.0's included, had been unreachable from it.
|
|
157
|
+
|
|
158
|
+
## [1.11.0] - 2026-09-02
|
|
159
|
+
|
|
160
|
+
### Added
|
|
161
|
+
|
|
162
|
+
- **Per-instance proxy pins (CLI).** `miaw-cli instance set-proxy <id>` persists a
|
|
163
|
+
proxy assignment to `<session-path>/instances.json`, so
|
|
164
|
+
`miaw-cli --instance-id bot-3 <command>` uses bot-3's proxy with no flags.
|
|
165
|
+
Four sources: a positional URL, `--label <name>` (selects a `label=` entry from
|
|
166
|
+
the proxy file and stores **no credentials**), `--from-env <VAR>`, and
|
|
167
|
+
`--from-file` (materializes the current deterministic selection).
|
|
168
|
+
`instance unset-proxy <id>` removes it.
|
|
169
|
+
- `instance ls` gains a Proxy column (masked) and lists instances that are pinned
|
|
170
|
+
but not yet created as `[not created]` — pinning before `instance create` is
|
|
171
|
+
supported, so the pairing itself comes from the final egress IP.
|
|
172
|
+
- **`MiawClient.setProxy(proxy)`** — stages a proxy for the **next** `connect()`,
|
|
173
|
+
returning `{ success, proxy, reconnectRequired, error }`. It never touches a
|
|
174
|
+
live socket, validates eagerly, and is refused when the client was constructed
|
|
175
|
+
with a custom `agent`/`fetchAgent`.
|
|
176
|
+
- `getProxyInfo()` gains `active` (is the open socket using this config?) and
|
|
177
|
+
`pending` (what it is using instead). The `{ url, protocol }` shape and the
|
|
178
|
+
`null`-for-custom-agent contract are unchanged.
|
|
179
|
+
- New exported types `SetProxyResult` and `ProxyInfo`.
|
|
180
|
+
- A complete, runnable dead-proxy failover recipe in docs/PROXY.md and
|
|
181
|
+
examples/10-proxy-rotation.ts, reusing a single client.
|
|
182
|
+
- `docs/DEPLOYMENT_INSTANCE_PROXY.md` — operational notes for the new
|
|
183
|
+
persistent pin store, and `docs/FOLLOW_UPS.md` for deferred findings.
|
|
184
|
+
|
|
185
|
+
### Behavior changes
|
|
186
|
+
|
|
187
|
+
- **`ProxyRotator` now defaults to `deterministic`, not `round-robin`.** The docs
|
|
188
|
+
and CLAUDE.md have always said deterministic is the default; only the CLI
|
|
189
|
+
actually applied it. The mismatch was silent and severe: following the docs
|
|
190
|
+
(`new ProxyRotator(urls)` then `next(id)`) gave round-robin, which hands a
|
|
191
|
+
long-lived session a different egress IP on each call — read by WhatsApp as
|
|
192
|
+
account takeover. Code changed rather than docs, so the default fails safe.
|
|
193
|
+
`next()` with no `instanceId` on a defaulted rotator now throws a message
|
|
194
|
+
naming the fix; pass `{ strategy: "round-robin" }` explicitly to restore the
|
|
195
|
+
old behavior. Checked against the sibling `miaw-api`, which constructs with an
|
|
196
|
+
explicit strategy and always calls `next(instanceId)`: unaffected.
|
|
197
|
+
|
|
198
|
+
### Fixed
|
|
199
|
+
|
|
200
|
+
- **The CLI silently dropped the proxy.** `instance create`/`connect`/`disconnect`/
|
|
201
|
+
`logout` built clients from `{instanceId, sessionPath}` only, discarding both
|
|
202
|
+
`proxy` and `debug`. Since the client cache key ignored the proxy, REPL
|
|
203
|
+
`connect <id>` cached a proxy-less client that every later command reused —
|
|
204
|
+
traffic went direct with no indication.
|
|
205
|
+
- **REPL `use <id>` carried the previous instance's proxy** to the next one: it
|
|
206
|
+
mutated `config.instanceId` in place without re-resolving.
|
|
207
|
+
- **Proxy selection ignored the target instance.** `--proxy-file` was resolved once
|
|
208
|
+
per process against the *startup* instance id, so `instance connect bot-3` got
|
|
209
|
+
another instance's egress IP. Resolution is now per target.
|
|
210
|
+
- `instance create` called `createClient()` directly, bypassing the cache, so the
|
|
211
|
+
freshly-paired live client was never registered and the next command built a
|
|
212
|
+
second `MiawClient` for the same account.
|
|
213
|
+
- An explicit `disconnect()` emitted `disconnected` twice — once as `"unknown"`
|
|
214
|
+
from the `connection.update{close}` that Baileys' `end()` fires, then once as
|
|
215
|
+
`"intentional"`.
|
|
216
|
+
- Console-filter reference leak: the filter was acquired only in the constructor
|
|
217
|
+
but released on every `disconnect()`/`logout()`, so a reconnect cycle lost this
|
|
218
|
+
client's reference and repeated cycles un-filtered other live clients' output.
|
|
219
|
+
- Proxy transports leaked: `connect()` built fresh agents on every call, auto-
|
|
220
|
+
reconnects included, and never released the old ones.
|
|
221
|
+
- `.cli_history` was written 0644 with every line verbatim, so an
|
|
222
|
+
`instance set-proxy` command turned it into a plaintext credential store. Now
|
|
223
|
+
redacted at entry and written 0600.
|
|
224
|
+
- **Global boolean flags swallowed the command name.** The arg parser assumed
|
|
225
|
+
every `--flag` took a value, so `miaw-cli --json instance ls` parsed as
|
|
226
|
+
`json="instance"` and failed with "Unknown command: ls" — even though
|
|
227
|
+
`--json` is documented as a global option. Value-less flags (`--json`,
|
|
228
|
+
`--debug`, `--ip`, `--from-file`, `--help`, `--version`) are now recognised
|
|
229
|
+
as booleans in any position.
|
|
230
|
+
- **`src/utils/proxy-rotator.ts` contained a literal NUL byte**, which made
|
|
231
|
+
`file(1)` classify the source as binary and caused `grep` to skip it in any
|
|
232
|
+
repo-wide search. Replaced with the equivalent escape sequence; verified
|
|
233
|
+
runtime-identical, so no instance is remapped to a different proxy.
|
|
234
|
+
- **Docs: `fetchAgent` is an `http.Agent`, not an undici Dispatcher.** The JSDoc
|
|
235
|
+
and three doc sites claimed otherwise; the PROXY.md "Custom agents" snippet was
|
|
236
|
+
copy-pasteable and would silently break every media upload through the proxy.
|
|
237
|
+
Also corrects the `createProxyAgents` API-table row and two broken anchors.
|
|
238
|
+
|
|
239
|
+
## [1.10.0] - 2026-07-29
|
|
240
|
+
|
|
241
|
+
**Proxy files, rotation, and CLI diagnostics** - builds on the v1.3.0 proxy core.
|
|
242
|
+
All additive; no breaking changes.
|
|
243
|
+
|
|
244
|
+
### Added
|
|
245
|
+
|
|
246
|
+
- **`socks5h://` and `socks4a://` support.** These resolve DNS *at the proxy*;
|
|
247
|
+
plain `socks5://` / `socks4://` resolve locally, so the destination hostname still
|
|
248
|
+
leaks to your DNS resolver even though the connection is tunnelled. Both variants
|
|
249
|
+
were previously rejected as unsupported protocols despite the underlying agent
|
|
250
|
+
supporting them.
|
|
251
|
+
- **Proxy list files** - `loadProxyList()` / `loadProxyListSync()` / `parseProxyList()`
|
|
252
|
+
read TXT (one per line, `#`/`;` comments, optional `weight=` and `label=` tokens,
|
|
253
|
+
scheme-less `host:port[:user:pass]` vendor forms) or JSON (array of strings and/or
|
|
254
|
+
objects, or a `{ "proxies": [...] }` wrapper). Format is auto-detected by extension
|
|
255
|
+
then by content. `validateProxyList()` partitions a list; `watchProxyList()` hot-reloads
|
|
256
|
+
a file.
|
|
257
|
+
- **`ProxyRotator`** - `round-robin`, `random`, `weighted`, and `deterministic`
|
|
258
|
+
strategies, plus `ProxyRotator.fromFile()`, `setProxies()`, `getStats()`, and `close()`.
|
|
259
|
+
It returns a `ProxyPoolEntry` you pass to `new MiawClient({ proxy })`, so `getProxyInfo()`
|
|
260
|
+
and proxy validation keep working for rotated instances.
|
|
261
|
+
- **`maskProxyUrl()`** - exported credential masking; `getProxyInfo()` now uses it.
|
|
262
|
+
- **CLI**: `proxy list` (alias `ls`), `proxy test <url>`, `proxy test-all`. These need
|
|
263
|
+
**no WhatsApp connection** - they probe the proxy through the same agent Baileys uses,
|
|
264
|
+
so you can validate a proxy before spending a pairing attempt on it. `proxy test-all`
|
|
265
|
+
exits non-zero if any proxy fails, so it can gate a deploy.
|
|
266
|
+
- **CLI global flags**: `--proxy-file <path>`, `--proxy-strategy <strategy>`
|
|
267
|
+
(default `deterministic`; `instance` accepted as an alias). Env fallbacks:
|
|
268
|
+
`MIAW_PROXY`, `MIAW_PROXY_FILE`, `MIAW_PROXY_STRATEGY`.
|
|
269
|
+
- **[.env.example](./.env.example)** - documents every `MIAW_*` runtime variable,
|
|
270
|
+
including `MIAW_INSTANCE_ID` and `MIAW_SESSION_PATH`, which the CLI has always
|
|
271
|
+
read but which were never written down anywhere.
|
|
272
|
+
- **[docs/DEPLOYMENT_PROXY.md](./docs/DEPLOYMENT_PROXY.md)** - operational notes for
|
|
273
|
+
deploying with proxies: why `instanceId` must be stable across rollouts, treating
|
|
274
|
+
proxy files as secrets, ConfigMap-safe hot reload, egress firewall rules, and the
|
|
275
|
+
sticky-session requirement.
|
|
276
|
+
- **[docs/PROXY.md](./docs/PROXY.md)** - dedicated proxy guide covering configuration,
|
|
277
|
+
proxy files, rotation, CLI diagnostics, troubleshooting, security, and provider
|
|
278
|
+
selection. Replaces the internal `docs/PROXY_SUPPORT_PLAN.md`, which is removed.
|
|
279
|
+
- 97 new tests (42 loader, 33 rotator, 22 CLI). The CLI proxy tests are the first in
|
|
280
|
+
`tests/integration/cli/` that run without a WhatsApp session.
|
|
281
|
+
|
|
282
|
+
### Fixed
|
|
283
|
+
|
|
284
|
+
- **Media uploads through a proxy were broken and always had been** (since v1.3.0).
|
|
285
|
+
`fetchAgent` was set to an undici `ProxyAgent`, but Baileys declares it as an
|
|
286
|
+
`https.Agent` and its Node upload path hands it to `https.request({ agent })`, which
|
|
287
|
+
cannot use a Dispatcher. Every `sendImage`/`sendVideo`/`sendDocument` through a proxy
|
|
288
|
+
failed with "Media upload failed on all hosts". `fetchAgent` is now the same
|
|
289
|
+
`http.Agent` as `wsAgent`. **Uploads are consequently proxied on SOCKS too**, which
|
|
290
|
+
the previous documentation said was impossible.
|
|
291
|
+
- **Media downloads were never proxied.** Baileys downloads with
|
|
292
|
+
`fetch(url, { dispatcher })` and never wires a proxy into that path, and
|
|
293
|
+
`downloadMedia()` passed no options — so every download revealed the real IP
|
|
294
|
+
regardless of proxy settings. It now passes an undici Dispatcher explicitly.
|
|
295
|
+
This works for HTTP/HTTPS proxies; SOCKS downloads remain direct because undici
|
|
296
|
+
has no SOCKS transport.
|
|
297
|
+
- `proxy test` reported a **407 Proxy Authentication Required as success**. A 407 comes
|
|
298
|
+
from the proxy itself and means the tunnel was refused, so nothing ever reached
|
|
299
|
+
WhatsApp - but the probe counted any HTTP status as reachable. `proxy test-all` would
|
|
300
|
+
therefore green-light a proxy list with wrong credentials, defeating the pre-flight
|
|
301
|
+
check it exists to provide. It now fails with `EPROXYAUTH` and a non-zero exit code.
|
|
302
|
+
- Proxy credentials leaked in two places: `MiawClient` interpolated the raw proxy URL,
|
|
303
|
+
password included, into its "Invalid proxy configuration" error (which lands in logs
|
|
304
|
+
and stack traces), and the CLI printed the raw `--proxy` URL to the REPL startup
|
|
305
|
+
banner. Both are masked now.
|
|
306
|
+
|
|
307
|
+
### Notes
|
|
308
|
+
|
|
309
|
+
- `--proxy-strategy` defaults to `deterministic` so a given `instanceId` keeps a stable
|
|
310
|
+
egress IP across runs. **Rotation is for distributing instances across proxies, never
|
|
311
|
+
for rotating a live session's IP** - WhatsApp treats a session's source IP as a trust
|
|
312
|
+
signal, and churning it looks like account takeover.
|
|
313
|
+
- Deterministic selection uses rendezvous hashing rather than `hash % length`, so adding
|
|
314
|
+
or removing a proxy remaps only the instances that were on it. Under modulo, one edit
|
|
315
|
+
to your proxy file would change the egress IP of every live session at once.
|
|
316
|
+
- SOCKS proxies still route media over a direct connection: Node's `fetch()` requires an
|
|
317
|
+
undici dispatcher and undici has no SOCKS transport. `proxy list` and `proxy test`
|
|
318
|
+
report this per proxy. See [docs/PROXY.md](./docs/PROXY.md).
|
|
319
|
+
|
|
320
|
+
## [1.9.2] - 2026-07-09
|
|
321
|
+
|
|
322
|
+
**CommonJS-consumer fix** - Let `require()` resolve the package.
|
|
323
|
+
|
|
324
|
+
### Fixed
|
|
325
|
+
|
|
326
|
+
- The `exports` map only declared the `import` condition, so CommonJS /
|
|
327
|
+
`require()` resolution (e.g. `ts-node` compiling to CJS) failed with
|
|
328
|
+
`ERR_PACKAGE_PATH_NOT_EXPORTED`. Added a `default` condition pointing at the
|
|
329
|
+
same ESM build; on Node >=22.12 `require(esm)` now resolves it. The package
|
|
330
|
+
stays ESM-only — no separate CJS build was added.
|
|
331
|
+
|
|
8
332
|
## [1.9.1] - 2026-07-07
|
|
9
333
|
|
|
10
334
|
**Message receipts** - Observe delivery/read/played status of messages you send.
|
|
@@ -328,6 +652,49 @@ unchanged.
|
|
|
328
652
|
|
|
329
653
|
---
|
|
330
654
|
|
|
655
|
+
## [1.3.0] - 2026-03-13
|
|
656
|
+
|
|
657
|
+
**Proxy support** - route a WhatsApp connection through a proxy, per instance.
|
|
658
|
+
|
|
659
|
+
_Backfilled: this release shipped in commit `8def495` but was never recorded here._
|
|
660
|
+
|
|
661
|
+
### Added
|
|
662
|
+
|
|
663
|
+
- `proxy` option on `MiawClientOptions`, accepting a URL string or a `ProxyConfig`
|
|
664
|
+
object (`{ url, username?, password? }`). Supports HTTP, HTTPS, SOCKS4, and SOCKS5.
|
|
665
|
+
- `createProxyAgents()` and `validateProxyConfig()` in `src/utils/proxy-agent.ts`.
|
|
666
|
+
Dual-agent approach: `https-proxy-agent` / `socks-proxy-agent` for the WebSocket
|
|
667
|
+
transport, `undici`'s `ProxyAgent` for media upload/download.
|
|
668
|
+
- `agent` and `fetchAgent` escape-hatch options for supplying custom transports.
|
|
669
|
+
- `MiawClient.getProxyInfo()` for inspecting the active proxy.
|
|
670
|
+
- `--proxy <url>` CLI flag.
|
|
671
|
+
|
|
672
|
+
### Notes
|
|
673
|
+
|
|
674
|
+
- SOCKS proxies tunnel the WebSocket but not media transfers: Node's `fetch()` needs an
|
|
675
|
+
undici dispatcher and undici has no SOCKS transport, so media falls back to a direct
|
|
676
|
+
connection.
|
|
677
|
+
|
|
678
|
+
## [1.2.0] - 2026-01-20
|
|
679
|
+
|
|
680
|
+
**Code quality release** - configurable timeouts, validation utilities, and type safety.
|
|
681
|
+
|
|
682
|
+
_Backfilled: this release shipped in commit `2e922d2` but was never recorded here._
|
|
683
|
+
|
|
684
|
+
### Added
|
|
685
|
+
|
|
686
|
+
- Configurable timeouts and exported `TIMEOUTS` / `THRESHOLDS` constants.
|
|
687
|
+
- Validation utilities and type-guard helpers (`isError`, `getErrorMessage`,
|
|
688
|
+
`isBaileysMessage`, `isBaileysMessageUpsert`).
|
|
689
|
+
- Custom logger support.
|
|
690
|
+
- CLI: `send video`, `send audio`, `media download`; topic-specific help sub-commands
|
|
691
|
+
and expanded autocomplete.
|
|
692
|
+
|
|
693
|
+
### Changed
|
|
694
|
+
|
|
695
|
+
- Type-safety improvements throughout; 14 of 15 issues from the code review report
|
|
696
|
+
resolved. No breaking changes.
|
|
697
|
+
|
|
331
698
|
## [1.1.0] - 2026-01-02
|
|
332
699
|
|
|
333
700
|
**Baileys v7 Migration** - ESM-only release with improved session stability
|