Originally created by: kristofferR
New Messenger messages now reach the OS notification center with the sender's name, the message preview, and their profile picture — only while Carrier is in the background — and clicking the notification opens that conversation.
Previously the page's Notification bridge forwarded just title + body to plugin:notification|notify, discarding the avatar (Facebook conveniently puts the sender's fbcdn avatar URL on the Notification's icon), firing even while you were actively reading, and doing nothing on click.
Investigation followed Caprine's proven model and the constraints of tauri-plugin-notification (it drops images on desktop — attachments is mobile-only, icon is ignored on macOS — and surfaces no click events).
Page (inject/messenger.js)
Notification override, render options.icon (the avatar URL) to a small PNG data URL via canvas — reusing the page's Facebook session + already-cached image, so the native side never re-fetches a possibly auth/CORS-gated URL (Caprine's trick). Best-effort: resolves to "" (→ text-only) on any failure, with a 2.5s timeout.carrier:notify event {id, title, body, icon} instead of calling the plugin, gated on document.hasFocus() so it only fires when Carrier is backgrounded.id; window.__carrierNotifyClick(id) (called from Rust on click) invokes Facebook's own onclick for that notification, which opens the right conversation.Native (src-tauri/src/lib.rs)
carrier:notify and build the notification natively (the plugin can't attach a per-notification image or report clicks on desktop). Each notification gets a thread that blocks until the user clicks or dismisses it — it only parks (waits on a condvar / message loop), it doesn't spin. On a click it hops to the main thread, shows/focuses the window, and evals __carrierNotifyClick(id).mac-notification-sys directly: notify-rust only reports a click when the notification carries a button, whereas wait_for_click reports a plain body click (no visible button), and content_image carries the avatar (right-side thumbnail). Its shared, id-keyed delegate makes concurrent notifications safe; the Tauri main loop pumps it.wait_for_action; Linux adds an explicit default action (shown as no button) so a body click is reported. Avatar via the notification icon.base64), unique-named to avoid a write/read race; the avatar temp dir is cleared at startup.notify-rust and mac-notification-sys are already in the dependency tree via tauri-plugin-notification, so the only genuinely new crate is base64.
Notification API in the WebView (it does — same as Caprine in Chromium; the bridge keeps permission = "granted"). If FB ever moved to service-worker push, a title/unread-based fallback would be the safety net (ties into [#5]).cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo test --lib (29 pass, incl. tests for the avatar data-URL decoder and the NotifyMsg wire contract), node --check inject/messenger.js — all green.https://claude.ai/code/session_019Sr356EC9NsasJz5mQDDXC
Improved support for notification actions on macOS and other desktop platforms.
Bug Fixes
Originally posted by: coderabbitai[bot]
📝 Walkthrough
## Walkthrough Adds native desktop notifications for new Messenger messages. The JS injection bridge now emits a `carrier:notify` event with notification metadata and a base64 avatar data URL. The Rust backend decodes the avatar into a temp PNG file, displays a platform-specific native notification (macOS via `mac-notification-sys`, others via `notify-rust`), and routes click events back to the page via `window.__carrierNotifyClick`. ## Changes **Native Message Notification Pipeline** | Layer / File(s) | Summary | |---|---| | **Cargo dependencies**`src-tauri/Cargo.toml` | Adds `notify-rust`, `base64`, and (macOS-only) `mac-notification-sys` dependencies. | | **JS notification bridge rework**
`src-tauri/inject/messenger.js` | Removes old `notify(...)` bridge, adds `openUrl(...)` bridge, reworks `CarrierNotification` to emit `carrier:notify` with avatar PNG data URL and `id`, and adds `window.__carrierNotifyClick` to route notification clicks back to Facebook's original `onclick`. | | **Rust notification implementation and wiring**
`src-tauri/src/lib.rs` | Defines `NotifyMsg`, decodes avatar `data:` URLs to temp PNG files, clears temp cache at startup, sets macOS bundle identifier, registers `carrier:notify` event listener, and spawns per-notification threads for OS-specific display and click-to-focus handling. Includes unit tests for avatar decoding, payload parsing, and malformed input rejection. | ## Estimated code review effort 🎯 4 (Complex) | ⏱️ ~45 minutes ## Possibly related PRs - [[kristofferR/Carrier#1](https://github.com/kristofferR/Carrier/issues/1)](https://github.com/kristofferR/Carrier/pull/1): Prior work on native notification commands and behavior in `src-tauri/src/lib.rs` that this PR extends with the full avatar and click-routing pipeline. ## Poem > 🐇 Hop hop! A message appears, > With avatars decoded and clear. > A temp PNG lands on disk, > The OS notified in a whisk. > Click it! The window leaps to view — > Carrier brings your chats to you! 🎉
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
| Check name | Status | Explanation | | :------------------------: | :------- | :----------------------------------------------------------------------------------------------------------------- | | Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. | | Title check | ✅ Passed | The title accurately summarizes the main change: native new-message notifications with avatar and preview support. | | Docstring Coverage | ✅ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. | | Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |✨ Finishing Touches
🧪 Generate unit tests (beta)
- [ ] Create PR with unit tests - [ ] Commit unit tests in branch `feat/notification-content-avatar`Comment
@coderabbitai helpto get the list of available commands.Originally posted by: kristofferR
@coderabbitai review
Originally posted by: coderabbitai[bot]
✅ Action performed
Review finished. > Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.Originally posted by: kristofferR
@coderabbitai review
Originally posted by: coderabbitai[bot]
✅ Action performed
Review finished. > Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.Ticket changed by: kristofferR