You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Added
GET /sessions/{sessionId}/chats reports muteExpiration, the epoch-ms instant a mute ends
(0 = indefinite), alongside muted (#1473).
Thanks @usmancynosure and @purnamcommunity.
The dashboard Message Tester loads bulk recipients from a .txt or .csv file, one entry per line,
appended to the Recipients box. Thanks @harry0x.
GET /sessions/{sessionId}/messages accepts inlineMedia=false, omitting inline media payloads
while keeping each row's { omitted, sizeBytes } marker and the media endpoint
(#1516).
GET /sessions/{sessionId}/messages accepts after, a keyset cursor on the previous page's last id, so a message arriving mid-walk cannot repeat or skip a page; offset is unchanged
(#1479).
Each engine names the install-time patches its library is missing at startup, not only the
message-id backport. Diagnostic only; startup continues. See docs/12.
The dashboard API Keys page can scope an operator or viewer key to chosen sessions, on creation and
after; an empty picker keeps access to every session. allowedSessions was already in the REST API.
Thanks @sebathi.
PUPPETEER_PROTOCOL_TIMEOUT_MS raises the per-browser-command budget on whatsapp-web.js for large
accounts hitting Runtime.callFunctionOn timed out; unset keeps Puppeteer's default. See docs/12.
Thanks @JuanGalzerano.
GET and PATCH /api/sessions/{sessionId}/proxy read and update a session's egress proxy;
credentials are never returned and changes apply on the next start
(#1474). Thanks @vitusan.
Sessions dashboard: set a proxy when creating a session, and view, change or clear it afterwards.
Thanks @vitusan.
The dashboard chat room loads older history as you scroll up, paged by DB rows already fetched and
holding the reading position when a page is prepended. Thanks @JuanGalzerano.
Webhook filters and automation rules can match on chat kind (individual, group, channel, status, broadcast, unknown), separating channel traffic the isGroup boolean could not
(#1500).
GET /sessions/{sessionId}/chats and .../labels/{labelId}/chats report each chat's archived, pinned and muted state; the archive/pin/mute actions existed but the list never reported the
result back.
Changed
ChatSummary gained three required fields (archived, pinned, muted). Every producer and the
SDK types set them, but a hand-built ChatSummary fixture, mock or stub must supply the three.
A whatsapp-web.js protocol timeout is no longer classified as a dead page. Behaviour is unchanged on
the current Puppeteer; the guard pins the intent against a future bump.
GET /sessions/{sessionId}/contacts declares and answers 503 when the whatsapp-web.js page dies
mid-read, instead of a bare 500. Thanks @Deyvis17GY.
All five clients document the 16-character minimum on a webhook secret, and that an empty string
clears it on update. The constraint is unchanged; until now only the gateway named it.
Fixed
Baileys chat muted, archived and pinned state now survives a reconnect or process restart.
WhatsApp does not re-deliver it, so it is persisted per chat and rehydrated on boot.
Paged lists tiebreak on id, so a walk returns every row once. On PostgreSQL a non-unique sort key
could repeat and drop rows across pages, on the message, session, webhook and delivery-failure lists
and GET /search. offset still shifts under concurrent writes.
PUT /sessions/{sessionId}/groups/{groupId}/description no longer answers a bare 500 on
whatsapp-web.js. A new install-time patch (🔧⁹, docs/29) calls setGroupDescription with the
options object the library now expects; an empty description still clears. Thanks @purnamcommunity.
whatsapp-web.js contact reads resolve the renamed $1 serialized-id field, so contacts keep their id on a WhatsApp Web build that renamed it; an unreadable entry is skipped and logged.
Thanks @Deyvis17GY.
Inbound media whose download fails keeps the media envelope with omitted: true and the declared
size on both engines, instead of dropping the field.
Webhook filters and automation rules gated on hasMedia now match those omitted-media messages.
Baileys logs a failed inbound media download at warn, not debug, so it is visible by default.
The webhook secret example in Swagger and the API reference now meets the 16-character floor, so
pasting it back no longer answers 400; both webhook routes publish the length rule
(#1491). Thanks @onepay-ye.
STORAGE_TYPE=s3 missing S3_ACCESS_KEY_ID or S3_SECRET_ACCESS_KEY warns at startup and names
the unset one, instead of silently writing every file to local disk. Thanks @onepay-ye.
Six whatsapp-web.js contact operations (blocked list, number lookup, addressbook save and delete,
block, unblock) answer the 503 their routes document when the page dies, not a bare 500
(#1476). Thanks @onepay-ye.
Fifteen more whatsapp-web.js operations answer 503 not 500 when the page dies mid-request: the
group list and membership queue, four label reads and writes, and nine message operations. Twelve
had no error handling on that path. The message sends keep 500 deliberately, since 503 is
replay-safe in the clients and would duplicate a message.
The seven routes that answer the media byte cap's 413 now declare it: the five media sends, send-bulk and the group picture. docs/06 had called it 400 on two. Behaviour is unchanged.
Thanks @onepay-ye.
.env.example no longer calls an oversized base64 send a 400 (it is 413), and no longer implies MINIO_BUILTIN=true fills the S3 credentials. Thanks @onepay-ye.
A caller-supplied message id can no longer be read as a dead browser page. The whatsapp-web.js
transport classifier matched its pattern against the gateway's own not-found errors, so a request
naming a message id of Target closed tore the session down and answered 503 instead of 404.
Gateway-constructed errors are now excluded.
The four whatsapp-web.js status posts, the channel create and the call-link create answer 500, not 503, when the page dies: 503 is replayed for a POST and could publish twice. DELETE on a
status keeps 503 and now declares it.
An allowedSessions entry that is empty, whitespace-padded, comma-bearing or duplicated is refused.
The column stores a comma join, so [""] read back as "every session", and a key meant to be scoped
could reach everything.
Messages sharing one second come back in arrival order on SQLite, the default database. The
tiebreaker was a random uuid, so a burst, bulk send or backfill rendered shuffled; it is now the
stored insertion sequence. PostgreSQL keeps the uuid order.
A send reconciling against its own echo no longer overwrites the delivery state. A delivered ack
arriving before the send's second save was pulled back to sent.
GET /sessions/{sessionId}/messages treats a blank after as absent, like a blank limit or offset, instead of 400; the 400 for a cursor naming no row is deliberate and now declared.
The dashboard holds a reader's position when an image finishes decoding above them. The correction
measured its baseline after the decode was already in layout, so it never ran.
The bulk-recipients upload reads a CSV column as one recipient; a row like 1,628123456789 had its
columns concatenated into a different, plausible-looking number.
The four media knobs (MEDIA_DOWNLOAD_MAX_BYTES, MEDIA_DOWNLOAD_TIMEOUT_MS, INBOUND_MEDIA_CONCURRENCY, CHAT_HISTORY_MEDIA_BUDGET_BYTES) refuse a unit-suffixed value at boot; 50mb had resolved to a 50-byte cap with nothing naming the cause.
GET /api/infra/export-data strips the userinfo from a session's proxy URL, as it already did for
webhook secrets; scheme and host survive so a restore cannot silently connect direct.
GET /sessions/{sessionId}/contacts/{contactId} declares the 503 it answers when the page dies,
distinct from the 404 for an absent contact.
SessionProxyResponseDto.proxyType admits null, so the ordinary "no proxy" response no longer
contradicts its own schema.
check:audit and check:contract-shapes run from a checkout path that needs URL escaping; both had
exited 0 having run nothing, so the jobs behind them reported a false pass. Thanks @JuanGalzerano.
docs/29 names the Baileys build the tree installs, and the counts spec binds both engine library
versions to the pins.
An unusable sharp no longer fails the gateway at boot. It backs one Baileys sticker route but was
imported at the top of a module both engines load, so a native binary that could not load took the
process down. It now loads lazily and only that route degrades
(#1459).
whatsapp-web.js requestPairingCode no longer hangs when it lands during a QR-page reload. The
in-page call ran against a destroyed context and hung until Puppeteer's protocol timeout; it is now
bounded per attempt and the navigation and timeout shapes are retried, so a code returns instead of
"Creating pairing code..." forever (#1543).
Thanks @emadhashem0.
Dependencies
browserslist 4.28.2 to 4.28.8 in both trees, closing two high-severity advisories. Dev-only and
transitive, so nothing that ships changes.
fast-uri 3.1.5 to 3.1.7 via an override, closing four high-severity advisories (two host-confusion,
two SSRF). It reaches the runtime tree through @modelcontextprotocol/sdk, so this one ships.
Force @puppeteer/browsers to 3.x through an override, dropping the vulnerable extract-zip and
closing GHSA-jmr9-qjv8-65gv, while keeping Puppeteer 24 in place. The amd64 image installs unzip
for @puppeteer/browsers 3's Chrome for Testing extraction. Thanks @raoulmusci.