node-notifier
Version:
A Node.js module for sending notifications on native Mac, Windows (post and pre 8) and Linux (or Growl as fallback)
109 lines (108 loc) • 4.23 kB
JavaScript
import callableClass from "../lib/callableClass.js";
import utils from "../lib/utils.js";
import { vendorPath } from "../lib/vendor.js";
import Notifier$1 from "./growl.js";
import { EventEmitter } from "node:events";
// src/notifiers/notificationcenter.ts
const notifier = vendorPath("mac.noindex/terminal-notifier.app/Contents/MacOS/terminal-notifier");
const errorMessageOsX = "You need macOS 10.14 or above to use NotificationCenter, or use Growl fallback with constructor option {withFallback: true}.";
var NotificationCenter = class extends EventEmitter {
options;
/** Clears each waiting notification. Used by `clearAll`. */
_activeNotifications;
#notify;
constructor(options) {
super();
this.options = utils.clone(options || {});
this._activeNotifications = /* @__PURE__ */ new Set();
}
get notify() {
this.#notify ??= notifyRaw.bind(this);
return this.#notify;
}
/**
* Kill all running terminal-notifier processes started by this instance, so
* the application can exit without waiting for their timeouts. Callbacks of
* cleared notifications are called without an error or response.
*/
clearAll() {
for (const clear of this._activeNotifications) clear();
this._activeNotifications.clear();
}
};
const Notifier = callableClass(NotificationCenter);
let activeId = null;
function noop() {}
function notifyRaw(notification, userCallback) {
const id = {};
let options = typeof notification === "string" ? {
title: "node-notifier",
message: notification
} : utils.clone(notification || {});
activeId = id;
const callback = userCallback || noop;
if (typeof callback !== "function") throw new TypeError(`The second argument must be a function callback. You have passed ${typeof callback}`);
const actionJackedCallback = utils.actionJackerDecorator(this, options, callback, (data) => {
if (activeId !== id) return false;
if (data === "activate") return "click";
if (data === "timeout") return "timeout";
if (data === "replied") return "replied";
return false;
});
options = utils.mapToMac(options);
if (!options.message && !options.group && !options.list && !options.remove) {
callback(/* @__PURE__ */ new Error("Message, group, remove or list property is required."));
return this;
}
if (options.actions?.some((action) => String(action).startsWith("-"))) {
callback(/* @__PURE__ */ new Error("Action titles can not start with \"-\"."));
return this;
}
const argsList = constructArgumentList(options);
if (utils.isMojaveOrLater()) {
let finished = false;
let cleared = false;
const clear = () => {
cleared = true;
child.kill();
};
const child = utils.fileCommand(this.options.customPath || notifier, argsList, (err, stdout) => {
finished = true;
this._activeNotifications.delete(clear);
if (cleared) return actionJackedCallback(null);
const output = (stdout || "").trim();
if (err?.code === 6 && output === "@TIMEOUT") err = null;
if (err instanceof Error) return actionJackedCallback(err, stdout);
const response = options.list || options.remove ? stdout : parseResponse(output, options);
actionJackedCallback(err || null, response);
});
if (child && !finished) this._activeNotifications.add(clear);
return this;
}
if (this.options.withFallback) return new Notifier$1(this.options).notify(options, callback);
callback(/* @__PURE__ */ new Error(errorMessageOsX));
return this;
}
function constructArgumentList(options) {
const { actions, ...rest } = options;
const args = utils.constructArgumentList(rest);
for (const action of actions || []) args.push("-action", String(action));
return args;
}
function parseResponse(output, options) {
if (!output) return {};
if (output === "@TIMEOUT") return { activationType: "timeout" };
if (output === "@CLOSED") return { activationType: "closed" };
if (output === "@ACTIONCLICKED") return { activationType: "contentsClicked" };
if (options.actions?.includes(output)) return {
activationType: "actionClicked",
activationValue: output
};
if (options.reply !== void 0) return {
activationType: "replied",
activationValue: output
};
return {};
}
export { Notifier as default, Notifier as "module.exports" };
//# sourceMappingURL=notificationcenter.js.map