Skip to content

Latest commit

 

History

History
123 lines (97 loc) · 8.28 KB

File metadata and controls

123 lines (97 loc) · 8.28 KB

Changelog

All notable changes to the Chatwoot Adapter plugin are documented here. The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

[Unreleased]

[0.5.2] — 2026-07-04

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.

[0.5.1] — 2026-07-03

Fixed

  • A contact who migrates to @lid no longer splits into a duplicate Chatwoot conversation on inbound. Their @lid messages now resolve to the existing <phone>@c.us conversation (via the host canonicalChatId resolver + 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's RESOLVE_LID_TO_PHONE=true is set (recommended to fully close the gap; it also helps the outbound path).

[0.5.0] — 2026-07-03

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.

[0.4.0] — 2026-07-03

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 as outgoing messages (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. New relayOwnMessages setting, on by default; turn it off to keep phone-composed messages out of the helpdesk. When the @lid mapping is resolvable, own sends to a contact WhatsApp has migrated to @lid land in their existing conversation instead of a duplicate, via the new host canonicalChatId resolver. Requires OpenWA 0.8.7+.

[0.3.0] — 2026-07-03

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 Chatwoot outgoing, contact messages as incoming.
    • Requires OpenWA 0.8.6+ (the engine.getChatHistory capability, bridged to sandboxed plugins) and the engine:read permission. 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.

Added

  • Reply/quote context is forwarded to Chatwoot. Every relayed message now carries its WhatsApp id as source_id, and a reply carries content_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 @lid chats. 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: baseUrl must be a public https URL (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/webp attachment named sticker.webp so it renders. (#609)

[0.1.1] — 2026-07-02

Fixed

  • Cross-tenant isolation for multi-account deployments. The reverse conversation map and the Chatwoot-side idempotency markers were keyed by the Chatwoot conversation/message id alone. Because plugin storage is shared across every session and Chatwoot ids are per-account autoincrement, two instances bound to different Chatwoot accounts could collide — an agent reply could be delivered to the wrong WhatsApp session, or silently dropped. Both are now scoped by the delivery's WA session; a legacy unscoped key is kept so single-tenant and pre-upgrade conversations are unaffected.
  • A transient WhatsApp-send failure no longer drops an agent reply. The outbound dedup marker was written before the send, so a momentary failure suppressed the retry. It is now written only after a successful send.
  • Attacker-controlled media filename/mimetype can no longer inject multipart parts into the upload to the Chatwoot API — CR/LF (and a quote) are stripped from the part headers.
  • baseUrl is validated at enable time. A non-https or credentialed baseUrl — which the host net allowlist rejects, silently failing every inbound relay — now fails fast when the plugin is enabled.
  • A malformed conversation_updated payload no longer retry-loops. A non-object changed_attributes element is guarded instead of throwing a TypeError.

[0.1.0] — 2026-07-02

Initial release — two-way WhatsApp ↔ Chatwoot sync.

  • WhatsApp → Chatwoot: relays inbound messages (1:1 and groups) into a Chatwoot API-channel inbox as incoming messages, including media as attachments. Contacts are keyed on the WhatsApp JID (safe across WhatsApp's @lid migration); a group maps to a single synthetic contact with sender-prefixed messages.
  • Chatwoot → WhatsApp: relays agent replies (message_type: outgoing, non-private) back to WhatsApp; drops the adapter's own posts, foreign inboxes, and private notes.
  • Handover: when a human agent is assigned in Chatwoot, other OpenWA bots stop auto-replying on that chat; automation resumes when the conversation is unassigned.
  • Inbound and outbound are serialized by an in-worker per-chat lock (no duplicate contacts/conversations on a cold-start burst), with idempotency on both WhatsApp and Chatwoot message ids.

Requires an OpenWA host with Integration SDK v1 (webhook ingress, ctx.mappings, the session+chat handover gate, and net.allowConfigHosts), and a Chatwoot version that HMAC-signs account-level webhooks with a timestamp (see the README setup guide).