Added
-
BAILEYS_MARK_ONLINE_ON_CONNECT=falsekeeps phone push notifications alive while a Baileys gateway is connected (defaulttrue, prior behavior). (#871) -
The catalog endpoints now work on the Baileys engine.
GET /catalog,GET /catalog/products,
GET /catalog/products/:idandPOST /messages/send-productwere501on both engines even
though Baileys has exposed the full catalog surface (getCatalog/getCollections) for a while —
the adapter simply never called it. The reads walk the library's cursor-based catalog in full and
slice page/limit in memory, sopagination.total/totalPagesare exact rather than estimated;
catalog metadata is synthesized from the first collection (a business without collections gets
null).sendProductresolves the product from the catalog and sends it as a native product
card — unknown ids come back404, products without an image400, since the card cannot render
without one.send-catalogstays501on both engines: neither library has a catalog-share
message type. whatsapp-web.js is unchanged (501throughout — it has no catalog API). (#905) -
Helm chart for Kubernetes deployments, under
charts/openwa/. A single-replica
StatefulSet with a PVC for/app/data(session auth, main DB, media, plugins), the
docker-compose hardening mirrored (read-only rootfs, dropped capabilities, writable
emptyDirat/tmp), free-formenv/secretEnvmaps covering every variable in
.env.example, and optional Ingress, PodDisruptionBudget and ServiceMonitor.
Datastores are not bundled — pointenvat your own or stay on the SQLite default.
Closes #695.
Fixed
-
A contact who hides their number no longer keeps a stale
lid -> phonemapping forever.
SessionLidResolveronly persisted positive resolutions, so once a@lidsender's phone became
unresolvable (e.g. username adoption) the stored mapping was never corrected — the messagefrom
filter and the reverse lookup kept attributing that lid to the old number, and API responses kept
returning a phone the user chose to hide. A definitivenullanswer from the engine now overwrites
the mapping; transient failures (no live engine, call rejected) still never touch it. (#1058) -
A key pasted with a stray space now authenticates on the WebSocket, not just over REST.
validateApiKeyhashed the raw string as given, and HTTP strips surrounding whitespace from header
values in transit — so a padded key was accepted on every REST call while the Socket.IO handshake,
which carries the literal string in itsCONNECTpayload, hashed to something else and was rejected.
The failure was silent in the worst way: the dashboard's commands all went through, but not a single
event arrived, so every session rendered as disconnected and restarting one looked inert — the
restart ran, the UI just never heard about it. The key is now trimmed once invalidateApiKey, which
REST, the WebSocket gateway and the MCP mount all route through, so every surface agrees on what the
credential is. Whitespace is never part of a key, so no legitimate credential changes meaning. -
Image builds no longer walk all of
node_modulesto chown it. The production stage ended with
chown -R openwa:openwa /app, which touched every installed dependency file — over half an hour on
a small VPS, the slowest step of the build — and duplicated their metadata into a new image layer.
It was redundant: runtime writes only happen under/app/dataand/tmp, the entrypoint re-chowns
/app/dataat every container start, and the app tree only needs read access. The chown now covers
./dataonly, so the step is instant and the layer is gone. (#1045)