v0.7 — plugin-contract expansion. Richer plugin config (declarative + sandboxed-iframe editors),
per-session activation and config, SSRF-guarded outbound HTTP, and the removal of the bundled
reference extensions in favour of the marketplace. ⚠️ See the Removed note before upgrading.
Added
- Plugins: richer config schema vocabulary — a
textareatype,min/max/patternvalidation hints, and composite kinds (itemsfor arrays, including array-of-rows whenitemsis an object;propertiesfor nested objects;enumrenders a select). The dashboard config form renders them recursively, and secret redaction/restore now recurses so asecretfield at any depth is masked on read and preserved on an unchanged write. (#439) - Plugins: a plugin may ship a sandboxed-iframe config editor via manifest
configUi { entry, height? }. The host serves the entry over an authenticatedGET /plugins/:id/config-ui(ADMIN, path/realpath escape-guarded, CSP-sandboxed) and the dashboard injects it as ansrcdocinto asandbox="allow-scripts"iframe (opaque origin). The editor exchanges config over apostMessagebridge — the API key never enters the iframe, and it only ever receives schema-declared, secret-redacted config. (#440) - Plugins: per-session config overrides. A session-scoped plugin can carry per-session config on top of its base (
'*') config viaPUT /plugins/:id/config/:sessionId;ctx.config(read inside a hook) is the override shallow-merged over the base for the firing session, resolved race-safely viaAsyncLocalStoragefor both in-process and sandboxed plugins. Overrides are secret-redacted per slice on the API and survive a restart. (#441) - Plugins: per-session activation. A session-scoped plugin can now be activated for all numbers (
*) or an explicit set of sessions viaPUT /plugins/:id/sessions, and only receives hook events for the sessions it is active for (enforced at delivery). A plugin declaressessionScopedin its manifest (defaulttrue); a global plugin (false, e.g. a metrics logger) always runs. The active set is surfaced on the plugin API and survives a restart. (#438) - Plugins: a new
ctx.net.fetchcapability lets a sandboxed plugin make outbound HTTP through the host's SSRF guard (resolve-once-pin, redirects refused), gated by anet:fetchpermission plus a manifestnet.allowhost allowlist (host:port, barehost, or*for any public host; internal IPs are always blocked). Responses are bounded by a timeout and a streamed size cap. (#437) - Chats: opening a conversation now shows its recent history. The dashboard backfills messages directly from WhatsApp when the gateway has none stored yet and merges them with locally-persisted messages, so a freshly connected session shows the conversation instead of an empty thread.
- Engine (whatsapp-web.js): a reconnect that stalls mid-authentication now self-heals — the stale local auth is cleared and a fresh QR pairing is started — and the WhatsApp Web build can be pinned via
WWEBJS_WEB_VERSIONfor environments where the auto-selected build drifts. - Dashboard: a searchable plugin catalog, audit-log CSV export across all pages (not just the current view), the running version shown in the sidebar, and an engine-aware engine-configuration dialog (Baileys no longer shows Puppeteer-only fields).
Changed
- Dashboard, small screens: the chat view is now a single-pane list → conversation flow with a back control instead of a cramped two-pane; page headers place the description directly under the title; and keyboard focus is a consistent, cross-browser, keyboard-only ring. Plus assorted copy and empty-state refinements.
- Plugins (install): install-from-URL / catalog downloads now follow CDN redirects safely — each hop is re-validated through the SSRF guard — so plugins published on GitHub Releases install correctly.
Removed
- ⚠️ Breaking: the bundled reference extensions
auto-replyandtranslationhave been removed from core. They are superseded by the marketplace pluginschat-flow(interactive auto-reply) andgroup-translate(LibreTranslate group translation), which target the v0.7 contract. Upgrade: if you had either enabled, install the replacement from the dashboard (Plugins → Catalog, orPOST /plugins/install-url) and re-enter its config. The idsauto-reply/translationremain reserved (an uploaded package can't claim them). Built-in engines (whatsapp-web.js, Baileys) are unaffected.
Fixed
- Plugins: an operator's per-session activation (and now per-session config) was silently dropped from the on-disk registry on the second restart, because the registry entry was rebuilt on each load without carrying those fields. Both are now preserved across restarts. (#441)
- Docker: the multi-arch image build failed on
linux/arm64(Cannot find module lightningcss.linux-arm64-gnu.node) — the builder stage was QEMU-emulated per target and the emulated arm64 install couldn't fetch lightningcss's (Vite's native CSS minifier) arm64 binary. The builder, which only produces arch-independent artifacts, is now pinned to$BUILDPLATFORMso it runs natively; per-arch runtime deps still install in the target-platform stage. Restoreslinux/arm64GHCR publishing. - Inbound media is now size-capped before the full attachment is buffered into memory, on both engines, and concurrent inbound media downloads are bounded — lowering peak memory under bursty load.
- Plugins: composite (object/array) config fields marked
secretare now fully masked when read back; plugin storage files and directories are created with owner-only permissions; and several runtime robustness fixes (timeout, validation, and error handling) in the sandbox and installer.
Security
- Session scope is now enforced on the session-statistics overview and on per-session plugin activation, so an API key restricted to specific sessions can no longer read or change state for sessions outside its scope.