From 58bd362301affdbc34a2ded36db28bc2ed4f3124 Mon Sep 17 00:00:00 2001 From: Remon Pel Date: Mon, 21 Sep 2026 13:59:42 +0200 Subject: [PATCH] Update bundled terminal-notifier to 3.1.0 (universal, Apple silicon) The vendored terminal-notifier 1.7.2 is an x86_64-only binary. On Apple silicon it needs Rosetta, and on macOS 27 Intel binaries no longer run at all, so node-notifier fails on every build that uses webpack-notifier, gulp-notify and friends. Fixes #361, supersedes #441. terminal-notifier 3.x (julienXX/terminal-notifier, released August 2026) ships an official universal x86_64 + arm64 bundle built on Apple's UserNotifications framework. This commit vendors that release unchanged. Supply chain: the bundle is the upstream GitHub release asset terminal-notifier-3.1.0.zip, SHA-256 e969d4ae20287da1ba55495ae31dcedd8e9069deb8ce4eed24f6561a5fc3e4d5. scripts/update-terminal-notifier.sh downloads it, verifies that checksum and unpacks it into vendor/mac.noindex, so anyone can reproduce and audit what is committed. `codesign --verify --strict` passes on the bundle. Code changes needed for terminal-notifier 3: - Minimum macOS for native notifications is 10.14 (Darwin 18); utils.isMojaveOrLater() replaces isMountainLion() (kept as alias). - Responses are plain text instead of -json: the clicked action title, the typed reply, or @TIMEOUT / @CLOSED / @ACTIONCLICKED. They are mapped back onto the existing { activationType, activationValue } shape, so callbacks and the click/replied/timeout events keep working. JSON output from older binaries used via customPath is still accepted. - Exit code 6 (timeout) is reported as a timeout, not an error. - -action is read from argv, one flag per button, unquoted; -reply may stand alone or take a placeholder string. - -appIcon and -sender are gone (the framework always uses the sending bundle's identity); they are dropped instead of producing stderr noise. - UNUserNotificationCenter refuses to request permission for a bundle LaunchServices has never seen, which is the case for an app inside node_modules. On that specific error the bundle is registered with lsregister once and the notification retried. Tested on macOS 27.0 arm64 without Rosetta (plain notification, action buttons with timeout, reply with placeholder) and with the jest suite. --- CHANGELOG.md | 15 ++ README.md | 36 ++-- lib/utils.js | 110 ++++++++-- notifiers/notificationcenter.js | 57 +++++- package.json | 2 +- scripts/update-terminal-notifier.sh | 47 +++++ test/terminal-notifier.js | 189 +++++++++++++++--- test/utils.js | 36 +++- .../terminal-notifier.app/Contents/Info.plist | 37 +--- .../Contents/MacOS/terminal-notifier | Bin 87688 -> 274592 bytes .../Contents/Resources/en.lproj/Credits.rtf | 29 --- .../Resources/en.lproj/InfoPlist.strings | Bin 92 -> 45 bytes .../Contents/Resources/en.lproj/MainMenu.nib | Bin 25790 -> 0 bytes .../Contents/_CodeSignature/CodeResources | 146 ++++++++++++++ 14 files changed, 576 insertions(+), 128 deletions(-) create mode 100755 scripts/update-terminal-notifier.sh delete mode 100644 vendor/mac.noindex/terminal-notifier.app/Contents/Resources/en.lproj/Credits.rtf delete mode 100644 vendor/mac.noindex/terminal-notifier.app/Contents/Resources/en.lproj/MainMenu.nib create mode 100644 vendor/mac.noindex/terminal-notifier.app/Contents/_CodeSignature/CodeResources diff --git a/CHANGELOG.md b/CHANGELOG.md index 07826b0..bba08a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +### Unreleased + +Breaking changes: + +- Updates the bundled `terminal-notifier` to the official 3.1.0 release, a universal binary that runs natively on Apple silicon (no Rosetta) as well as Intel. Fixes [#361](https://github.com/mikaelbr/node-notifier/issues/361). The bundle is downloaded from the upstream GitHub release and checked against a recorded SHA-256 by `scripts/update-terminal-notifier.sh`. +- The minimum macOS version for native notifications is now 10.14 (Mojave); older versions fall back to Growl as before. +- macOS asks for notification permission once, the first time a notification is sent. node-notifier registers the bundled app with LaunchServices on first use so that prompt can appear. +- `icon`/`appIcon`, `sender`, `closeLabel` and `dropdownLabel` have no effect on macOS anymore: the `UserNotifications` framework does not support them. +- On macOS, `wait`/`timeout` only wait for a response when `actions` or `reply` is set. + +Fixes: + +- `actions` are passed as separate `-action` flags and `reply` accepts a placeholder string, matching terminal-notifier 3. +- `utils.isMountainLion()` is deprecated in favour of `utils.isMojaveOrLater()` (kept as an alias). + ### `v10.0.1` Fixes: diff --git a/README.md b/README.md index 44885fa..6800fb2 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ notifier.notify({ ## Requirements -- **macOS**: >= 10.8 for native notifications, or Growl if earlier. +- **macOS**: >= 10.14 for native notifications, or Growl if earlier. Ships a universal (Intel + Apple silicon) `terminal-notifier`, so Rosetta is not needed. - **Linux**: `notify-osd` or `libnotify-bin` installed (Ubuntu should have this by default) - **Windows**: >= 8, or task bar balloons for Windows < 8. Growl as fallback. Growl takes precedence over Windows balloons. - **General Fallback**: Growl @@ -134,10 +134,17 @@ new nn.Growl(options).notify(options); Same usage and parameter setup as [**`terminal-notifier`**](https://github.com/julienXX/terminal-notifier). -Native Notification Center requires macOS version 10.8 or higher. If you have +Native Notification Center requires macOS version 10.14 or higher. If you have an earlier version, Growl will be the fallback. If Growl isn't installed, an error will be returned in the callback. +The bundled [`terminal-notifier`](https://github.com/julienXX/terminal-notifier) +is the official universal release (Intel and Apple silicon), built on Apple's +`UserNotifications` framework. The first notification on a machine makes macOS +ask for permission once, under the name **terminal-notifier** in System +Settings → Notifications. If that permission is declined, notifications fail +with an error in the callback until it is granted again there. + #### Example Because `node-notifier` wraps around [**`terminal-notifier`**](https://github.com/julienXX/terminal-notifier), @@ -158,7 +165,7 @@ but they aren't documented. const NotificationCenter = require('node-notifier').NotificationCenter; var notifier = new NotificationCenter({ - withFallback: false, // Use Growl Fallback if <= 10.8 + withFallback: false, // Use Growl Fallback if < 10.14 customPath: undefined // Relative/Absolute path to binary if you want to use your own fork of terminal-notifier }); @@ -168,17 +175,17 @@ notifier.notify( subtitle: undefined, message: undefined, sound: false, // Case Sensitive string for location of sound file, or use one of macOS' native sounds (see below) - icon: 'Terminal Icon', // Absolute Path to Triggering Icon - contentImage: undefined, // Absolute Path to Attached Image (Content Image) + icon: undefined, // Ignored on macOS: the icon always comes from the sending app bundle (see below) + contentImage: undefined, // Absolute Path to Attached Image (Content Image). Local files only. open: undefined, // URL to open on Click wait: false, // Wait for User Action against Notification or times out. Same as timeout = 5 seconds - // New in latest version. See `example/macInput.js` for usage - timeout: 5, // Takes precedence over wait if both are defined. - closeLabel: undefined, // String. Label for cancel button - actions: undefined, // String | Array. Action label or list of labels in case of dropdown - dropdownLabel: undefined, // String. Label to be used if multiple actions - reply: false // Boolean. If notification should take input. Value passed as third argument in callback and event emitter. + // See `example/macInput.js` for usage + timeout: 5, // Takes precedence over wait if both are defined. Only waits when `actions` or `reply` is set. + closeLabel: undefined, // Ignored on macOS >= 10.14 (no equivalent in the UserNotifications framework) + actions: undefined, // String | Array. One button per label. + dropdownLabel: undefined, // Ignored on macOS >= 10.14 (no equivalent in the UserNotifications framework) + reply: false // Boolean | String. If notification should take input; a string is used as placeholder. Value passed as third argument in callback and event emitter. }, function (error, response, metadata) { console.log(response, metadata); @@ -198,7 +205,9 @@ high value, or to nothing at all. --- -**For macOS notifications: `icon`, `contentImage`, and all forms of `reply`/`actions` require macOS 10.9.** +**For macOS notifications:** `terminal-notifier` only waits for a response (and +therefore only reports `click`, `replied` and `timeout`) when `actions` or +`reply` is set. A plain notification returns as soon as it is delivered. Sound can be one of these: `Basso`, `Blow`, `Bottle`, `Frog`, `Funk`, `Glass`, `Hero`, `Morse`, `Ping`, `Pop`, `Purr`, `Sosumi`, `Submarine`, `Tink`. @@ -416,7 +425,8 @@ parent application initiating the notification. For `node-notifier`, `terminal-n is the initiator, and it has the Terminal icon defined as its icon. To define your custom icon, you need to fork `terminal-notifier` and build your -custom version with your icon. +custom version with your icon, then point `customPath` at it. The `icon` option +is accepted for compatibility but has no effect on macOS. See [Issue #71 for more info](https://github.com/mikaelbr/node-notifier/issues/71) . diff --git a/lib/utils.js b/lib/utils.js index fe4b164..e745e27 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -56,14 +56,13 @@ module.exports.command = function (notifier, options, cb) { console.info('[notifier options]', options.join(' ')); } - return cp.exec(notifier + ' ' + options.join(' '), function ( - error, - stdout, - stderr - ) { - if (error) return cb(error); - cb(stderr, stdout); - }); + return cp.exec( + notifier + ' ' + options.join(' '), + function (error, stdout, stderr) { + if (error) return cb(error); + cb(stderr, stdout); + } + ); }; module.exports.fileCommand = function (notifier, options, cb) { @@ -86,11 +85,16 @@ module.exports.fileCommandJson = function (notifier, options, cb) { console.info('[notifier options]', options.join(' ')); } return cp.execFile(notifier, options, function (error, stdout, stderr) { + // terminal-notifier >= 3 exits with 6 when -timeout expires. That is a + // regular outcome for node-notifier, not an error. + if (error && error.code === MAC_EXIT_NO_RESPONSE) { + error = null; + } if (error) return cb(error, stdout); if (!stdout) return cb(error, {}); try { - const data = JSON.parse(stdout); + const data = parseMacResponse(options, stdout); cb(!stderr ? null : stderr, data); } catch (e) { cb(e, stdout); @@ -98,6 +102,80 @@ module.exports.fileCommandJson = function (notifier, options, cb) { }); }; +// Exit codes of terminal-notifier >= 3. +const MAC_EXIT_NOT_AUTHORIZED = 3; +const MAC_EXIT_NO_RESPONSE = 6; +module.exports.MAC_EXIT_NOT_AUTHORIZED = MAC_EXIT_NOT_AUTHORIZED; +module.exports.MAC_EXIT_NO_RESPONSE = MAC_EXIT_NO_RESPONSE; + +/** + * Normalises what terminal-notifier prints on stdout into the object shape + * node-notifier has always handed to callbacks and event listeners: + * `{ activationType, activationValue }`. + * + * terminal-notifier 1.x/2.x (and forks used through `customPath`) print JSON + * when passed `-json`. terminal-notifier >= 3 prints a single line: the + * clicked action title, the typed reply, or one of the markers `@TIMEOUT`, + * `@CLOSED`, `@ACTIONCLICKED`. `-list` and `-remove` print free text. + */ +function parseMacResponse(argsList, stdout) { + argsList = argsList || []; + try { + return JSON.parse(stdout); + } catch (e) { + // Not JSON; fall through to the plain-text protocol of terminal-notifier 3. + } + + if (inArray(argsList, '-list') || inArray(argsList, '-remove')) { + return stdout; + } + + const text = String(stdout).replace(/\r?\n$/, ''); + switch (text) { + case '@TIMEOUT': + return { activationType: 'timedOut' }; + case '@CLOSED': + return { activationType: 'closed' }; + case '@ACTIONCLICKED': + return { activationType: 'contentsClicked' }; + } + + if (inArray(argsList, '-reply')) { + return { activationType: 'replied', activationValue: text }; + } + if (inArray(argsList, '-action')) { + return { activationType: 'actionClicked', activationValue: text }; + } + return stdout; +} +module.exports.parseMacResponse = parseMacResponse; + +/** + * UNUserNotificationCenter (terminal-notifier >= 3) refuses to ask for + * notification permission for an app bundle LaunchServices has never seen, + * failing with "Notifications are not allowed for this application". A bundle + * that lives inside node_modules is exactly that, so register it once. + */ +const LSREGISTER = + '/System/Library/Frameworks/CoreServices.framework/Frameworks/' + + 'LaunchServices.framework/Support/lsregister'; + +module.exports.isMacNotAuthorizedError = function (error, stderr) { + return ( + !!error && + error.code === MAC_EXIT_NOT_AUTHORIZED && + /not allowed for this application/i.test(String(stderr || error.message)) + ); +}; + +module.exports.registerMacNotifier = function (notifier, cb) { + const match = /^(.*\.app)\/Contents\/MacOS\//.exec(notifier); + if (!match) return cb(new Error('Not an app bundle: ' + notifier)); + cp.execFile(LSREGISTER, ['-f', match[1]], function (error) { + cb(error || null); + }); +}; + module.exports.immediateFileCommand = function (notifier, options, cb) { if (process.env.DEBUG && process.env.DEBUG.indexOf('notifier') !== -1) { console.info('node-notifier debug info (notifier):'); @@ -234,7 +312,12 @@ module.exports.mapToMac = function (options) { } } - options.json = true; + // terminal-notifier >= 3 has no way to set a custom icon or sender: the + // UserNotifications framework always uses the sending bundle's identity. + // Both flags are accepted but only produce warnings on stderr, so drop them. + delete options.appIcon; + delete options.sender; + return options; }; @@ -507,13 +590,16 @@ module.exports.isMac = function () { return os.type() === 'Darwin'; }; -module.exports.isMountainLion = function () { +module.exports.isMojaveOrLater = function () { return ( os.type() === 'Darwin' && - semver.satisfies(garanteeSemverFormat(os.release()), '>=12.0.0') + semver.satisfies(garanteeSemverFormat(os.release()), '>=18.0.0') ); }; +// Deprecated alias, kept so existing code that stubs it keeps working. +module.exports.isMountainLion = module.exports.isMojaveOrLater; + module.exports.isWin8 = function () { return ( os.type() === 'Windows_NT' && diff --git a/notifiers/notificationcenter.js b/notifiers/notificationcenter.js index 966997b..fe9956a 100644 --- a/notifiers/notificationcenter.js +++ b/notifiers/notificationcenter.js @@ -13,7 +13,7 @@ const EventEmitter = require('events').EventEmitter; const util = require('util'); const errorMessageOsX = - 'You need Mac OS X 10.8 or above to use NotificationCenter,' + + 'You need macOS 10.14 or above to use NotificationCenter,' + ' or use Growl fallback with constructor option {withFallback: true}.'; module.exports = NotificationCenter; @@ -53,7 +53,7 @@ function notifyRaw(options, callback) { this, options, callback, - function(data) { + function (data) { if (activeId !== id) return false; if (data === 'activate') { @@ -76,9 +76,9 @@ function notifyRaw(options, callback) { return this; } - const argsList = utils.constructArgumentList(options); - if (utils.isMountainLion()) { - utils.fileCommandJson( + const argsList = constructMacArgumentList(options); + if (utils.isMojaveOrLater()) { + runNotifier( this.options.customPath || notifier, argsList, actionJackedCallback @@ -95,8 +95,53 @@ function notifyRaw(options, callback) { return this; } +/** + * terminal-notifier >= 3 reads `-action` and `-reply` straight from argv + * instead of through NSUserDefaults, so they must not be wrapped in quotes, + * `-action` may repeat (one per button) and `-reply` may stand alone. + */ +function constructMacArgumentList(options) { + let actions = options.actions; + const reply = options.reply; + delete options.actions; + delete options.reply; + + const argsList = utils.constructArgumentList(options); + + if (actions) { + actions = utils.isArray(actions) ? actions : [actions]; + actions.forEach(function (action) { + argsList.push('-action', String(action)); + }); + } + + if (typeof reply === 'string') { + argsList.push('-reply', reply); + } else if (reply) { + argsList.push('-reply'); + } + + return argsList; +} + +function runNotifier(notifierPath, argsList, callback) { + utils.fileCommandJson(notifierPath, argsList, function (error, data) { + if (!utils.isMacNotAuthorizedError(error, data)) { + return callback(error, data); + } + + // First run of the bundled binary on this machine: make LaunchServices + // aware of the app bundle so macOS can show the permission prompt, then + // try once more. + utils.registerMacNotifier(notifierPath, function (registerError) { + if (registerError) return callback(error, data); + utils.fileCommandJson(notifierPath, argsList, callback); + }); + }); +} + Object.defineProperty(NotificationCenter.prototype, 'notify', { - get: function() { + get: function () { if (!this._notify) this._notify = notifyRaw.bind(this); return this._notify; } diff --git a/package.json b/package.json index 8e097be..8af39a0 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ }, "keywords": [ "notification center", - "mac os x 10.8", + "mac os x 10.14", "notify", "terminal-notifier", "notify-send", diff --git a/scripts/update-terminal-notifier.sh b/scripts/update-terminal-notifier.sh new file mode 100755 index 0000000..bc9f3b9 --- /dev/null +++ b/scripts/update-terminal-notifier.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# Replaces the vendored macOS notifier with an official terminal-notifier +# release from https://github.com/julienXX/terminal-notifier/releases. +# +# The bundle is downloaded straight from the upstream GitHub release and +# verified against the SHA-256 recorded below, so what ends up in +# vendor/mac.noindex can be reproduced and audited by anyone. +# +# Usage: scripts/update-terminal-notifier.sh [VERSION] [SHA256] +set -euo pipefail + +VERSION="${1:-3.1.0}" +SHA256="${2:-e969d4ae20287da1ba55495ae31dcedd8e9069deb8ce4eed24f6561a5fc3e4d5}" + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +DEST="$ROOT/vendor/mac.noindex" +URL="https://github.com/julienXX/terminal-notifier/releases/download/${VERSION}/terminal-notifier-${VERSION}.zip" + +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT + +echo "Downloading $URL" +curl -fsSL "$URL" -o "$TMP/terminal-notifier.zip" + +ACTUAL="$(shasum -a 256 "$TMP/terminal-notifier.zip" | awk '{print $1}')" +if [ "$ACTUAL" != "$SHA256" ]; then + echo "SHA-256 mismatch for terminal-notifier-${VERSION}.zip" >&2 + echo " expected: $SHA256" >&2 + echo " actual: $ACTUAL" >&2 + exit 1 +fi + +unzip -q "$TMP/terminal-notifier.zip" -d "$TMP/unpacked" +if [ ! -d "$TMP/unpacked/terminal-notifier.app" ]; then + echo "terminal-notifier.app not found in the release archive" >&2 + exit 1 +fi + +rm -rf "$DEST/terminal-notifier.app" +mkdir -p "$DEST" +cp -R "$TMP/unpacked/terminal-notifier.app" "$DEST/terminal-notifier.app" + +echo "Installed terminal-notifier ${VERSION} into vendor/mac.noindex" +if command -v lipo >/dev/null 2>&1; then + echo -n "Architectures: " + lipo -archs "$DEST/terminal-notifier.app/Contents/MacOS/terminal-notifier" +fi diff --git a/test/terminal-notifier.js b/test/terminal-notifier.js index fa8325b..bed9470 100644 --- a/test/terminal-notifier.js +++ b/test/terminal-notifier.js @@ -8,20 +8,20 @@ const testUtils = require('./_test-utils'); let notifier = null; const originalUtils = utils.fileCommandJson; -const originalMacVersion = utils.isMountainLion; +const originalMacVersion = utils.isMojaveOrLater; const originalType = os.type; describe('Mac fallback', function () { - const original = utils.isMountainLion; + const original = utils.isMojaveOrLater; const originalMac = utils.isMac; afterEach(function () { - utils.isMountainLion = original; + utils.isMojaveOrLater = original; utils.isMac = originalMac; }); - it('should default to Growl notification if older Mac OSX than 10.8', function (done) { - utils.isMountainLion = function () { + it('should default to Growl notification if older macOS than 10.14', function (done) { + utils.isMojaveOrLater = function () { return false; }; utils.isMac = function () { @@ -35,7 +35,7 @@ describe('Mac fallback', function () { }); it('should not fallback to Growl notification if withFallback is false', function (done) { - utils.isMountainLion = function () { + utils.isMojaveOrLater = function () { return false; }; utils.isMac = function () { @@ -56,7 +56,7 @@ describe('terminal-notifier', function () { return 'Darwin'; }; - utils.isMountainLion = function () { + utils.isMojaveOrLater = function () { return true; }; }); @@ -67,7 +67,7 @@ describe('terminal-notifier', function () { afterEach(function () { os.type = originalType; - utils.isMountainLion = originalMacVersion; + utils.isMojaveOrLater = originalMacVersion; }); // Simulate async operation, move to end of message queue. @@ -174,9 +174,7 @@ describe('terminal-notifier', function () { '-tullball', '"notValid"', '-timeout', - '"10"', - '-json', - '"true"' + '"10"' ]; expectArgsListToBe(expected, done); @@ -206,18 +204,20 @@ describe('terminal-notifier', function () { }); }); - it('should convert list of actions to flat list', function (done) { + it('should pass each action as a separate unquoted -action flag', function (done) { const expected = [ '-title', '"title \\"message\\""', '-message', '"body \\"message\\""', - '-actions', - '"foo","bar","baz \\"foo\\" bar"', '-timeout', '"10"', - '-json', - '"true"' + '-action', + 'foo', + '-action', + 'bar', + '-action', + 'baz "foo" bar' ]; expectArgsListToBe(expected, done); @@ -239,9 +239,7 @@ describe('terminal-notifier', function () { '-message', '"Message"', '-timeout', - '"5"', - '-json', - '"true"' + '"5"' ]; expectArgsListToBe(expected, done); @@ -259,9 +257,7 @@ describe('terminal-notifier', function () { '-message', '"Message"', '-timeout', - '"10"', - '-json', - '"true"' + '"10"' ]; expectArgsListToBe(expected, done); @@ -278,24 +274,74 @@ describe('terminal-notifier', function () { }); it('should not set a default timeout if explicitly false', function (done) { + const expected = ['-title', '"Title"', '-message', '"Message"']; + + expectArgsListToBe(expected, done); + const notifier = new NotificationCenter(); + notifier.isNotifyChecked = true; + notifier.hasNotifier = true; + + notifier.notify({ + title: 'Title', + message: 'Message', + timeout: false + }); + }); + + it('should pass a bare -reply flag when reply is true', function (done) { const expected = [ '-title', '"Title"', '-message', '"Message"', - '-json', - '"true"' + '-timeout', + '"10"', + '-reply' ]; expectArgsListToBe(expected, done); const notifier = new NotificationCenter(); - notifier.isNotifyChecked = true; - notifier.hasNotifier = true; + notifier.notify({ title: 'Title', message: 'Message', reply: true }); + }); + it('should pass a reply placeholder unquoted', function (done) { + const expected = [ + '-title', + '"Title"', + '-message', + '"Message"', + '-timeout', + '"10"', + '-reply', + 'Type here' + ]; + + expectArgsListToBe(expected, done); + const notifier = new NotificationCenter(); notifier.notify({ title: 'Title', message: 'Message', - timeout: false + reply: 'Type here' + }); + }); + + it('should drop icon and sender, which terminal-notifier 3 cannot use', function (done) { + const expected = [ + '-title', + '"Title"', + '-message', + '"Message"', + '-timeout', + '"10"' + ]; + + expectArgsListToBe(expected, done); + const notifier = new NotificationCenter(); + notifier.notify({ + title: 'Title', + message: 'Message', + icon: '/tmp/icon.png', + sender: 'com.apple.Terminal' }); }); @@ -308,9 +354,7 @@ describe('terminal-notifier', function () { '-tullball', '"notValid"', '-timeout', - '"10"', - '-json', - '"true"' + '"10"' ]; expectArgsListToBe(expected, done); @@ -326,3 +370,88 @@ describe('terminal-notifier', function () { }); }); }); + +describe('terminal-notifier 3 responses', function () { + const originalFileCommand = utils.fileCommandJson; + const originalRegister = utils.registerMacNotifier; + const originalMac = utils.isMojaveOrLater; + + beforeEach(function () { + utils.isMojaveOrLater = function () { + return true; + }; + }); + + afterEach(function () { + utils.fileCommandJson = originalFileCommand; + utils.registerMacNotifier = originalRegister; + utils.isMojaveOrLater = originalMac; + }); + + it('should emit click for a clicked action button', function (done) { + utils.fileCommandJson = function (n, args, cb) { + cb(null, utils.parseMacResponse(args, 'Yes\n')); + }; + const n = new NotificationCenter(); + n.on('click', function (notifier, options, metadata) { + expect(metadata.activationValue).toBe('Yes'); + done(); + }); + n.notify({ message: 'Hello', actions: ['Yes', 'No'] }, function (err) { + expect(err).toBeNull(); + }); + }); + + it('should emit replied with the typed text', function (done) { + utils.fileCommandJson = function (n, args, cb) { + cb(null, utils.parseMacResponse(args, 'Sure thing\n')); + }; + const n = new NotificationCenter(); + n.on('replied', function (notifier, options, metadata) { + expect(metadata.activationValue).toBe('Sure thing'); + done(); + }); + n.notify({ message: 'Hello', reply: true }); + }); + + it('should emit timeout for @TIMEOUT', function (done) { + utils.fileCommandJson = function (n, args, cb) { + cb(null, utils.parseMacResponse(args, '@TIMEOUT\n')); + }; + const n = new NotificationCenter(); + n.on('timeout', function () { + done(); + }); + n.notify({ message: 'Hello', actions: 'OK', timeout: 1 }); + }); + + it('should register the bundle with LaunchServices and retry when not authorized', function (done) { + let calls = 0; + let registered = false; + utils.fileCommandJson = function (n, args, cb) { + calls++; + if (calls === 1) { + const error = new Error( + 'Command failed: terminal-notifier\nCould not request notification permission: Notifications are not allowed for this application' + ); + error.code = 3; + return cb(error, ''); + } + cb(null, {}); + }; + utils.registerMacNotifier = function (notifierPath, cb) { + registered = true; + expect(notifierPath).toMatch( + /terminal-notifier\.app\/Contents\/MacOS\/terminal-notifier$/ + ); + cb(null); + }; + const n = new NotificationCenter(); + n.notify({ message: 'Hello' }, function (err) { + expect(err).toBeNull(); + expect(registered).toBe(true); + expect(calls).toBe(2); + done(); + }); + }); +}); diff --git a/test/utils.js b/test/utils.js index 1c7ac47..a2b2402 100644 --- a/test/utils.js +++ b/test/utils.js @@ -47,13 +47,11 @@ describe('utils', function () { ).toEqual(expected); }); - it('should map icon for notification center', function () { + it('should drop icon for notification center (unsupported by terminal-notifier 3)', function () { const expected = { title: 'Foo', message: 'Bar', - appIcon: 'foobar', - timeout: 10, - json: true + timeout: 10 }; expect( @@ -65,6 +63,36 @@ describe('utils', function () { ); }); + it('should parse terminal-notifier responses', function () { + expect( + _.parseMacResponse([], '{"activationType":"contentsClicked"}') + ).toEqual({ + activationType: 'contentsClicked' + }); + expect(_.parseMacResponse(['-action', 'Yes'], '@TIMEOUT\n')).toEqual({ + activationType: 'timedOut' + }); + expect(_.parseMacResponse(['-action', 'Yes'], '@CLOSED\n')).toEqual({ + activationType: 'closed' + }); + expect( + _.parseMacResponse(['-action', 'Yes'], '@ACTIONCLICKED\n') + ).toEqual({ + activationType: 'contentsClicked' + }); + expect(_.parseMacResponse(['-action', 'Yes'], 'Yes\n')).toEqual({ + activationType: 'actionClicked', + activationValue: 'Yes' + }); + expect(_.parseMacResponse(['-reply'], 'Hello\n')).toEqual({ + activationType: 'replied', + activationValue: 'Hello' + }); + expect(_.parseMacResponse(['-list', '"ALL"'], 'GroupID\tTitle\n')).toBe( + 'GroupID\tTitle\n' + ); + }); + it('should map icon for growl', function () { const icon = path.join(__dirname, 'fixture', 'coulson.jpg'); const iconRead = fs.readFileSync(icon); diff --git a/vendor/mac.noindex/terminal-notifier.app/Contents/Info.plist b/vendor/mac.noindex/terminal-notifier.app/Contents/Info.plist index 9e6ad8f..e624c82 100644 --- a/vendor/mac.noindex/terminal-notifier.app/Contents/Info.plist +++ b/vendor/mac.noindex/terminal-notifier.app/Contents/Info.plist @@ -2,8 +2,6 @@ - BuildMachineOSBuild - 16E195 CFBundleDevelopmentRegion en CFBundleExecutable @@ -11,7 +9,7 @@ CFBundleIconFile Terminal CFBundleIdentifier - nl.superalloy.oss.terminal-notifier + fr.julienxx.oss.terminal-notifier CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -19,45 +17,18 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.7.2 + 3.1.0 CFBundleSignature ???? - CFBundleSupportedPlatforms - - MacOSX - CFBundleVersion 17 - DTCompiler - com.apple.compilers.llvm.clang.1_0 - DTPlatformBuild - 8B62 - DTPlatformVersion - GM - DTSDKBuild - 16B2649 - DTSDKName - macosx10.12 - DTXcode - 0810 - DTXcodeBuild - 8B62 LSMinimumSystemVersion - 10.8 + 10.14 LSUIElement - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - NSHumanReadableCopyright - Copyright © 2012-2016 Eloy Durán, Julien Blanchard. All rights reserved. - NSMainNibFile - MainMenu + Copyright © 2012-2017 Eloy Durán, Julien Blanchard. All rights reserved. NSPrincipalClass NSApplication - NSUserNotificationAlertStyle - alert diff --git a/vendor/mac.noindex/terminal-notifier.app/Contents/MacOS/terminal-notifier b/vendor/mac.noindex/terminal-notifier.app/Contents/MacOS/terminal-notifier index dc1127a048fd521c90dc8507d17728ad067d2ccf..732e8840bdb9044ff34e9caab9b98e19a7255636 100755 GIT binary patch literal 274592 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