v0.8.15
-
WhatsApp Web sessions no longer wedge silently in
INITIALIZINGforever.engine.initialize()was awaited with no timeout, and neither whatsapp-web.js nor Puppeteer bounds the initial browser launch/navigation (page.gotois called withtimeout: 0and the web-version-cache fetch carries no timeout). If Chromium stalled under container memory pressure — realistic at the documented 2 GB Standard profile — the await never resolved or rejected: the session sat inINITIALIZINGindefinitely,GET /sessions/:id/qr400'd forever, and nothing was logged. The #635 abandoned-engine reaper is reactive (terminalonError/ rejected re-init only), so nothing recovered it.initializeEngine()now racesengine.initialize()against a deadline derived from the configured auth wait (floor 60 s, orWWEBJS_AUTH_TIMEOUT_MS+ 30 s when an operator has raised that for slow first boots) so a legitimate slow init is never cut short; on timeout it force-kills the wedged browser, marks the sessionDISCONNECTED(retryable, so the existing reconnect backoff picks it up), and rethrows — surfacing the failure to a manualPOST /startcaller instead of hanging. The race's catch is scoped to the timeout only (EngineInitTimeoutError): a real init rejection (e.g. Chromium can't launch) propagates untouched sostart()'s existingFAILED+reason diagnostics are preserved — handling both in one catch would downgrade real failures toDISCONNECTEDand hide their reason. Thanks @INAPA-desarrolloTIC. [#667] -
Dashboard primary buttons were invisible until hover in light mode. A leftover Vite template rule —
:root:not([data-theme='dark']) button { background-color:#f9f9f9 }inside@media (prefers-color-scheme: light)— carried specificity(0,2,1)(:root+ the:not([data-theme])argument +button), higher than every page-scoped.X-page .btn-primaryrule(0,2,0). In light mode (the default) it overrode the green design-system background with a near-white#f9f9f9, leaving the buttons' white text invisible until the leftover Vitebutton:hover { border-color:#646cff }ring revealed them on hover; the same(0,2,1)rule also pushed.btn-secondaryand.btn-iconoff their intended backgrounds. Removed that rule (Create-session and other primary buttons are green again), and cleared the remaining Vite scaffolding brand-colors fromindex.css(a { color:#646cff }, the purplea:hover,button { background-color:#1a1a1a },button:hover { border-color:#646cff }) that competed with the App.css design system on import-order tiebreaks; the structural button CSS (border-radius, padding, font, cursor) is retained. Plain<button>elements now render with the browser default instead of the dark#1a1a1a. The defect was invisible to anyone developing the dashboard in dark mode. Refs #684 (addresses the dashboard-button part; the QR-with-whatsapp-web.js report in the same issue is separate and still under investigation). -
PostgreSQL upgrade crash-loop for deployments formerly run with
DATABASE_SYNCHRONIZE=true. On the PostgreSQL data connection, migrations always run at boot (migrationsRun: true), so a schema previously bootstrapped withDATABASE_SYNCHRONIZE=true— whose@PrimaryGeneratedColumn('uuid')columns TypeORM created as nativeuuid— collides with a migration chain that assumesvarcharids and crash-loops the container on boot. A new guard migration (NormalizeSynchronizeUuidColumns), ordered before the first colliding migration, now converts thoseuuidid and foreign-key columns tovarchar(dropping and recreating the dependent cascade foreign keys, and re-applying thegen_random_uuid()::varchardefaults), so affected deployments self-heal on the next restart. It is a single-probe no-op on SQLite and on already-varchar(healthy) PostgreSQL. For very largemessagestables the conversion holds an exclusive lock, so runnpm run migration:runagainst the stopped app during a maintenance window if needed;DATABASE_SYNCHRONIZE=trueon PostgreSQL remains unsupported for production. Fixes #690. -
WhatsApp Web auto-version resolver now prefers a settled build. The whatsapp-web.js engine auto-pins its WhatsApp Web build from the wppconnect wa-version registry; the resolver previously took the registry's
currentVersionverbatim — the absolute latest build, which can be minutes old and unvalidated and, on some setups, never reaches QR readiness (the #684 whatsapp-web.js "stuck at Starting, no QR" report class). It now picks the newest non-beta, unexpired build published at least 12 hours ago, falling back tocurrentVersiononly when no build qualifies, so auto-pinning no longer latches onto a brand-new build. Operators who setWWEBJS_WEB_VERSIONexplicitly are unaffected. Fixes the whatsapp-web.js "stuck at Starting, no QR" report from #684 (Bug 2); #692 fixes the dashboard-button part (Bug 1) of the same issue. -
Baileys engine: messages no longer get stuck on "Waiting for this message. This may take a while." on iOS recipients. Reported specifically on iOS WhatsApp: the recipient's chat shows the message as permanently pending, with no error and a stable connection. The Baileys
makeWASocketconfig had nogetMessageimplementation, so WhatsApp's own retry-on-decrypt-failure protocol had nothing to resend, leaving the recipient stuck instead of recovering within seconds; it's now backed by the message store. -
Baileys message-store lookups no longer fail their FK check. The engine factory keyed
messageStore.put/getMessage/clearSessionby the session's on-disk auth-directory name, butBaileysStoredMessage.sessionIdis a foreign key tosessions.id— every write violated the FK and was silently dropped by the orphan guard, leaving the store empty and defeating thegetMessagefix above. The engine config now carries the auth-directory key (sessionId, the session name) and the DB-row key (dbSessionId, the session's UUID) as two separate fields, so the message store is keyed correctly without disturbing the existing on-disk auth-directory layout (andpurgeSessionData, still keyed by name, keeps working on delete). -
Closed a write-then-immediate-read race in the Baileys signal key store. The raw signal key store is now wrapped in Baileys' own
makeCacheableSignalKeyStore, which could previously make a freshly-established session appear "missing" and force an unnecessary fresh PreKey handshake. -
Upgraded
@whiskeysockets/baileys6.7.23→7.0.0-rc13. Picks up an upstream concurrency rewrite (WhiskeySockets/Baileys#2571, #2587) that closes a "dual uncoordinated prekey queues" race in the same session-establishment path; no6.xrelease (up to6.17.16) carries this fix. -
Fixed a first-message-after-reconnect drop on the Baileys engine.
handleMessagesUpsertno longer treats everytype: 'append'upsert as history sync — Baileys can tag a genuinely new customer message'append'when it arrives in the same window as a reconnect's state-sync handshake, silently dropping it; it's now gated on the message's own timestamp against the connection's open time instead (with the account's own sent-message echoes still excluded, to avoid double-firing the existingemitOwnSendEchowebhook). -
Dashboard Korean (ko) locale polish. Refined several ko strings for consistency, fluency, and accuracy (follow-up to #679): "Create New Session" →
새 세션 생성(aligns with생성used elsewhere in the create flow); the plugin "Configuration" tab →설정(matches the rest of the config UI); "Start messaging" →대화 시작하기(idiomatic — in Korean one starts a conversation, not a "message"); the WhatsApp Web build "current known-good" now reads현재instead of최신(latest), which had inverted the version-pinning intent; the "New" session status →신규(the conventional Korean status label); and the template placeholder example re-phrases the{{orderId}}clause so the interpolation reads naturally. -
Reliability and correctness hardening batch. A set of fixes across the engine, session, auth, infra, dashboard, and SDK layers:
- The inbound media concurrency limiter now bounds its waiter queue and rejects when full; both engines route a rejected download to their existing emit-without-media path, so a burst of inbound media can no longer grow heap without bound.
start()now cancels any pending reconnect timer before recreating the engine, so a stale timer left by a failed reconnect can no longer destroy the engine or orphan the Chromium process.- The dashboard chat thread now refetches after a WebSocket reconnect, so messages that arrived during a transient gap (and ack/reaction/revoke updates) are no longer silently missing until the chat is reopened.
- Updating an API key's role, allowed sessions, allowed IPs, or expiry now disconnects the key's already-connected WebSocket sockets, so a narrowed key stops streaming realtime events for sessions/IPs it just lost. A benign rename leaves connected sockets alone.
- The SQLite→PostgreSQL export/import path now covers every data-owned table (plugin instances + ingress HMAC secrets, conversation mappings, ingress events, both dead-letter queues) instead of only seven, so a migration no longer silently drops the Integration Fabric and the DLQs. The main connection (API keys, audit logs) stays excluded; existing seven-table exports still import unchanged.
- The bundled
docker-compose.ymlno longer shadows dashboard-saved Puppeteer headless / session-data-path / browser-args with pinned container defaults — those are blank-forwarded so a dashboard (ordata/.env.generated) selection applies, with the sane container defaults supplied by the application config layer (headless,./data/sessions, the full--no-sandbox --disable-setuid-sandbox --disable-dev-shm-usage --disable-gpuflag set). Upgrade note: if you previously saved engine config in the dashboard, re-save it (or setPUPPETEER_ARGS) so the full Docker sandbox flag set is retained. - The PHP SDK
messages.list()andcatalog.products()docblocks now match the real{messages, total}/{products, pagination}envelopes the server returns (consistent with the JS/Python/Java SDKs), and the SDK CI path-filter now covers backend controllers and services so response-shape drift re-runs the SDK suites.