UNPKG

node-notifier

Version:

A Node.js module for sending notifications on native Mac, Windows (post and pre 8) and Linux (or Growl as fallback)

135 lines (134 loc) • 4.26 kB
import callableClass from "../lib/callableClass.js"; import utils from "../lib/utils.js"; import os from "node:os"; import fs from "node:fs"; import path from "node:path"; import { EventEmitter } from "node:events"; // src/notifiers/notifysend.ts /** * Node.js wrapper for "notify-send". */ const notifier = "notify-send"; let hasNotifier; var NotifySend = class extends EventEmitter { options; #notify; constructor(options) { super(); this.options = utils.clone(options || {}); } get notify() { this.#notify ??= notifyRaw.bind(this); return this.#notify; } }; const Notifier = callableClass(NotifySend); function noop() {} function notifyRaw(notification, userCallback) { 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 options = typeof notification === "string" ? { title: "node-notifier", message: notification } : utils.clone(notification || {}); if (!options.message) { callback(/* @__PURE__ */ new Error("Message is required.")); return this; } if (os.type() !== "Linux" && !os.type().match(/BSD$/)) { callback(/* @__PURE__ */ new Error("Only supported on Linux and *BSD systems")); return this; } if (hasNotifier === false) { callback(/* @__PURE__ */ new Error("notify-send must be installed on the system.")); return this; } if (hasNotifier || this.options.suppressOsdCheck) { doNotification.call(this, options, callback); return this; } try { hasNotifier = !!findOnPath(notifier); doNotification.call(this, options, callback); } catch (err) { hasNotifier = false; callback(err); } return this; } function findOnPath(cmd) { const dirs = (process.env.PATH || "").split(path.delimiter); for (const dir of dirs) { const file = path.join(/^".*"$/.test(dir) ? dir.slice(1, -1) : dir, cmd); try { if (fs.statSync(file).isFile()) { fs.accessSync(file, fs.constants.X_OK); return file; } } catch {} } throw Object.assign(/* @__PURE__ */ new Error(`not found: ${cmd}`), { code: "ENOENT" }); } const allowedArguments = [ "urgency", "expire-time", "icon", "category", "hint", "app-name" ]; function doNotification(options, callback) { const originalOptions = { ...options }; const actions = toActionList(options.actions); const transient = options.transient === true; delete options.actions; delete options.transient; options = utils.mapToNotifySend(options); options.title = options.title || "Node Notification:"; const initial = [options.title, options.message]; delete options.title; delete options.message; const argsList = [ ...utils.constructArgumentList(options, { keyExtra: "-", allowedArguments, noEscape: true, wrapper: "" }), ...actions.map((action, i) => `--action=${i}=${action}`), ...transient ? ["--hint=int:transient:1"] : [], "--", ...utils.constructArgumentList({}, { initial, noEscape: true, wrapper: "" }) ]; if (!actions.length) { utils.commandWithoutShell(notifier, argsList, callback); return; } const expireTime = options["expire-time"]; const start = Date.now(); const actionJackedCallback = utils.actionJackerDecorator(this, originalOptions, callback, (data) => { if (data === "activate") return "click"; if (data === "timeout") return "timeout"; return false; }); utils.commandWithoutShell(notifier, argsList, (err, stdout) => { if (err instanceof Error) return actionJackedCallback(err, stdout); const output = (stdout || "").trim(); if (/^\d+$/.test(output) && Number(output) < actions.length) return actionJackedCallback(err || null, { activationType: "actionClicked", activationValue: actions[Number(output)] }); if (String(err || "").includes("Wait timeout expired") || expireTime > 0 && Date.now() - start >= expireTime) return actionJackedCallback(null, { activationType: "timeout" }); actionJackedCallback(err || null, { activationType: "closed" }); }); } function toActionList(actions) { if (actions === void 0 || actions === null) return []; return (Array.isArray(actions) ? actions : [actions]).map(String); } export { Notifier as default, Notifier as "module.exports" }; //# sourceMappingURL=notifysend.js.map