Skip to content

v1.3.0 - Self-Updating

Choose a tag to compare

@Thuong180702 Thuong180702 released this 09 Aug 02:11
· 9 commits to main since this release

🚀 notihub v1.3.0

Release Title: v1.3.0 - Self-Updating


🌟 Highlights

  • ⬇️ notihub updates itself. An available update is now a Download & Install button instead of a link to this page. It fetches the release zip, checks it against the SHA-256 GitHub publishes for that exact asset, and replaces the installed app — you restart when it suits you.
  • 🔓 No more "notihub is damaged" on updates. com.apple.quarantine is applied by browsers, so a build notihub downloads for itself is never quarantined. The xattr command is now only ever needed for the first manual install.
  • 🍺 Works the same however you installed. The Homebrew cask declares auto_updates, so brew upgrade steps aside instead of fighting the app over versions.
  • 🐛 Fixes a broken v1.2.0 npm package — see below. If you installed the CLI from npm, please upgrade.

🛠️ Detailed Changelog

⬇️ In-place updates without Squirrel.Mac

Squirrel.Mac is macOS's usual update mechanism and it is unavailable to this project: it installs only an update signed by the same Apple Developer ID as the running copy, which ad-hoc signing (no paid Developer ID) cannot provide. Rather than leave updates manual, src/updater.js does by hand exactly what a user was doing:

  1. Download notihub-v<version>-mac.zip from the release.
  2. Verify it against the digest GitHub publishes per asset. A mismatch deletes the download before anything is unpacked — nothing is installed that does not hash to the published value.
  3. Unpack with ditto (framework symlinks survive; cp would flatten them).
  4. Confirm the unpacked build passes codesign and reports the version the release advertised.
  5. Move the installed bundle aside, copy the new one in, and restore the old one if the copy fails.

If notihub cannot write over its own bundle — a non-admin account, or a copy running from somewhere read-only — the button falls back to opening the release page, exactly as before.

🐛 The npm package published for v1.2.0 was broken

npm rejected the bare name notihub as too similar to an existing package, so v1.2.0 was published scoped, as @thuong180702/notihub. Two places derived the app name from the package name, and so began looking for /Applications/@thuong180702/notihub.app:

  • bin/notihub.js — the CLI stopped finding the installed app, silently demoting notihub, notihub notify and notihub doctor to an unpackaged Electron run, which macOS refuses to deliver notifications from. Anyone who installed @thuong180702/notihub@1.2.0 from npm should upgrade.
  • scripts/build-app.js — building from source failed outright.

Both now read a new productName field, which is the app's name and is independent of whatever the registry requires the package to be called.

🔁 Downloads retry

A dropped connection partway through the ~120MB transfer (seen as net::ERR_CONNECTION_RESET while testing this) used to cost the whole update. Downloads now retry before surfacing a failure.

🧷 Restarting into the new build

notihub holds a single-instance lock, so a new copy that starts before the old process has exited sees the lock and quits — which would look like the update killed the app. The restart now waits for the old process to exit, then goes through open -a so LaunchServices gives the new copy its menu bar slot and notification identity.


✅ How this was verified

The full chain was run against the live v1.2.0 release under real Electron — download, checksum reject and accept, extract, version-mismatch reject, swap, codesign, launch, and cleanup: 19 checks, alongside 16 new unit tests.

Two bugs were caught by that testing rather than by review:

  • Deriving the bundle path from the executable returned Electron.app on a dev run (that binary also sits three levels inside a .app) — an updater willing to write there would have overwritten node_modules. It now requires its own bundle name.
  • The single-instance lock race described above.

📦 Download Assets & Checksums

Asset File Format SHA-256 Checksum
notihub-v1.3.0-mac.dmg Native macOS DMG Installer 50bef908d980334ff8c35a89ada3eebf1db8cdce6d644716341e5481e447aa87
notihub-v1.3.0-mac.zip Portable Zip Archive 64e7a0e28734274ffd9d0267548b2ebd4f5a782c08ade838aefaf6f11c61584a

📥 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.0-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.0-mac.zip.
  2. Unzip and move notihub.app into /Applications.

⬆️ Upgrading from v1.2.0 or earlier

This is the last update you have to install by hand — v1.3.0 onwards, notihub offers to do it for you.

Replace the app as usual. No bundle identifier change, so notifications stay granted.


⚠️ Gatekeeper Notice

notihub is signed ad-hoc, not notarized by Apple, so macOS will refuse this 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 the last time you should need it.