A small correctness & consistency patch — no breaking changes. Session engine callbacks no longer
mutate a session after it has been stopped or its engine replaced; bulk-message variables now use the
same {{name}} syntax as message templates (single-brace {name} deprecated but still honored); and
a plugin's declared capability permissions are now actually enforced at the capability boundary.
Changed
- Plugin capability permissions are now enforced. A plugin may use a capability —
ctx.messages.*
(send/reply) orctx.engine.*(read-only group/contact/chat queries) — only if its manifest
declares the matching permission (messages:send/engine:read); a plugin that doesn't declare
it, or declares none, is denied with a clearPluginCapabilityError. Previouslymanifest.permissions
was advisory and unenforced. The built-in extensions declare exactly what they use (auto-reply:
messages:send; translation:messages:send+engine:read) and are unaffected; custom plugins
must declare the permissions for the capabilities they call. (#412) - Bulk-message variable substitution now uses the same
{{name}}syntax as message templates.
POST /sessions/:id/messages/send-bulkpreviously substitutedmessages[].variableswith a
single-brace{name}convention, inconsistent with the double-brace{{name}}used everywhere
else in the gateway. Bulk content is now rendered by the shared template helper, so the canonical
{{name}}placeholders work in bulk content. Existing single-brace{name}content keeps working
unchanged. (#69, #411)
Deprecated
- Single-brace
{name}placeholders in bulk-message content. Prefer{{name}}; the legacy
{name}form is still substituted for backward compatibility but may be removed in a future major
version. (#69, #411)
Fixed
- A session is no longer mutated by callbacks from an engine it has already replaced or torn
down. Each engine's lifecycle/message callbacks (QR, ready, disconnect, state, ack, message,
reaction, …) now no-op once that engine is no longer the live one for the session. This closes a
race where a late callback from a stopped engine — or from a previous engine after a
restart/reconnect — could write a stale status (e.g. flip a stopped session back toready),
schedule a reconnect for a session meant to be down, or persist a stray message/ack against the
wrong engine generation. The guard is a no-op for the live engine and for ordinary network-drop
reconnects. (#410)