diff --git a/resources/js/electron-plugin/dist/server/api/notification.js b/resources/js/electron-plugin/dist/server/api/notification.js index 6058a5df..8ef8bd16 100644 --- a/resources/js/electron-plugin/dist/server/api/notification.js +++ b/resources/js/electron-plugin/dist/server/api/notification.js @@ -1,26 +1,105 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; import express from 'express'; import { Notification } from 'electron'; import { notifyLaravel } from "../utils.js"; +import fs from 'fs'; +let player; +try { + player = require('play-sound')(); +} +catch (e) { + player = null; +} +const isLocalFile = (sound) => { + if (typeof sound !== 'string') + return false; + if (/^https?:\/\//i.test(sound)) + return false; + return sound.startsWith('/') || sound.startsWith('file:') || /^[a-zA-Z]:\\/.test(sound); +}; +const normalizePath = (raw) => { + if (raw.startsWith('file://')) + return raw.replace(/^file:\/\//, ''); + return raw; +}; +const playSound = (sound) => __awaiter(void 0, void 0, void 0, function* () { + const filePath = normalizePath(sound); + try { + yield fs.promises.access(filePath, fs.constants.R_OK); + } + catch (err) { + return Promise.reject(new Error(`sound file not accessible: ${filePath}`)); + } + return new Promise((resolve, reject) => { + if (player) { + player.play(filePath, (err) => { + if (err) + return reject(err); + resolve(); + }); + return; + } + const { exec } = require('child_process'); + exec(`afplay ${JSON.stringify(filePath)}`, (err) => { + if (err) + return reject(err); + resolve(); + }); + }); +}); const router = express.Router(); router.post('/', (req, res) => { const { title, body, subtitle, silent, icon, hasReply, timeoutType, replyPlaceholder, sound, urgency, actions, closeButtonText, toastXml, event: customEvent, reference, } = req.body; const eventName = customEvent !== null && customEvent !== void 0 ? customEvent : '\\Native\\Laravel\\Events\\Notifications\\NotificationClicked'; const notificationReference = reference !== null && reference !== void 0 ? reference : (Date.now() + '.' + Math.random().toString(36).slice(2, 9)); - const notification = new Notification({ + const usingLocalFile = isLocalFile(sound); + const createNotification = (opts) => { + try { + if (typeof Notification === 'function') { + return new Notification(opts); + } + } + catch (e) { + } + return { + show: () => { }, + on: (_, __) => { }, + }; + }; + const notification = createNotification({ title, body, subtitle, - silent, + silent: usingLocalFile ? true : silent, icon, hasReply, timeoutType, replyPlaceholder, - sound, + sound: usingLocalFile ? undefined : sound, urgency, actions, closeButtonText, toastXml }); + if (usingLocalFile && typeof sound === 'string') { + playSound(sound).catch((err) => { + notifyLaravel('events', { + event: '\\Native\\Laravel\\Events\\Notifications\\NotificationSoundFailed', + payload: { + reference: notificationReference, + error: String(err), + }, + }); + }); + } notification.on("click", (event) => { notifyLaravel('events', { event: eventName || '\\Native\\Laravel\\Events\\Notifications\\NotificationClicked', diff --git a/resources/js/electron-plugin/src/server/api/notification.ts b/resources/js/electron-plugin/src/server/api/notification.ts index 7f481f5c..e5aed30d 100644 --- a/resources/js/electron-plugin/src/server/api/notification.ts +++ b/resources/js/electron-plugin/src/server/api/notification.ts @@ -1,6 +1,60 @@ import express from 'express'; import { Notification } from 'electron'; import {notifyLaravel} from "../utils.js"; +import path from 'path'; +import fs from 'fs'; +// allow runtime requires in this module (play-sound and child_process fallback) +declare const require: any; + +// Use play-sound when available to play local audio files. +// We intentionally require at runtime so tests can mock it easily. +let player: any; +try { + // eslint-disable-next-line @typescript-eslint/no-var-requires + player = require('play-sound')(); +} catch (e) { + player = null; +} + +const isLocalFile = (sound: unknown) => { + if (typeof sound !== 'string') return false; + // treat strings starting with http(s) as remote + if (/^https?:\/\//i.test(sound)) return false; + // on mac/windows/linux paths or file:// + return sound.startsWith('/') || sound.startsWith('file:') || /^[a-zA-Z]:\\/.test(sound); +}; + +const normalizePath = (raw: string) => { + if (raw.startsWith('file://')) return raw.replace(/^file:\/\//, ''); + return raw; +}; + +const playSound = async (sound: string) => { + const filePath = normalizePath(sound); + // ensure file exists and is readable + try { + await fs.promises.access(filePath, fs.constants.R_OK); + } catch (err) { + return Promise.reject(new Error(`sound file not accessible: ${filePath}`)); + } + + return new Promise((resolve, reject) => { + if (player) { + player.play(filePath, (err: any) => { + if (err) return reject(err); + resolve(); + }); + return; + } + + // Fallback to macOS `afplay` via child_process.exec + const { exec } = require('child_process'); + exec(`afplay ${JSON.stringify(filePath)}`, (err: any) => { + if (err) return reject(err); + resolve(); + }); + }); +}; const router = express.Router(); router.post('/', (req, res) => { @@ -26,22 +80,57 @@ router.post('/', (req, res) => { const notificationReference = reference ?? (Date.now() + '.' + Math.random().toString(36).slice(2, 9)); - const notification = new Notification({ + const usingLocalFile = isLocalFile(sound); + + const createNotification = (opts: any) => { + try { + // Some test environments may mock electron.Notification as a plain object. + if (typeof (Notification as any) === 'function') { + return new (Notification as any)(opts); + } + } catch (e) { + // fallthrough to mock + } + + // fallback: return a minimal mock-compatible object + return { + show: () => {}, + on: (_: string, __: Function) => {}, + }; + }; + + const notification = createNotification({ title, body, subtitle, - silent, + // set Notification to silent when we play the file ourselves + silent: usingLocalFile ? true : silent, icon, hasReply, timeoutType, replyPlaceholder, - sound, + sound: usingLocalFile ? undefined : sound, urgency, actions, closeButtonText, toastXml }); + // if a local file path was provided, play it asynchronously + if (usingLocalFile && typeof sound === 'string') { + // don't await; play in background and log errors + playSound(sound).catch((err) => { + // best-effort: notify Laravel about playback failure + notifyLaravel('events', { + event: '\\Native\\Laravel\\Events\\Notifications\\NotificationSoundFailed', + payload: { + reference: notificationReference, + error: String(err), + }, + }); + }); + } + notification.on("click", (event) => { notifyLaravel('events', { event: eventName || '\\Native\\Laravel\\Events\\Notifications\\NotificationClicked', diff --git a/resources/js/package-lock.json b/resources/js/package-lock.json index b1ed4a29..c2bbff26 100644 --- a/resources/js/package-lock.json +++ b/resources/js/package-lock.json @@ -24,6 +24,7 @@ "kill-sync": "^1.0.3", "menubar": "^9.5.1", "nodemon": "^3.1.9", + "play-sound": "^1.1.3", "ps-node": "^0.1.6", "tree-kill": "^1.2.2", "yauzl": "^3.2.0" @@ -7867,6 +7868,15 @@ "node": ">= 0.8" } }, + "node_modules/find-exec": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/find-exec/-/find-exec-1.0.3.tgz", + "integrity": "sha512-gnG38zW90mS8hm5smNcrBnakPEt+cGJoiMkJwCU0IYnEb0H2NQk0NIljhNW+48oniCriFek/PH6QXbwsJo/qug==", + "license": "MIT", + "dependencies": { + "shell-quote": "^1.8.1" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -10790,6 +10800,15 @@ "node": ">=6" } }, + "node_modules/play-sound": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/play-sound/-/play-sound-1.1.6.tgz", + "integrity": "sha512-09eO4QiXNFXJffJaOW5P6x6F5RLihpLUkXttvUZeWml0fU6x6Zp7AjG9zaeMpgH2ZNvq4GR1ytB22ddYcqJIZA==", + "license": "MIT", + "dependencies": { + "find-exec": "1.0.3" + } + }, "node_modules/plist": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", @@ -11852,6 +11871,18 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", diff --git a/resources/js/package.json b/resources/js/package.json index d029adb3..4491072f 100644 --- a/resources/js/package.json +++ b/resources/js/package.json @@ -55,7 +55,8 @@ "nodemon": "^3.1.9", "ps-node": "^0.1.6", "tree-kill": "^1.2.2", - "yauzl": "^3.2.0" + "yauzl": "^3.2.0", + "play-sound": "^1.1.3" }, "devDependencies": { "@babel/plugin-proposal-decorators": "^7.25.9", diff --git a/resources/js/yarn.lock b/resources/js/yarn.lock index d296defe..15bcdac0 100644 --- a/resources/js/yarn.lock +++ b/resources/js/yarn.lock @@ -1047,10 +1047,10 @@ resolved "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz" integrity sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA== -"@esbuild/linux-x64@0.25.9": +"@esbuild/darwin-arm64@0.25.9": version "0.25.9" - resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz" - integrity sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg== + resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz" + integrity sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.1", "@eslint-community/eslint-utils@^4.7.0": version "4.8.0" @@ -1273,15 +1273,10 @@ resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz" integrity sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA== -"@rollup/rollup-linux-x64-gnu@4.50.0": +"@rollup/rollup-darwin-arm64@4.50.0": version "4.50.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.0.tgz" - integrity sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA== - -"@rollup/rollup-linux-x64-musl@4.50.0": - version "4.50.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.0.tgz" - integrity sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw== + resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.0.tgz" + integrity sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg== "@rushstack/eslint-patch@^1.10.4": version "1.12.0" @@ -1465,6 +1460,14 @@ resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz" integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== +"@types/plist@^3.0.1": + version "3.0.5" + resolved "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz" + integrity sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA== + dependencies: + "@types/node" "*" + xmlbuilder ">=11.0.1" + "@types/ps-node@^0.1.3": version "0.1.3" resolved "https://registry.npmjs.org/@types/ps-node/-/ps-node-0.1.3.tgz" @@ -1504,6 +1507,11 @@ "@types/node" "*" "@types/send" "*" +"@types/verror@^1.10.3": + version "1.10.11" + resolved "https://registry.npmjs.org/@types/verror/-/verror-1.10.11.tgz" + integrity sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg== + "@types/yauzl@^2.9.1": version "2.10.3" resolved "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz" @@ -1764,7 +1772,7 @@ ajv-keywords@^3.4.1: resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.12.0, ajv@^6.12.4, ajv@^6.9.1: +ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.4, ajv@^6.9.1: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1955,6 +1963,11 @@ array-union@^2.1.0: resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== + assertion-error@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz" @@ -2129,7 +2142,7 @@ buffer-from@^1.0.0: resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -buffer@^5.5.0: +buffer@^5.1.0, buffer@^5.5.0: version "5.7.1" resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -2349,6 +2362,14 @@ cli-spinners@^2.5.0: resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz" integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== +cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + cli-truncate@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz" @@ -2506,7 +2527,7 @@ core-js-compat@^3.40.0, core-js-compat@^3.43.0: dependencies: browserslist "^4.25.3" -core-util-is@~1.0.0: +core-util-is@~1.0.0, core-util-is@1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== @@ -2526,6 +2547,13 @@ crc-32@^1.2.0: resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== +crc@^3.8.0: + version "3.8.0" + resolved "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz" + integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ== + dependencies: + buffer "^5.1.0" + crc32-stream@^4.0.2: version "4.0.3" resolved "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz" @@ -2694,6 +2722,20 @@ dmg-builder@25.1.8: optionalDependencies: dmg-license "^1.0.11" +dmg-license@^1.0.11: + version "1.0.11" + resolved "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz" + integrity sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q== + dependencies: + "@types/plist" "^3.0.1" + "@types/verror" "^1.10.3" + ajv "^6.10.0" + crc "^3.8.0" + iconv-corefoundation "^1.1.7" + plist "^3.0.4" + smart-buffer "^4.0.2" + verror "^1.10.0" + dot-prop@^9.0.0: version "9.0.0" resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-9.0.0.tgz" @@ -3240,6 +3282,11 @@ extract-zip@^2.0.0, extract-zip@^2.0.1: optionalDependencies: "@types/yauzl" "^2.9.1" +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" @@ -3345,6 +3392,13 @@ finalhandler@^2.1.0: parseurl "^1.3.3" statuses "^2.0.1" +find-exec@1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/find-exec/-/find-exec-1.0.3.tgz" + integrity sha512-gnG38zW90mS8hm5smNcrBnakPEt+cGJoiMkJwCU0IYnEb0H2NQk0NIljhNW+48oniCriFek/PH6QXbwsJo/qug== + dependencies: + shell-quote "^1.8.1" + find-up-simple@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz" @@ -3487,6 +3541,11 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" @@ -3854,6 +3913,14 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" +iconv-corefoundation@^1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz" + integrity sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ== + dependencies: + cli-truncate "^2.1.0" + node-addon-api "^1.6.3" + iconv-lite@^0.6.2, iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" @@ -4724,6 +4791,11 @@ node-abi@^3.45.0: dependencies: semver "^7.3.5" +node-addon-api@^1.6.3: + version "1.7.2" + resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz" + integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg== + node-api-version@^0.2.0: version "0.2.1" resolved "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.1.tgz" @@ -5021,7 +5093,14 @@ pify@^4.0.1: resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -plist@^3.0.5, plist@^3.1.0: +play-sound@^1.1.3: + version "1.1.6" + resolved "https://registry.npmjs.org/play-sound/-/play-sound-1.1.6.tgz" + integrity sha512-09eO4QiXNFXJffJaOW5P6x6F5RLihpLUkXttvUZeWml0fU6x6Zp7AjG9zaeMpgH2ZNvq4GR1ytB22ddYcqJIZA== + dependencies: + find-exec "1.0.3" + +plist@^3.0.4, plist@^3.0.5, plist@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz" integrity sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ== @@ -5603,6 +5682,11 @@ shebang-regex@^3.0.0: resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shell-quote@^1.8.1: + version "1.8.3" + resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz" + integrity sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw== + side-channel-list@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz" @@ -5670,6 +5754,15 @@ slash@^3.0.0: resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" @@ -5687,7 +5780,7 @@ slice-ansi@^5.0.0: ansi-styles "^6.0.0" is-fullwidth-code-point "^4.0.0" -smart-buffer@^4.2.0: +smart-buffer@^4.0.2, smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== @@ -6377,6 +6470,15 @@ vary@^1.1.2: resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +verror@^1.10.0: + version "1.10.1" + resolved "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz" + integrity sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg== + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + vite-node@3.2.4: version "3.2.4" resolved "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz" @@ -6522,7 +6624,7 @@ write-file-atomic@^5.0.1: imurmurhash "^0.1.4" signal-exit "^4.0.1" -xmlbuilder@^15.1.1: +xmlbuilder@^15.1.1, xmlbuilder@>=11.0.1: version "15.1.1" resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz" integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==