Menu ▾ ▴

#351 Let Messenger raise its own notifications and key them by message ID

closed
nobody
2026-11-07
2026-11-07
Anonymous
No

Originally created by: kristofferR

Problem

Every Carrier notification is reconstructed from the DOM. Carrier.log on both Kris's Mac and Omarchy shows notify.fired (a page-constructed Web Notification) 0 times, against 561 and 603 notify.fallback row-scrape firings. The comment in notifications.ts:736 says Meta "no longer reliably constructs Web Notifications".

Because of that, Carrier pairs titles and bodies against chat rows (notifications.ts:398-451, lib/notification-fallback.ts (github.com), about 1,650 lines), guesses the sender from a "Name:" prefix (lib/notification-names.ts:34), and harvests avatars from the DOM by display name (lib/sender-avatars.ts (github.com)). It never sees a stable message ID.

Root cause

Messenger's useMWLSChatPopperUpper only raises a notification when isMessengerPWA() && justknobx._("1465") holds and the page is hidden. In Carrier neither condition is true, so Messenger never notifies.

Design

Phase 1: make Messenger notify, and capture the real message.

  • Rewrite those two checks in the module source before it registers. fMess reloads the patched source as a blob: script and only applies the patch when the pattern matches exactly once; otherwise the original module runs unchanged (03-facebook-modules.js:128-153). Carrier should add the same guard and log a diagnostics line when the pattern stops matching.
  • Wrap MWDesktopNotifications.triggerLocalNotification(db, message) (03-facebook-modules.js:84-103). The message row carries threadKey, senderId, timestampMs, and a messageId equal to the notification tag. From it:
  • resolve route and sender exactly through the contacts and participants tables (14-notifications.js:36-60);
  • take the large avatar from getLSMediaContactProfilePictureLargeUrl and the group picture from getLSMediaThreadPictureUrl;
  • de-duplicate by tag (14-notifications.js:154-157);
  • drop the post-sleep backlog using lastReadWatermarkTimestampMs (14-notifications.js:29-35).
  • Feed these into the existing carrier:notify path and the cross-window notification ledger, keyed by tag. Keep the row fallback running as a safety net, suppressed for any message already delivered by tag.

Phase 2: delete the guessing. Once Phase 1 has run cleanly on all three platforms, remove the text-correlation, name-prefix and DOM avatar-harvest code that it makes redundant. Keep the row fallback only if diagnostics show the hook missing messages.

Carrier already imports LSDatabaseSingleton and ReQL (notification-names.ts:115-123), so the database plumbing exists. The idea is reused from fMess (MIT); only the two short match patterns would be copied, with attribution.

Testing

  • Unit tests for the source-rewrite guard: zero matches, one match, two matches.
  • Live on each OS: 1:1, group, encrypted chat, muted chat, message while the window is hidden, focused and minimized; reactions and edits do not notify twice.
  • Diagnostics: notify.fired should now dominate notify.fallback in Carrier.log.
  • Sleep the machine for an hour with incoming messages; on wake, no backlog burst.

Part of [#349].

Related

Tickets: #253
Tickets: #349
Tickets: #384

Discussion

  • Anonymous

    Anonymous - 2026-11-07

    Ticket changed by: kristofferR

    • status: open --> closed
     
  • Anonymous

    Anonymous - 2026-11-07

    Originally posted by: kristofferR

    [!NOTE]
    🤖 Claude Opus 5.5 responding on behalf of Kristoffer

    Landed in [#384]: Messenger raises its own notifications, keyed by message ID, and Carrier renders them natively.

    It is on main and ships in the next release.

     

    Related

    Tickets: #384


Log in to post a comment.