Releases: rmyndharis/OpenWA-plugins
Release list
chatwoot-adapter v0.5.2
Fixed
- The internal de-duplication markers no longer grow without bound. The adapter keeps one marker per
relayed message — to skip WhatsApp re-deliveries and its own echoed sends — and these were never cleaned
up, so the plugin's storage grew for the life of the install and the inbound-retry timer's periodic scan
got progressively slower on a long-running instance. Markers now carry a timestamp and are pruned once
they pass a 3-day retention window, which comfortably outlasts any realistic WhatsApp re-delivery or
own-send echo, so normal live de-duplication is unaffected. No configuration or action is needed;
existing markers are migrated automatically.
Install: download chatwoot-adapter.zip below and upload it in the OpenWA dashboard (Plugins → Install).
SHA-256: f9ad7dfa8ebe1e3b560234d8c1b92acf04c3f4acbe9497d22b0d1c26a2c2f328
chatwoot-adapter v0.5.1
Fixed
- A contact who migrates to
@lidno longer splits into a duplicate Chatwoot conversation on inbound.
Their@lidmessages now resolve to the existing<phone>@c.usconversation (via the host
canonicalChatIdresolver + a dual lookup), mirroring the outbound fix in 0.4.0. Best-effort — it
applies whenever the lid→phone mapping is known: after any reply to the contact, or on every inbound
when OpenWA'sRESOLVE_LID_TO_PHONE=trueis set (recommended to fully close the gap; it also helps the
outbound path).
Install: download chatwoot-adapter.zip below and upload it in the OpenWA dashboard (Plugins → Install).
SHA-256: 560013eadc449be608f624c6c8b7683213c388663cdf73fa74264c69535a5b4e
chatwoot-adapter v0.5.0
Added
- Inbound relay is now retried instead of dropped when Chatwoot is transiently unreachable (#609).
A failed inbound message is held in a durable, storage-backed queue and re-posted on a timer until it
succeeds; a message that keeps failing is dead-lettered after several attempts. The plugin's health
check surfaces the pending backlog and any dead-lettered messages.- This makes inbound delivery at-least-once (previously at-most-once — a failed post was logged and
dropped). As a result, a message that actually reached Chatwoot but whose response was lost may, on
rare occasions, be re-posted as a duplicate.
- This makes inbound delivery at-least-once (previously at-most-once — a failed post was logged and
Install: download chatwoot-adapter.zip below and upload it in the OpenWA dashboard (Plugins → Install).
SHA-256: 7c92a79a00a0e3be4a839dc28835d5f70991d880e103a6ec87d149c91b3c2592
chatwoot-adapter v0.4.0
Added
- Relay your own outbound sends into Chatwoot, so a conversation isn't one-sided when you reply from a
linked phone, the WhatsApp app, or the OpenWA API (#615). These mirror into the contact's existing
mapped Chatwoot conversation asoutgoingmessages (a send to a chat not yet in Chatwoot is skipped —
it appears once the contact replies, never as a duplicate conversation). Replies you send from within
Chatwoot are recognized and never duplicated. NewrelayOwnMessagessetting, on by default; turn it
off to keep phone-composed messages out of the helpdesk. When the@lidmapping is resolvable, own
sends to a contact WhatsApp has migrated to@lidland in their existing conversation instead of a
duplicate, via the new hostcanonicalChatIdresolver. Requires OpenWA 0.8.7+.
Install: download chatwoot-adapter.zip below and upload it in the OpenWA dashboard (Plugins → Install).
SHA-256: b88b90e24a21b5b45fa08bf2b2ab6fe99b61c5424a872c7a092f084bc11cb024
chatwoot-adapter v0.3.0
Added
- History backfill so agents see prior WhatsApp context in Chatwoot instead of a conversation that
starts mid-thread (#609). Two composable modes, both off by default:- Lazy (
backfillLimit) — when a chat first opens as a Chatwoot conversation, its recent messages
(both directions, with media) are replayed oldest→newest before the triggering message, so the thread
reads in order. Deduped against the live path, so nothing double-posts. - Bulk (
backfillAllOnce) — a one-time sweep that imports the history of every existing chat on
setup, for mirroring a whole inbox. Sequential, best-effort, runs once per session. - Business-side (
fromMe) messages post as Chatwootoutgoing, contact messages asincoming. - Requires OpenWA 0.8.6+ (the
engine.getChatHistorycapability, bridged to sandboxed plugins) and the
engine:readpermission. History that can't be fetched (e.g. the Baileys engine, which doesn't support
it, or a chat with no fetchable history) is skipped — the bulk sweep never creates empty conversations.
- Lazy (
Added
- Reply/quote context is forwarded to Chatwoot. Every relayed message now carries its WhatsApp id as
source_id, and a reply carriescontent_attributes.in_reply_to_external_id, so a swipe-to-reply shows
its quoted bubble in Chatwoot instead of a bare, context-less line. (#606) - Voice notes relay both ways. Inbound WhatsApp voice notes are uploaded as Chatwoot voice messages
(is_voice_message,voice.ogg); a voice note whose blob was dropped for size posts a short
placeholder instead of an empty bubble. Outbound audio attachments from Chatwoot are sent back to
WhatsApp as PTT voice notes, and image/video/file attachments are relayed as their native media type —
previously any attachment without text was silently dropped. Requires OpenWA 0.8.3+. (#607) - Contact names self-heal for
@lidchats. A chat first seen from a privacy-id (@lid) sender is
seeded in Chatwoot with the bare id; once a real WhatsApp display name arrives on a later message, the
Chatwoot contact is renamed to it. Best-effort, only when the name actually changed, and never for
group contacts. (#609) - Self-hosted Chatwoot guidance in the README:
baseUrlmust be a publichttpsURL (LAN/localhost
are rejected by the SSRF guard), how to expose a self-hosted instance, and how to avoid 502/530 on large
media uploads through a tunnel. (#609) - Locations and stickers relay as first-class types. A shared location posts as a Chatwoot text bubble
with its coordinates and an openable maps link (previously an empty message); a sticker is uploaded as a
image/webpattachment namedsticker.webpso it renders. (#609)
Install: download chatwoot-adapter.zip below and upload it in the OpenWA dashboard (Plugins → Install).
SHA-256: 99914f07bd8909de5cfdc01ce98dcc46fdf81f0eb069dd5b27a63e3b7508bb56
chatwoot-adapter v0.2.0
Added
- Reply/quote context is forwarded to Chatwoot. Every relayed message now carries its WhatsApp id as
source_id, and a reply carriescontent_attributes.in_reply_to_external_id, so a swipe-to-reply shows
its quoted bubble in Chatwoot instead of a bare, context-less line. (#606) - Voice notes relay both ways. Inbound WhatsApp voice notes are uploaded as Chatwoot voice messages
(is_voice_message,voice.ogg); a voice note whose blob was dropped for size posts a short
placeholder instead of an empty bubble. Outbound audio attachments from Chatwoot are sent back to
WhatsApp as PTT voice notes, and image/video/file attachments are relayed as their native media type —
previously any attachment without text was silently dropped. Requires OpenWA 0.8.3+. (#607) - Contact names self-heal for
@lidchats. A chat first seen from a privacy-id (@lid) sender is
seeded in Chatwoot with the bare id; once a real WhatsApp display name arrives on a later message, the
Chatwoot contact is renamed to it. Best-effort, only when the name actually changed, and never for
group contacts. (#609) - Self-hosted Chatwoot guidance in the README:
baseUrlmust be a publichttpsURL (LAN/localhost
are rejected by the SSRF guard), how to expose a self-hosted instance, and how to avoid 502/530 on large
media uploads through a tunnel. (#609) - Locations and stickers relay as first-class types. A shared location posts as a Chatwoot text bubble
with its coordinates and an openable maps link (previously an empty message); a sticker is uploaded as a
image/webpattachment namedsticker.webpso it renders. (#609)
Install: download chatwoot-adapter.zip below and upload it in the OpenWA dashboard (Plugins → Install).
SHA-256: 938decb55225b8b5b152fa38ed9ee72e29c2737933ba70803c348446b4baf41c
voice-transcription v1.0.1
Fixed
- A webhook-delivery failure no longer suppresses the in-chat transcript. When both
deliveryWebhookUrlandchatDeliverywere configured, a transient webhook error threw before the
chat send, so the transcript reached neither channel. The two sinks are now isolated: a webhook failure
is warned and the in-chat delivery still runs. - Untrusted media mimetype is validated before it reaches the STT upload's multipart headers. The
inboundmimetypeis now accepted only as a well-formedtype/subtypetoken (codec suffix stripped);
anything else — including a CRLF-bearing value — falls back toaudio/ogg. The part filename is already
fixed tovoice.ogg, so valid formats (e.g.audio/ogg; codecs=opus) are unaffected.
Added
- Initial release. Transcribes inbound WhatsApp voice notes via an OpenAI-compatible
/v1/audio/transcriptionsbackend (self-hosted Speaches/faster-whisper, or hosted Groq/OpenAI) and
delivers amessage.transcriptionevent to a configurable webhook — the integration channel for
bots/AI to read and reply to audio. - Runs off the message-delivery critical path: the
message:receivedhook returns immediately and
the STT call + delivery run as an un-awaited promise, so transcription never blocks or delays message
delivery (and is not bound by the host's 5s hook budget). - Audio is uploaded as a binary multipart body (intact across the sandbox boundary); the part is labeled
voice.ogg/audio/oggso OpenAI-compatible servers accept WhatsApp's OGG/Opus without transcoding. - Guards: message-type filter (default
voice), exactmaxSizeBytescost guard, best-effort per-session
hourly rate limit, and a best-effort idempotency guard that suppresses near-simultaneous engine re-fires. - Status events: delivers
completed(with transcript),failed(STT errored), orskipped(too large,
rate-limited, empty) — so a consumer always knows a voice note was received even when it can't be read. - Optional in-chat delivery (
chatDelivery:off|self|reply, defaultoff) for operators who
want the transcript inside WhatsApp;selfnotes it to your own number without leaking to the sender.
Webhook delivery is optional too — the plugin can run chat-only. - Webhook payloads are HMAC-SHA256 signed in
X-OpenWA-Signature(same scheme as OpenWA core webhooks)
when a delivery secret is set, so existing verification reuses the same check. - STT circuit breaker: after repeated failures the backend is skipped for a cooldown, so a degraded
provider isn't hammered. - Fail-open throughout — any STT or delivery error is logged and skipped, never disrupting delivery.
- The delivered transcript is marked
untrusted: true(source: "speech-to-text"): downstream LLM
consumers must treat it as user-role input.
Install: download voice-transcription.zip below and upload it in the OpenWA dashboard (Plugins → Install).
SHA-256: 82b8590e85f8825abc92e6b50518d041691bf51231317344ab1016dcd7976704
gsheets-logger v0.2.3
Fixed
- Oversized cell no longer stalls logging. A message body longer than Google Sheets' 50 000-char
cell limit made the whole append batch fail with a 400 that was retained and retried forever,
blocking all logging. Every cell is now capped at 50 000 chars, so one long message can't poison the
pipeline. - Formula-injection guard on free-text fields extended to
+/-. A leading+/-is now quoted
when it is not the start of a number, so an attacker-controlled sender name or body like
-IMPORTXML(…)/+ HYPERLINK(…)is neutralized on CSV export, while a phone number (+62812…) or a
negative number (-5°C) is still written unquoted. - Sub-second flush interval floored to 1s. A finite but tiny
flushIntervalSec(e.g.0.001) was
accepted and hot-looped the flush timer; it is now floored to 1 second (the NaN/0/negative clamp is
unchanged).
Install: download gsheets-logger.zip below and upload it in the OpenWA dashboard (Plugins → Install).
SHA-256: a688835e73b0bbdbc36a4ad0ae0baa79f4e6fbcfdaebc97bad22452810978c59
group-translate v1.0.5
Fixed
denyReplyis now honored. The denial reply for a restricted command was sent unconditionally,
ignoring thedenyReplyconfig (which the manifest documents as defaultfalse). It now replies only
whendenyReplyis enabled — so by default an unauthorized user cannot make the bot echo an "admins
only" message back into the group on every attempt.
Changed
- README Security section corrected. It previously claimed
SSRF_ALLOWED_HOSTS"no longer applies to
plugins" — the opposite of the truth. The host SSRF guard blocks loopback/private addresses at connect
for everyctx.net.fetchregardless ofnet.allow, so a self-hosted LibreTranslate on
localhost/127.0.0.1/a private host (including the defaulthttp://localhost:7001) requires
SSRF_ALLOWED_HOSTS=<hostname>on the gateway. The Security section and config table now say so.
Install: download group-translate.zip below and upload it in the OpenWA dashboard (Plugins → Install).
SHA-256: 0f47a47e4180c369563c64d0e2f2783662b8dca3dc51a6b6be8dd4da96bdc96e
faq-bot v0.1.6
Fixed
- An empty character class (
[]/[^]) no longer bypasses the regex safety screen. The class
parser treated a leading]as a literal member (POSIX), but in JavaScript[]is an empty class and
[^]matches any char — so[^](a+)+!was mis-parsed as one atom and its catastrophic(a+)+tail
slipped through and could pin the worker. The parser now follows JS class semantics. (Differential
fuzzing confirms the screen rejects everything the pre-0.1.5 screen did, with no reintroduced hole.)
Changed
- Fewer false rejections of safe patterns. Adjacent overlapping quantifiers are now rejected only at
3 or more in a row (.*.*.*) — two adjacent (.*.*,.*\d+) isO(n²), safe under the 1000-char
cap, and is now allowed. A repeated variable-width group is rejected only when the repeat is unbounded
or large (≥10, e.g.(a?){40}); a small bounded repeat like(ab?){2}or(\d{2,4}){3}is allowed.
Install: download faq-bot.zip below and upload it in the OpenWA dashboard (Plugins → Install).
SHA-256: 2557047940b4c5333dfa654410ced2190fc59d4ad50316278218bacabf8966d9