Skip to content

v1.3.6 - Messenger Notifications Actually Say What They're About

Latest

Choose a tag to compare

@Thuong180702 Thuong180702 released this 09 Aug 23:58
· 2 commits to main since this release

🚀 Notihub v1.3.6

Release Title: v1.3.6 - Messenger Notifications Actually Say What They're About


🎯 What this fixes

Messenger banners said "1 new message" with no sender and no text — and two messages only ever produced one banner. If you've seen the menu bar badge stop at 1 no matter how many messages actually arrived, this is why, and it's fixed.


🔍 The bug

Messenger runs its entire messaging stack inside a SharedWorker and raises its notifications from there. Measured directly in the running app:

Realm window.Notification
Messenger's page our shim — intercepted
Messenger's SharedWorker function Notification() { [native code] } — never seen

Every real notification went straight past us. What arrived instead was the fallback: reading the unread count out of the tab title. That title counts unread conversations, not messages — two messages from the same person move the count 0 → 1 exactly once, so the badge froze at 1 and the banner had nothing but a generic count to show.

A SharedWorker also turned out to be the one JS realm nothing in this app could reach. preload.js only ever ran in the page. Electron has no preload for a shared or dedicated worker at all — the closest thing, a service-worker preload, runs in an isolated ShadowRealm (measured: self isn't even defined there), which rules that path out too.


🛠️ How it works now

The DevTools protocol reaches where preloads can't. webContents.debugger auto-attaches to every worker a service creates, with waitForDebuggerOnStart so the shim installs before the site's own script can grab a reference to the native Notification. New file: src/worker-notify.js.

That still leaves the SharedWorker itself unreachable — auto-attach only follows a page's dedicated workers, and a shared worker is a browser-level target. So the preload now hides window.SharedWorker from the page before any site script runs. Messenger's own fallback path takes over, the same messaging bundle loads as a dedicated worker instead, and that one the debugger can attach to. Verified end-to-end: firing a notification from inside that worker now reaches notify() with the real sender name and message body, and two messages in one thread arrive as two separate banners.

New per-service option in config.json, on by default:

"hideSharedWorker": true

Set it to false for a service if hiding SharedWorker ever breaks a site that has no fallback for its absence.

Also fixed: notifications with no icon at all. nativeImage only decodes PNG and JPEG. Messenger's auto-detected favicon is a .ico, and the app had been saving it over the working PNG already in config.json — the icon silently failed to decode and the banner shipped with nothing. Unusable sources are now remembered and skipped in favor of the next candidate (Google's favicon service always re-encodes to PNG). Checked across all eight bundled presets; every one now resolves to a usable image.

Smaller fixes in the same pass:

  • A site's notification icon and tag now travel through the whole pipeline — a sender's avatar shows where available, and same-thread messages group in Notification Center instead of piling up as separate items (grouped, not deduplicated: a second message no longer risks silently replacing the first).
  • document.hasFocus() is now shimmed alongside document.hidden — a site that gates its own notification logic on focus rather than visibility saw the hidden panel as focused and stayed silent, for the same underlying reason the visibility override already existed.

✅ How this was verified

  • npm test: 95 reported checks, including a new 15-check suite (test/test-worker-notify.js) for the worker-realm shim in isolation — install guards, title/body/tag/icon relay, ascending ids per notification, click replay, and permission reporting.
  • Live simulation through the actual realm Messenger uses. Connected to the running app over the DevTools protocol, located MAWMainV4WebWorkerBundle (Messenger's messaging worker), and fired notifications from inside it — confirmed two messages in one thread arrive as two distinct banners with real sender names and message text, not the generic unread-count line.
  • A real banner from the packaged v1.3.6 build, captured on screen: sender name, service name, message body, and the Messenger icon all present.
  • Confirmed Messenger keeps working with SharedWorker hidden — 43 conversations listed, composer present, page otherwise unaffected.
  • A dead end recorded rather than shipped: a service-worker preload was built and measured to run in a ShadowRealm with no access to the worker's own scope, and removed once that was confirmed rather than left in as dead code.

📦 Download Assets & Checksums

Asset File Format SHA-256 Checksum
notihub-v1.3.6-mac.dmg Native macOS DMG Installer a8512642cd71d996e41435786eff05c00978be563e78600337a2670b9b7cb4e9
notihub-v1.3.6-mac.zip Portable Zip Archive 6d22f1f3308089a676e28e8da93274541f1e3d39a0cfe811a043771434a98077

These are the same values src/updater.js verifies each download against before installing.


📥 Installation Options

Method 1: Homebrew (Recommended)

brew tap thuong180702/notihub
brew install --cask notihub

Method 2: npm (CLI companion)

npm install -g @thuong180702/notihub

Method 3: DMG Installer

  1. Download notihub-v1.3.6-mac.dmg below.
  2. Double click to open the DMG, then drag notihub.app into Applications.

Method 4: Direct Zip Download

  1. Download notihub-v1.3.6-mac.zip.
  2. Unzip and move notihub.app into /Applications.

⬆️ Upgrading

Use Settings → Download & Install. No bundle identifier or data-directory change, so existing logins stay intact.

If DevTools is open on a service tab after upgrading, that tab falls back to the old title-count notifications until DevTools is closed — webContents.debugger and DevTools can't attach to the same tab at once. --dev no longer opens DevTools automatically for this reason; use the new --devtools flag when you actually want it open.


⚠️ Gatekeeper Notice

Notihub is signed ad-hoc, not notarized by Apple, so macOS will refuse a manual install with "notihub is damaged and can't be opened". This isn't corruption — it's Gatekeeper rejecting an unnotarized app. Clear the quarantine flag once:

xattr -dr com.apple.quarantine /Applications/notihub.app

Updates Notihub installs itself are never quarantined, so this is only needed for a fresh manual install.