miaw-core 1.12.0 → 1.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +135 -1
  2. package/README.md +2 -2
  3. package/bin/miaw-cli.mjs +31 -0
  4. package/dist/cli/commands/catalog.d.ts +0 -5
  5. package/dist/cli/commands/catalog.d.ts.map +1 -1
  6. package/dist/cli/commands/catalog.js +42 -0
  7. package/dist/cli/commands/catalog.js.map +1 -1
  8. package/dist/cli/commands/contact.d.ts.map +1 -1
  9. package/dist/cli/commands/contact.js +6 -2
  10. package/dist/cli/commands/contact.js.map +1 -1
  11. package/dist/cli/commands/get.d.ts.map +1 -1
  12. package/dist/cli/commands/get.js +12 -2
  13. package/dist/cli/commands/get.js.map +1 -1
  14. package/dist/cli/commands/group.d.ts.map +1 -1
  15. package/dist/cli/commands/group.js +9 -3
  16. package/dist/cli/commands/group.js.map +1 -1
  17. package/dist/cli/commands/index.d.ts.map +1 -1
  18. package/dist/cli/commands/index.js +12 -2
  19. package/dist/cli/commands/index.js.map +1 -1
  20. package/dist/cli/commands/instance.d.ts.map +1 -1
  21. package/dist/cli/commands/instance.js +16 -5
  22. package/dist/cli/commands/instance.js.map +1 -1
  23. package/dist/cli/commands/misc.d.ts.map +1 -1
  24. package/dist/cli/commands/misc.js +5 -1
  25. package/dist/cli/commands/misc.js.map +1 -1
  26. package/dist/cli/commands/proxy.d.ts +16 -0
  27. package/dist/cli/commands/proxy.d.ts.map +1 -1
  28. package/dist/cli/commands/proxy.js +77 -4
  29. package/dist/cli/commands/proxy.js.map +1 -1
  30. package/dist/cli/main.d.ts +22 -0
  31. package/dist/cli/main.d.ts.map +1 -0
  32. package/dist/cli/main.js +243 -0
  33. package/dist/cli/main.js.map +1 -0
  34. package/dist/client/MiawClient.d.ts +5 -0
  35. package/dist/client/MiawClient.d.ts.map +1 -1
  36. package/dist/client/MiawClient.js +34 -1
  37. package/dist/client/MiawClient.js.map +1 -1
  38. package/dist/utils/proxy-agent.d.ts.map +1 -1
  39. package/dist/utils/proxy-agent.js +23 -2
  40. package/dist/utils/proxy-agent.js.map +1 -1
  41. package/docs/CLI.md +33 -8
  42. package/docs/DEPLOYMENT_V1.12.0.md +9 -10
  43. package/docs/FOLLOW_UPS.md +49 -3
  44. package/docs/PROXY.md +5 -1
  45. package/eslint.config.js +12 -0
  46. package/package.json +3 -3
  47. package/proxies.txt +16 -0
  48. package/bin/miaw-cli.ts +0 -278
@@ -1 +1 @@
1
- {"version":3,"file":"proxy-agent.d.ts","sourceRoot":"","sources":["../../src/utils/proxy-agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAW;IAC1B,0EAA0E;IAC1E,OAAO,EAAE,KAAK,CAAC;IACf,sEAAsE;IACtE,UAAU,EAAE,KAAK,CAAC;IAClB;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAkCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,WAAW,GAAG,MAAM,GAC3B,OAAO,CAAC,WAAW,CAAC,CAmCtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,MAAM,CAkBjE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,OAAO,CAQzE"}
1
+ {"version":3,"file":"proxy-agent.d.ts","sourceRoot":"","sources":["../../src/utils/proxy-agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAW;IAC1B,0EAA0E;IAC1E,OAAO,EAAE,KAAK,CAAC;IACf,sEAAsE;IACtE,UAAU,EAAE,KAAK,CAAC;IAClB;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAkCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,WAAW,GAAG,MAAM,GAC3B,OAAO,CAAC,WAAW,CAAC,CAmCtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,MAAM,CA2BjE;AAoBD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,OAAO,CAQzE"}
@@ -99,13 +99,34 @@ export function maskProxyUrl(config) {
99
99
  }
100
100
  if (parsed.password) {
101
101
  parsed.password = "****";
102
+ return parsed.toString();
102
103
  }
103
- return parsed.toString();
104
+ // Parsed, but with nothing in userinfo - which does not mean there are no
105
+ // credentials, only that the URL is not shaped the way it reads.
106
+ // "user:pw@host:8080" with the scheme left off parses as the *scheme*
107
+ // "user:", stranding the password in the path where nothing masks it, so
108
+ // this used to return the secret verbatim. A scheme-less form is an easy
109
+ // mistake to make given that the TXT list format is itself scheme-less.
110
+ return redactUserinfo(parsed.toString());
104
111
  }
105
112
  catch {
106
- return raw;
113
+ // Not parseable at all, and it may still carry credentials.
114
+ return redactUserinfo(raw);
107
115
  }
108
116
  }
117
+ /**
118
+ * Last-resort credential redaction for a string `new URL()` could not make
119
+ * sense of.
120
+ *
121
+ * Replaces whatever sits in userinfo position - between an optional scheme
122
+ * and the "@" that ends it. A string with no "@" has no userinfo by URL
123
+ * syntax and is returned untouched: there is no password in it to hide, and
124
+ * mangling it would remove exactly the detail that explains why it was
125
+ * rejected.
126
+ */
127
+ function redactUserinfo(raw) {
128
+ return raw.replace(/^([a-z][a-z0-9+.-]*:\/{0,2})?([^/@]*?:)[^/@]*@/i, (_match, scheme = "", user = "") => `${scheme}${user}****@`);
129
+ }
109
130
  /**
110
131
  * Validates a proxy configuration.
111
132
  * Checks that the URL is parseable and uses a supported protocol.
@@ -1 +1 @@
1
- {"version":3,"file":"proxy-agent.js","sourceRoot":"","sources":["../../src/utils/proxy-agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"proxy-agent.js","sourceRoot":"","sources":["../../src/utils/proxy-agent.ts"],"names":[],"mappings":"AAgCA,8EAA8E;AAC9E,iFAAiF;AACjF,6EAA6E;AAC7E,MAAM,eAAe,GAAG;IACtB,QAAQ;IACR,SAAS;IACT,UAAU;IACV,SAAS;IACT,UAAU;CACX,CAAC;AACF,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC3C,MAAM,mBAAmB,GAAG,CAAC,GAAG,eAAe,EAAE,GAAG,cAAc,CAAC,CAAC;AAEpE;;;GAGG;AACH,SAAS,aAAa,CAAC,MAA4B;IACjD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,CAAC;IACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAA4B;IAE5B,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC;IAE5C,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CACb,+BAA+B,QAAQ,gBAAgB,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxF,CAAC;IACJ,CAAC;IAED,6EAA6E;IAC7E,IAAI,OAAc,CAAC;IACnB,IAAI,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;QAC9D,OAAO,GAAG,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;QAC9D,OAAO,GAAG,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,UAAU,GAAU,OAAO,CAAC;IAElC,8EAA8E;IAC9E,iEAAiE;IACjE,IAAI,kBAA2B,CAAC;IAChC,IAAI,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChE,kBAAkB,GAAG,IAAI,gBAAgB,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO;QACL,OAAO;QACP,UAAU;QACV,GAAG,CAAC,kBAAkB,KAAK,SAAS,IAAI,EAAE,kBAAkB,EAAE,CAAC;KAChE,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY,CAAC,MAA4B;IACvD,MAAM,GAAG,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;IAE7D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YAClD,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACpC,CAAC;QACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YAClD,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACpC,CAAC;QACD,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACpB,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC;YACzB,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC3B,CAAC;QAED,0EAA0E;QAC1E,iEAAiE;QACjE,sEAAsE;QACtE,yEAAyE;QACzE,yEAAyE;QACzE,wEAAwE;QACxE,OAAO,cAAc,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,4DAA4D;QAC5D,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,cAAc,CAAC,GAAW;IACjC,OAAO,GAAG,CAAC,OAAO,CAChB,iDAAiD,EACjD,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,MAAM,GAAG,IAAI,OAAO,CAC5D,CAAC;AACJ,CAAC;AAGD;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAA4B;IAC9D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QAC7D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,OAAO,mBAAmB,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
package/docs/CLI.md CHANGED
@@ -170,6 +170,10 @@ npx miaw-cli instance status
170
170
  npx miaw-cli instance status my-bot
171
171
  ```
172
172
 
173
+ Like `instance ls`, this accepts an instance that exists only as a proxy pin
174
+ and reports it as `[not created]` — pinning before `instance create` is the
175
+ supported workflow, so you can always ask what you just pinned.
176
+
173
177
  #### Create Instance
174
178
 
175
179
  ```bash
@@ -955,23 +959,44 @@ npx miaw-cli proxy test-all --proxy-file ./proxies.txt || exit 1
955
959
  **Output:**
956
960
 
957
961
  ```
958
- 🔍 Testing 4 proxies via https://web.whatsapp.com/ (5 at a time) ...
962
+ 🔍 Testing 3 proxies via https://web.whatsapp.com/ (5 at a time) ...
959
963
 
960
- ┌────────┬──────────────────────────────────┬──────────┬─────────┬──────────────────────┐
961
- │ Status │ Proxy │ Protocol │ Latency │ Detail │
962
- ├────────┼──────────────────────────────────┼──────────┼─────────┼──────────────────────┤
963
- │ OK │ http://eu1.example.com:8080 │ http │ 188ms │ HTTP 200 │
964
- │ OK │ socks5://us1.example.com:1080 │ socks5 │ 412ms │ HTTP 200 (dl direct) │
965
- │ FAIL │ http://dead.example.com:8080 │ http │ - │ ECONNREFUSED │
966
- └────────┴──────────────────────────────────┴──────────┴─────────┴──────────────────────┘
964
+ ┌─────────┬──────────────────────────────────┬───────────┬──────────┬──────────────────────────────┐
965
+ │ Status │ Proxy │ Protocol │ Latency │ Detail │
966
+ ├─────────┼──────────────────────────────────┼───────────┼──────────┼──────────────────────────────┤
967
+ │ OK │ eu1.example.com:8080 │ http │ 188ms │ HTTP 200 │
968
+ │ OK │ us1.example.com:1080 │ socks5 │ 412ms │ HTTP 200 (dl direct) │
969
+ │ FAIL │ dead.example.com:8080 │ http │ - │ ECONNREFUSED │
970
+ └─────────┴──────────────────────────────────┴───────────┴──────────┴──────────────────────────────┘
967
971
 
968
972
  ⚠️ 2/3 proxies reachable (median 300ms)
969
973
  ```
970
974
 
975
+ With `--ip`, an Exit IP column is added — the column is only rendered when you
976
+ ask for it, since each entry costs an extra request to the echo service:
977
+
978
+ ```bash
979
+ npx miaw-cli proxy test-all --proxy-file ./proxies.txt --ip
980
+ ```
981
+
982
+ ```
983
+ ┌─────────┬─────────────────────┬───────────┬──────────┬────────────────┬──────────┐
984
+ │ Status │ Proxy │ Protocol │ Latency │ Exit IP │ Detail │
985
+ ├─────────┼─────────────────────┼───────────┼──────────┼────────────────┼──────────┤
986
+ │ OK │ 198.51.100.23:5829 │ http │ 975ms │ 198.51.100.23 │ HTTP 200 │
987
+ │ OK │ 203.0.113.7:7809 │ http │ 1223ms │ 203.0.113.7 │ HTTP 200 │
988
+ └─────────┴─────────────────────┴───────────┴──────────┴────────────────┴──────────┘
989
+ ```
990
+
971
991
  **Notes:**
972
992
 
973
993
  - Results are sorted fastest-first with failures last.
974
994
  - Exits non-zero if **any** proxy fails.
995
+ - The Proxy column shows `host:port`, not the masked URL. Vendors issue one
996
+ long username across a whole pool, so the masked URLs are identical on every
997
+ row; `host:port` is the part that differs, and it carries no credentials.
998
+ An over-long endpoint keeps its **tail** (`…pool.example.com:19001`) because
999
+ a per-session port is often the only thing distinguishing two entries.
975
1000
 
976
1001
  ### Contact Operations
977
1002
 
@@ -1,4 +1,4 @@
1
- # Deploying v1.12.0 (Baileys rc14)
1
+ # Deploying v1.12.x (Baileys rc14)
2
2
 
3
3
  **Audience:** whoever operates miaw-core deployments.
4
4
 
@@ -73,9 +73,9 @@ npm ls @whiskeysockets/baileys
73
73
 
74
74
  ## 3. Not on the npm registry
75
75
 
76
- At time of writing, the newest miaw-core on npm is **1.10.0**. Both 1.11.0 and
77
- 1.12.0 exist only in git and are **not published**, and the repository carries
78
- no version tags.
76
+ At time of writing, the newest miaw-core on npm is **1.10.0**. Everything since
77
+ — 1.11.0, 1.12.0 and 1.12.1 — exists only in git and is **not published**, and
78
+ the repository carries no version tags.
79
79
 
80
80
  This matters if you deploy from the registry: `npm install miaw-core` will give
81
81
  you 1.10.0 and none of this. Deploy from git (or publish first). Consumers
@@ -148,11 +148,10 @@ rollback — that is the only thing to check before reverting.
148
148
 
149
149
  Stated plainly so it is not discovered later:
150
150
 
151
- - The full CLI integration suite was last run **without a live WhatsApp
152
- session**, so it confirms test counts, not live behaviour. Fifteen known
153
- pre-existing failures are catalogued in [FOLLOW_UPS.md](./FOLLOW_UPS.md) §9;
154
- they were proven pre-existing by re-running against rc13 and getting a
155
- byte-identical failure set.
151
+ - The full CLI integration suite **has now been run against a live session**
152
+ (2026-09-02): 13/13 suites, 276 passed, 2 skipped, **0 failed**. The fifteen
153
+ failures previously catalogued in [FOLLOW_UPS.md](./FOLLOW_UPS.md) §9 were
154
+ all fixed in v1.12.1.
156
155
  - View-once **receipt** under the Android identity is unverified — see §4.
157
156
  - Live verification needs a QR pairing. `npm run test:cli` reports all-green
158
157
  when disconnected because connection-dependent tests return early; trust the
@@ -160,4 +159,4 @@ Stated plainly so it is not discovered later:
160
159
 
161
160
  ---
162
161
 
163
- _Last updated: 2026-09-02 (miaw-core v1.12.0, Baileys 7.0.0-rc14)._
162
+ _Last updated: 2026-09-02 (miaw-core v1.12.1, Baileys 7.0.0-rc14)._
@@ -214,9 +214,24 @@ output. Worth a sweep for consistency rather than one-off additions.
214
214
 
215
215
  ---
216
216
 
217
- ## 9. Fifteen pre-existing CLI integration failures, surfaced by the first live run
218
-
219
- **Severity:** medium (they are real defects; none is new).
217
+ ## 9. Fifteen pre-existing CLI integration failures, surfaced by the first live run — RESOLVED
218
+
219
+ **Severity:** medium (they were real defects; none was new).
220
+
221
+ > **Closed 2026-09-02 (v1.12.1).** All fifteen are fixed. A live run now
222
+ > reports **13/13 suites, 276 passed, 2 skipped, 0 failed**, and the suite time
223
+ > fell from 745s to 189s because the catalog commands no longer wait out a 60s
224
+ > query timeout. See CHANGELOG v1.12.1. The analysis below is kept because it
225
+ > explains *why* each one happened, and three of the four causes are patterns
226
+ > worth not repeating:
227
+ >
228
+ > - `--json` was broken on seven commands and nobody noticed, because the
229
+ > corruption is invisible unless you pipe the output to a parser.
230
+ > - `label list --json` was never broken at all — its failure was console
231
+ > output from the timing-out catalog tests bleeding into an active capture.
232
+ > Two of the fifteen were one bug wearing two hats.
233
+ > - The `load messages` tests asserted `true` unconditionally, so they could
234
+ > not tell "no history" from "broken".
220
235
 
221
236
  Until 2026-09-02 no session on disk authenticated, so every connection-dependent
222
237
  CLI test short-circuited via `if (!isConnected()) return;` and reported as
@@ -318,3 +333,34 @@ socket that can reject; the second needs the dispatch to be exercised. Adding
318
333
  mock-backed unit tests for the clusters above would raise the number without
319
334
  catching that class of bug. Prefer the CLI integration and manual suites for
320
335
  anything whose failure mode is "the real socket says no".
336
+
337
+ ---
338
+
339
+ ## 11. The test account's `.env.test` invalidates ~5 manual-runner results
340
+
341
+ **Severity:** low (environment, not code — but it makes every run read as
342
+ partly broken).
343
+
344
+ `TEST_CONTACT_PHONE_A` and `TEST_CONTACT_PHONE_B` are both set to the test
345
+ bot's **own** number. `warnOnDegenerateConfig()` detects this and says so on
346
+ connect, and the live run on 2026-09-02 confirmed exactly the failures it
347
+ predicts:
348
+
349
+ | Entry | Why it fails |
350
+ |---|---|
351
+ | `checkNumbers()` | WhatsApp deduplicates a batch check of one repeated number |
352
+ | `addParticipants()` | cannot add yourself to a group you are already in |
353
+ | `promoteToAdmin()` / `demoteFromAdmin()` | same participant problem |
354
+ | `blockContact()` | WhatsApp refuses a self-block (`forbidden`) |
355
+
356
+ Fix by pointing `TEST_CONTACT_PHONE_B` at a second real number. Until then,
357
+ read those five as environment noise rather than defects.
358
+
359
+ Separately, the account belongs to **no community**, so the community entries
360
+ have no valid JID. `getCommunityInfo()` now reports **skipped** rather than
361
+ failed in that case (it used to hard-fail), but the community admin path stays
362
+ genuinely unexercised live until a community exists. The unit suite covers it;
363
+ `tests/unit/group-community-admin.test.ts` includes the group/community
364
+ cross-wire assertions.
365
+
366
+ _Recorded 2026-09-02 after the first fully-live run of v1.12.0._
package/docs/PROXY.md CHANGED
@@ -321,7 +321,11 @@ Random, biased by each entry's `weight` (default `1`). **A weight of `0` drains
321
321
 
322
322
  WhatsApp treats a session's source IP as part of its trust signal. If `bot-3` connects from Frankfurt on Monday and São Paulo on Tuesday, you have manufactured an account-takeover signature against your own account. The observable results are re-pairing prompts, 401/440 disconnect loops, and eventually a ban.
323
323
 
324
- `deterministic` hashes the `instanceId` to a stable entry, so a given session keeps a stable egress IP for its lifetime while N instances still spread across N proxies.
324
+ `deterministic` hashes the `instanceId` to a stable entry, so a given session keeps a stable egress IP for its lifetime while instances still spread across the pool.
325
+
326
+ > **It spreads, it does not deal.** Hashing is stateless, so two instances can land on the same proxy — with 10 instances over a 10-proxy pool, expect roughly 6-7 distinct egress IPs, not 10. That is inherent: a rotator that guaranteed one proxy per instance would need to know about every other instance, and would then have to remap live sessions whenever the set changed, which is the churn this strategy exists to avoid.
327
+ >
328
+ > If you need a guaranteed 1:1 mapping — and [IP separation for multi-instance](#ip-separation-for-multi-instance) is a reason you might — assign it explicitly rather than by hashing: pin each instance with [`instance set-proxy`](#pinning-a-proxy-to-an-instance-cli), or build the assignment map yourself. Size the pool above the instance count either way.
325
329
 
326
330
  > **Rotation is for distributing instances across proxies. It is never for rotating a live session's IP.**
327
331
 
package/eslint.config.js CHANGED
@@ -7,6 +7,18 @@ export default tseslint.config(
7
7
  {
8
8
  ignores: ["dist/**", "node_modules/**", "coverage/**", "*.js"],
9
9
  },
10
+ {
11
+ // The published CLI executable is plain ESM JavaScript, not TypeScript,
12
+ // so it is not covered by the TS block below and needs Node's globals
13
+ // declared explicitly.
14
+ files: ["bin/**/*.mjs"],
15
+ languageOptions: {
16
+ globals: { console: "readonly", process: "readonly" },
17
+ },
18
+ rules: {
19
+ "no-console": "off",
20
+ },
21
+ },
10
22
  {
11
23
  files: ["src/**/*.ts", "tests/**/*.ts", "examples/**/*.ts", "bin/**/*.ts"],
12
24
  rules: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miaw-core",
3
- "version": "1.12.0",
3
+ "version": "1.12.2",
4
4
  "description": "Simplified WhatsApp API wrapper for Baileys - Multiple Instance of Awesome WhatsApp",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -13,7 +13,7 @@
13
13
  }
14
14
  },
15
15
  "bin": {
16
- "miaw-cli": "./bin/miaw-cli.ts"
16
+ "miaw-cli": "./bin/miaw-cli.mjs"
17
17
  },
18
18
  "keywords": [
19
19
  "whatsapp",
@@ -32,6 +32,7 @@
32
32
  "@hapi/boom": "^10.0.1",
33
33
  "@whiskeysockets/baileys": "7.0.0-rc14",
34
34
  "cli-table3": "^0.6.5",
35
+ "dotenv": "^16.4.5",
35
36
  "https-proxy-agent": "^8.0.0",
36
37
  "pino": "^8.19.0",
37
38
  "qrcode-terminal": "^0.12.0",
@@ -48,7 +49,6 @@
48
49
  "@typescript-eslint/eslint-plugin": "^8.51.0",
49
50
  "@typescript-eslint/parser": "^8.51.0",
50
51
  "babel-jest": "^30.2.0",
51
- "dotenv": "^16.4.5",
52
52
  "eslint": "^9.39.2",
53
53
  "jest": "^29.7.0",
54
54
  "ts-jest": "^29.1.2",
package/proxies.txt ADDED
@@ -0,0 +1,16 @@
1
+ # Webshare proxy pool - LIVE CREDENTIALS. Ignored via /proxies.txt in .gitignore.
2
+ # Saved 2026-09-03. Vendor: webshare.io (plan 13791773), 10 static residential HTTP.
3
+ # Refresh: curl -o proxies.txt "<webshare download url>" (the url itself is a secret)
4
+ # Use: npx miaw-cli proxy test-all --proxy-file ./proxies.txt --ip
5
+ # or set MIAW_PROXY_FILE=./proxies.txt
6
+
7
+ 209.166.23.193:5354:mbmkuoqxstaticresidential:i9h6jrarzm6e
8
+ 82.23.91.50:7809:mbmkuoqxstaticresidential:i9h6jrarzm6e
9
+ 138.226.65.190:7381:mbmkuoqxstaticresidential:i9h6jrarzm6e
10
+ 130.180.228.105:6389:mbmkuoqxstaticresidential:i9h6jrarzm6e
11
+ 72.1.136.247:7138:mbmkuoqxstaticresidential:i9h6jrarzm6e
12
+ 9.142.198.183:5850:mbmkuoqxstaticresidential:i9h6jrarzm6e
13
+ 179.198.17.248:6367:mbmkuoqxstaticresidential:i9h6jrarzm6e
14
+ 31.98.14.152:5829:mbmkuoqxstaticresidential:i9h6jrarzm6e
15
+ 147.79.22.195:7911:mbmkuoqxstaticresidential:i9h6jrarzm6e
16
+ 103.243.147.25:6004:mbmkuoqxstaticresidential:i9h6jrarzm6e
package/bin/miaw-cli.ts DELETED
@@ -1,278 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * miaw-cli - WhatsApp Command-Line Interface
4
- *
5
- * Usage:
6
- * miaw-cli # Start interactive REPL
7
- * miaw-cli <command> [args] # Run one-shot command
8
- *
9
- * Examples:
10
- * miaw-cli get groups
11
- * miaw-cli send text 6281234567890 "Hello"
12
- * miaw-cli instance status
13
- */
14
-
15
- import * as dotenv from "dotenv";
16
- import { runRepl } from "../src/cli/repl.js";
17
- import { runCommand } from "../src/cli/commands/index.js";
18
- import { initializeCLICleanup } from "../src/cli/utils/cleanup.js";
19
- import { getErrorMessage } from "../src/utils/type-guards.js";
20
- import {
21
- configFromResolved,
22
- describeProxySource,
23
- resolveProxyForInstance,
24
- type ProxyResolutionBase,
25
- } from "../src/cli/utils/proxy-resolver.js";
26
- import { maskProxyUrl } from "../src/utils/proxy-agent.js";
27
- import {
28
- parseProxyStrategy,
29
- } from "../src/cli/utils/proxy-config.js";
30
-
31
- // Initialize CLI cleanup handlers for graceful shutdown
32
- initializeCLICleanup();
33
-
34
- // Load environment variables
35
- dotenv.config();
36
- dotenv.config({ path: ".env.test" });
37
-
38
- // Default configuration
39
- const DEFAULT_INSTANCE_ID = process.env.MIAW_INSTANCE_ID || "default";
40
- const DEFAULT_SESSION_PATH = process.env.MIAW_SESSION_PATH || "./sessions-cli";
41
- // Proxy credentials belong in .env, not in shell history.
42
- const DEFAULT_PROXY = process.env.MIAW_PROXY || undefined;
43
- const DEFAULT_PROXY_FILE = process.env.MIAW_PROXY_FILE || undefined;
44
- const DEFAULT_PROXY_STRATEGY_ENV = process.env.MIAW_PROXY_STRATEGY || undefined;
45
-
46
- /**
47
- * Global flags that never take a value. Listed explicitly because the parser is
48
- * positional: without this an `--ip`-style flag consumes the command name.
49
- */
50
- const BOOLEAN_FLAGS = new Set(["json", "debug", "help", "version", "ip", "from-file", "force"]);
51
-
52
- /**
53
- * Parse CLI arguments
54
- */
55
- function parseArgs(args: string[]): {
56
- command: string;
57
- args: string[];
58
- flags: { [key: string]: string | boolean };
59
- } {
60
- const flags: { [key: string]: string | boolean } = {};
61
- const commandArgs: string[] = [];
62
-
63
- for (let i = 0; i < args.length; i++) {
64
- const arg = args[i];
65
- if (arg.startsWith("--")) {
66
- const flagName = arg.slice(2);
67
- // Value-less flags must never swallow the next token. `--json instance ls`
68
- // otherwise parsed as json="instance", leaving the command empty and
69
- // reporting "Unknown command: ls" - even though --json is documented as a
70
- // global option, i.e. valid before the command.
71
- if (BOOLEAN_FLAGS.has(flagName)) {
72
- flags[flagName] = true;
73
- continue;
74
- }
75
- const nextArg = args[i + 1];
76
- if (nextArg && !nextArg.startsWith("--")) {
77
- flags[flagName] = nextArg;
78
- i++;
79
- } else {
80
- flags[flagName] = true;
81
- }
82
- } else {
83
- commandArgs.push(arg);
84
- }
85
- }
86
-
87
- const command = commandArgs[0] || "";
88
- const remainingArgs = commandArgs.slice(1);
89
-
90
- return { command, args: remainingArgs, flags };
91
- }
92
-
93
- /**
94
- * Show help message
95
- */
96
- function showHelp() {
97
- console.log(`
98
- ╔════════════════════════════════════════════════════════════════════════╗
99
- ║ miaw-cli - WhatsApp CLI Tool ║
100
- ╚════════════════════════════════════════════════════════════════════════╝
101
-
102
- USAGE:
103
- miaw-cli Start interactive REPL mode
104
- miaw-cli <command> [args] Run one-shot command
105
-
106
- GLOBAL FLAGS:
107
- --instance-id <id> Instance ID (default: "default")
108
- --session-path <path> Session directory
109
- --proxy <url> Proxy URL (http/https/socks4/socks4a/socks5/socks5h)
110
- --proxy-file <path> Proxy list file (.txt one-per-line, or .json array)
111
- --proxy-strategy <strategy> Pick from --proxy-file: round-robin | random |
112
- weighted | deterministic (default: deterministic)
113
- --json Output as JSON
114
- --debug Enable verbose logging
115
-
116
- COMMANDS:
117
- instance Manage instances (ls, status, create, delete, connect, disconnect,
118
- logout, set-proxy, unset-proxy)
119
- get Fetch data (profile, contacts, groups, chats, messages, labels)
120
- load Load older messages from history
121
- send Send messages (text, image, document)
122
- group Group management (list, info, participants, invite, settings)
123
- check Check if phone numbers are on WhatsApp
124
- contact Contact management (list, info, business, picture, add, remove)
125
- profile Profile management (picture, name, status)
126
- label Label management - WhatsApp Business (list, chats, add, chat)
127
- catalog Catalog management - WhatsApp Business (list, collections, product)
128
- proxy Inspect and test proxies (list, test, test-all) - no connection needed
129
-
130
- COMMON OPTIONS:
131
- --limit N Limit number of results
132
- --filter TEXT Filter by name/phone (case-insensitive)
133
-
134
- EXAMPLES:
135
- miaw-cli get contacts --limit 10 --filter john
136
- miaw-cli send text 6281234567890 "Hello"
137
- miaw-cli group participants add 120363xxx@g.us 628xxx
138
- miaw-cli contact add 6281234567890 "John Doe"
139
- miaw-cli proxy test socks5://proxy.example.com:1080
140
- miaw-cli --instance-id bot-3 --proxy-file ./proxies.txt get groups
141
- miaw-cli instance set-proxy bot-3 --label eu Pin a proxy, no credentials stored
142
- miaw-cli --instance-id bot-3 get groups Uses bot-3's pinned proxy, no flags
143
-
144
- PROXY PRECEDENCE (highest first):
145
- --proxy / MIAW_PROXY > pinned in <session-path>/instances.json
146
- > --proxy-file > direct
147
- A pin applies on the instance's NEXT connect. Never change a live session's
148
- egress IP - WhatsApp reads that as account takeover.
149
-
150
- REPL MODE:
151
- Run 'miaw-cli' without arguments to start interactive mode.
152
- In REPL, use 'help <command>' for detailed help on each command.
153
-
154
- For detailed documentation: https://github.com/biji-dev/miaw-core/blob/main/docs/CLI.md
155
- `);
156
- }
157
-
158
- /**
159
- * Main entry point
160
- */
161
- async function main() {
162
- const args = process.argv.slice(2);
163
-
164
- // Show help if requested
165
- if (args.includes("--help") || args.includes("-h")) {
166
- showHelp();
167
- process.exit(0);
168
- }
169
-
170
- const { command, args: commandArgs, flags } = parseArgs(args);
171
-
172
- // Extract global flags
173
- const instanceId = (flags["instance-id"] as string) || DEFAULT_INSTANCE_ID;
174
- const sessionPath = (flags["session-path"] as string) || DEFAULT_SESSION_PATH;
175
- const jsonOutput = flags.json === true;
176
- const debugMode = flags.debug === true;
177
-
178
- // Extract proxy flags (CLI flag wins over the MIAW_PROXY* env fallbacks)
179
- const explicitProxy = (flags.proxy as string | undefined) || DEFAULT_PROXY;
180
- const proxyFile = (flags["proxy-file"] as string | undefined) || DEFAULT_PROXY_FILE;
181
-
182
- let proxyStrategy;
183
- try {
184
- proxyStrategy = parseProxyStrategy(
185
- (flags["proxy-strategy"] as string | undefined) || DEFAULT_PROXY_STRATEGY_ENV
186
- );
187
- } catch (error: unknown) {
188
- console.error(`❌ ${getErrorMessage(error)}`);
189
- process.exit(1);
190
- }
191
-
192
- // Precedence lives in one place - see src/cli/utils/proxy-resolver.ts:
193
- // --proxy > pin in instances.json > --proxy-file > direct
194
- // Selection is keyed on this instanceId, and commands targeting a *different*
195
- // instance re-resolve rather than reusing what the process started with.
196
- const proxyBase: ProxyResolutionBase = {
197
- sessionPath,
198
- debug: debugMode,
199
- ...(explicitProxy && { explicitProxy }),
200
- ...(proxyFile && { proxyFile }),
201
- proxyStrategy,
202
- };
203
-
204
- // A failure here is reported but does NOT exit. A bad pin would otherwise
205
- // lock the operator out of `instance unset-proxy` and `instance ls` - the
206
- // commands that repair it. The config instead carries `proxyError`, and
207
- // createClient() refuses to build a client, so nothing connects direct.
208
- let clientConfig;
209
- let resolvedProxy;
210
- try {
211
- // Resolve once, then build the config from that result: resolving twice
212
- // would print every override warning twice.
213
- resolvedProxy = await resolveProxyForInstance(proxyBase, instanceId);
214
- clientConfig = configFromResolved(proxyBase, instanceId, resolvedProxy);
215
- } catch (error: unknown) {
216
- const reason = getErrorMessage(error);
217
- console.error(`❌ ${reason}`);
218
- console.error(
219
- ` Commands needing a connection will refuse until this is fixed; ` +
220
- `"instance unset-proxy ${instanceId}" removes the pin.`
221
- );
222
- resolvedProxy = { source: "none" as const };
223
- clientConfig = {
224
- ...configFromResolved(proxyBase, instanceId, resolvedProxy),
225
- proxyError: reason,
226
- };
227
- }
228
-
229
- const proxyUrl = clientConfig.proxy;
230
-
231
- // No command provided - start REPL
232
- if (!command) {
233
- console.log(`\n🚀 Starting miaw-cli REPL...`);
234
- console.log(`📂 Instance: ${instanceId}`);
235
- console.log(`📂 Session: ${sessionPath}`);
236
- if (proxyUrl) {
237
- console.log(
238
- `🌐 Proxy: ${maskProxyUrl(proxyUrl)} (${describeProxySource(resolvedProxy.source)})`
239
- );
240
- }
241
- console.log(`🔧 Debug: ${debugMode ? "ON" : "OFF"}\n`);
242
-
243
- try {
244
- await runRepl(clientConfig);
245
- } catch (error: unknown) {
246
- console.error("❌ REPL error:", getErrorMessage(error));
247
- process.exit(1);
248
- }
249
- return;
250
- }
251
-
252
- // Run one-shot command
253
- try {
254
- const success = await runCommand(command, commandArgs, {
255
- clientConfig,
256
- jsonOutput,
257
- flags,
258
- ...(proxyFile && { proxyFile }),
259
- proxyStrategy,
260
- });
261
-
262
- if (!success) {
263
- process.exit(1);
264
- }
265
- } catch (error: unknown) {
266
- console.error("❌ Command error:", getErrorMessage(error));
267
- if (debugMode && error instanceof Error) {
268
- console.error(error.stack);
269
- }
270
- process.exit(1);
271
- }
272
- }
273
-
274
- // Run the CLI
275
- main().catch((error) => {
276
- console.error("Fatal error:", error);
277
- process.exit(1);
278
- });