Added
GET /sessions/{sessionId}/chatsreportsmuteExpiration, the epoch-ms instant a mute ends
(0= indefinite), alongsidemuted(#1473).
Thanks @usmancynosure and @purnamcommunity.- The dashboard Message Tester loads bulk recipients from a
.txtor.csvfile, one entry per line,
appended to the Recipients box. Thanks @harry0x. GET /sessions/{sessionId}/messagesacceptsinlineMedia=false, omitting inline media payloads
while keeping each row's{ omitted, sizeBytes }marker and the media endpoint
(#1516).GET /sessions/{sessionId}/messagesacceptsafter, a keyset cursor on the previous page's last
id, so a message arriving mid-walk cannot repeat or skip a page;offsetis 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.allowedSessionswas already in the REST API.
Thanks @sebathi. PUPPETEER_PROTOCOL_TIMEOUT_MSraises the per-browser-command budget on whatsapp-web.js for large
accounts hittingRuntime.callFunctionOn timed out; unset keeps Puppeteer's default. See docs/12.
Thanks @JuanGalzerano.GETandPATCH /api/sessions/{sessionId}/proxyread 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 theisGroupboolean could not
(#1500). GET /sessions/{sessionId}/chatsand.../labels/{labelId}/chatsreport each chat'sarchived,
pinnedandmutedstate; the archive/pin/mute actions existed but the list never reported the
result back.
Changed
ChatSummarygained three required fields (archived,pinned,muted). Every producer and the
SDK types set them, but a hand-builtChatSummaryfixture, 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}/contactsdeclares and answers503when the whatsapp-web.js page dies
mid-read, instead of a bare500. 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,archivedandpinnedstate 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
andGET /search.offsetstill shifts under concurrent writes. PUT /sessions/{sessionId}/groups/{groupId}/descriptionno longer answers a bare500on
whatsapp-web.js. A new install-time patch (๐งโน, docs/29) callssetGroupDescriptionwith the
options object the library now expects; an empty description still clears. Thanks @purnamcommunity.- whatsapp-web.js contact reads resolve the renamed
$1serialized-id field, so contacts keep their
idon a WhatsApp Web build that renamed it; an unreadable entry is skipped and logged.
Thanks @Deyvis17GY. - Inbound media whose download fails keeps the
mediaenvelope withomitted: trueand the declared
size on both engines, instead of dropping the field. - Webhook filters and automation rules gated on
hasMedianow match those omitted-media messages. - Baileys logs a failed inbound media download at
warn, notdebug, so it is visible by default. - The webhook
secretexample in Swagger and the API reference now meets the 16-character floor, so
pasting it back no longer answers400; both webhook routes publish the length rule
(#1491). Thanks @onepay-ye. STORAGE_TYPE=s3missingS3_ACCESS_KEY_IDorS3_SECRET_ACCESS_KEYwarns 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 the503their routes document when the page dies, not a bare500
(#1476). Thanks @onepay-ye. - Fifteen more whatsapp-web.js operations answer
503not500when 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 keep500deliberately, since503is
replay-safe in the clients and would duplicate a message. - The seven routes that answer the media byte cap's
413now declare it: the five media sends,
send-bulkand the group picture.docs/06had called it400on two. Behaviour is unchanged.
Thanks @onepay-ye. .env.exampleno longer calls an oversized base64 send a400(it is413), and no longer implies
MINIO_BUILTIN=truefills 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 ofTarget closedtore the session down and answered503instead of404.
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:503is replayed for a POST and could publish twice.DELETEon a
status keeps503and now declares it. - An
allowedSessionsentry 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
deliveredack
arriving before the send's second save was pulled back tosent. GET /sessions/{sessionId}/messagestreats a blankafteras absent, like a blanklimitor
offset, instead of400; the400for 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,628123456789had 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;
50mbhad resolved to a 50-byte cap with nothing naming the cause. GET /api/infra/export-datastrips 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 the503it answers when the page dies,
distinct from the404for an absent contact.SessionProxyResponseDto.proxyTypeadmitsnull, so the ordinary "no proxy" response no longer
contradicts its own schema.check:auditandcheck:contract-shapesrun from a checkout path that needs URL escaping; both had
exited0having 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
sharpno 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
requestPairingCodeno 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
browserslist4.28.2 to 4.28.8 in both trees, closing two high-severity advisories. Dev-only and
transitive, so nothing that ships changes.fast-uri3.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/browsersto 3.x through an override, dropping the vulnerableextract-zipand
closingGHSA-jmr9-qjv8-65gv, while keeping Puppeteer 24 in place. The amd64 image installsunzip
for@puppeteer/browsers3's Chrome for Testing extraction. Thanks @raoulmusci.