diff --git a/.gitignore b/.gitignore index a04aa04..d7907bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .vscode/ build/ node_modules/ +*.log diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1287d6b --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +Copyright 2019 Simon Buchan + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e40ea3c --- /dev/null +++ b/README.md @@ -0,0 +1,113 @@ +# Windows Notification Icons + +Because calling it the system tray [would be wrong](https://devblogs.microsoft.com/oldnewthing/20030910-00/?p=42583). + +## Description + +Provides fairly direct access to the Win32 +[`Shell_NotifyIcon`](https://docs.microsoft.com/en-nz/windows/desktop/api/shellapi/nf-shellapi-shell_notifyiconw) +API, which allows adding an icon to the notification area, and +support for the related windows APIs to load icons and use context +(e.g. right-click) menus. + +Prebuilt as N-API (64-bit only for now, sorry), meaning you +don't need Visual Studio or build tools installed on your +development machine or CI server. + +Note that this is using the Win32 desktop APIs, so you don't +need to be running under the UWP (Windows Store) model, +and thus has odd limitations like requiring an icon in the +notification area to show a notification message, and not +supporting notification actions (e.g. buttons). + +## Usage + +The [type definitions](index.d.ts) have fuller jsdoc descriptions, +but as a basic overview: + +```js +import { NotifyIcon, Icon, Menu } from "not-the-systray"; + +// Creates an empty (blank) icon in the notification area +// that does nothing. +// Unfortunately the Windows terminology I'm exposing here is +// pretty confusing, they have "Notification icons" that have +// icons and can show notifications that also have icons. +const emptyIcon = new NotifyIcon(); +// Remove it! +emptyIcon.remove(); + +// Creates and adds an initialized icon, with a select callback. +const appIcon = new NotifyIcon({ + icon: Icon.load("my-icon.ico", Icon.small), // Notify icons should use + tooltip: "My icon from nodejs", + onSelect({ target, rightButton, mouseX, mouseY }) { + // `this` is `target` is `appIcon`. + // `rightButton` is which mouse button it was selected with, + // `mouseX and `mouseX` are the screen co-ordinates of the click. + // If selected with the keyboard, these values will be simulated. + + if (rightButton) { + handleMenu(mouseX, mouseY); + } else { + // some default action, or just show the same menu. + } + }, +}); + +// Notifications should use the size `Icon.large`. +// Icons can be loaded ahead of time to catch errors earlier, +// and save a bit of time and memory. +const notificationIcon = Icon.load("notification-icon.ico", Icon.large); +// You can also use some built-in icons, for example: +const errorIcon = Icon.load(Icon.ids.error, Icon.large); + +const toggleId = 1; +const notificationId = 2; +const submenuId = 3; + +const menu = new Menu([ + { id: toggleId, text: "Toggle item", checked: true }, + { id: notificationId, text: "Show notification" }, + { separator: true }, + { text: "Sub-menu", items: [ + { id: submenuId, text: "Sub-menu item" }, + ] } +]); + +function handleMenu(x, y) { + const id = menu.showSync(x, y); + switch (id) { + case null: + // user cancelled selection. + break; + case toggleId: { + // You can read the immediate properties (ie. not counting `items`) + // of any item by id. + const { checked } = menu.get(toggleId); + // You can update any properties of an item whenever you want, including + // `items`. + menu.update(toggleId, { checked: !checked }); + break; + } + case notificationId: + // The win32 (non-UWP) model of notifications are as + // a property of a notification area icon, and can't + // be displayed without one (remember the old balloons?) + // Updating with a new notification will remove the + // previous one. + appIcon.update({ + notification: { + icon: notificationIcon, + title: "Hello, world", + text: "A notification from nodejs", + }, + }); + break; + case submenuId: + // Ids work in submenus too. + console.log("Selected the submenu item"); + break; + } +} +``` diff --git a/binding.gyp b/binding.gyp index cd55513..3480f0f 100644 --- a/binding.gyp +++ b/binding.gyp @@ -1,7 +1,7 @@ { "targets": [ { - "target_name": "tray", + "target_name": "notify_icon", "include_dirs": [ "src" ], @@ -14,6 +14,7 @@ "src/menu-object.cc", "src/notify-icon.cc", "src/notify-icon-object.cc", + "src/reg-icon-stream.cc", "src/parse_guid.cc", "src/module.cc" ], diff --git a/icon-stream.js b/icon-stream.js new file mode 100644 index 0000000..bfb8944 --- /dev/null +++ b/icon-stream.js @@ -0,0 +1,102 @@ +let native; +try { + native = require('./build/Release/notify_icon.node'); +} catch (e) { + native = require('./build/Debug/notify_icon.node'); +} + +module.exports = { printIconStream }; + +// For debugging icon registration, see +// https://github.com/electron/electron/issues/2468#issuecomment-142684129 +function printIconStream() { + /** @type Buffer */ + const buffer = native.icon_stream; + // const headerSize = buffer.readUInt32LE(0); + // buffer.readUInt32LE(4); = 7 + // buffer.readUInt16LE(8); = 1 + // buffer.readUInt16LE(10); = 1 + const itemCount = buffer.readUInt32LE(12); + const itemListOffset = buffer.readUInt32LE(16); + + const itemSize = 1640; + + const pathStart = 0; + const pathEnd = pathStart + 2 * 260; + const tipStart = pathEnd + 16; + const tipEnd = tipStart + 2 * 260; // 260 seems to be closer than the NOTIFYITEMDATA size of 128 + const infoStart = tipEnd + 60; + const infoEnd = infoStart + 2 * 260; + + console.log("header data = %s", buffer.slice(0, itemListOffset).toString("hex")); + + for (let itemIndex = 0; itemIndex < itemCount; itemIndex++) { + const itemOffset = itemListOffset + itemIndex * itemSize; + const itemData = buffer.slice(itemOffset, itemOffset + itemSize); + console.group('Item %d/%d at 0x%s', itemIndex, itemCount, itemOffset.toString(16)); + + const [path, pathTrailing] = readUTF16(itemData, pathStart, pathEnd); + console.log("path = %O", stringRot(path, 13)); + if (pathTrailing.some(b => b != 0)) { + console.log(" trailing = %s", pathTrailing.toString("hex")); + } + + console.group("? = %s", itemData.slice(pathEnd, pathEnd + 12).toString("hex")); + console.log("? = %O", itemData.readInt32LE(pathEnd)); + console.log("? = %O", itemData.readInt32LE(pathEnd + 4)); + console.log("? = %O", itemData.readInt32LE(pathEnd + 8)); + console.groupEnd(); + + console.log("last seen = %d-%d", itemData.readUInt16LE(pathEnd + 12), itemData.readUInt16LE(pathEnd + 14)); + + const [tip, tipTrailing] = readUTF16(itemData, tipStart, tipEnd); + console.log("tooltip = %O", stringRot(tip, 13)); + if (tipTrailing.some(b => b != 0)) { + console.log(" trailing = %s", tipTrailing.toString("hex")); + } + console.log("? = %O", itemData.readInt32LE(tipEnd)); + console.log("? = %O", itemData.readInt32LE(tipEnd + 4)); + console.log("order? = %O", itemData.readInt32LE(tipEnd + 8)); + console.log("? = %s", itemData.slice(tipEnd + 12, tipEnd + 40).toString("hex")); + console.log("? = %s", itemData.slice(tipEnd + 40, infoStart).toString("hex")); + + const [info, infoTrailing] = readUTF16(itemData, infoStart, infoEnd); + console.log("info? = %O", stringRot(info, 13)); + console.log("? = %s", infoTrailing.slice(0, 4).toString("hex")); + const [info2, info2Trailing] = readUTF16(infoTrailing, 4); + console.log("? = %O", stringRot(info2, 13)); + if (info2Trailing.some(b => b != 0)) { + console.log(" trailing = %s", info2Trailing.toString("hex")); + } + + console.log("? = %O", itemData.readUInt32LE(infoEnd)); + console.groupEnd(); + } + + console.log("trailer data = %s", buffer.slice(itemListOffset + itemCount * itemSize).toString("hex")); +} + +function stringRot(value, rot) { + const codes = Array(value.length); + for (let i = 0; i != value.length; i++) { + const code = value.charCodeAt(i); + if (65 <= code && code <= 90) { + codes[i] = (code - 65 + rot) % 26 + 65; + } else if (97 <= code && code <= 122) { + codes[i] = (code - 97 + rot) % 26 + 97; + } else { + codes[i] = code; + } + } + return String.fromCharCode(...codes); +} + +function readUTF16(buffer, offset = 0, bufferEnd = buffer.length) { + let end = offset; + while (end < bufferEnd && buffer.readUInt16LE(end)) { + end += 2; + } + const value = buffer.slice(offset, end).toString('utf16le'); + const trailing = buffer.slice(end + 2, bufferEnd); + return [value, trailing]; +} \ No newline at end of file diff --git a/index.js b/index.js index d25af2d..960cdc5 100644 --- a/index.js +++ b/index.js @@ -1,105 +1,13 @@ let native; try { - native = require('./build/Release/tray.node'); + native = require('./build/Release/notify_icon.node'); } catch (e) { - native = require('./build/Debug/tray.node'); + native = require('./build/Debug/notify_icon.node'); } const { NotifyIcon, Icon, Menu } = native; -module.exports = { NotifyIcon, Icon, Menu, printIconStream }; - -function printIconStream() { - /** @type Buffer */ - const buffer = native.icon_stream; - // const headerSize = buffer.readUInt32LE(0); - // buffer.readUInt32LE(4); = 7 - // buffer.readUInt16LE(8); = 1 - // buffer.readUInt16LE(10); = 1 - const itemCount = buffer.readUInt32LE(12); - const itemListOffset = buffer.readUInt32LE(16); - - const itemSize = 1640; - - const pathStart = 0; - const pathEnd = pathStart + 2 * 260; - const tipStart = pathEnd + 16; - const tipEnd = tipStart + 2 * 260; // 260 seems to be closer than the NOTIFYITEMDATA size of 128 - const infoStart = tipEnd + 60; - const infoEnd = infoStart + 2 * 260; - - console.log("header data = %s", buffer.slice(0, itemListOffset).toString("hex")); - - for (let itemIndex = 0; itemIndex < itemCount; itemIndex++) { - const itemOffset = itemListOffset + itemIndex * itemSize; - const itemData = buffer.slice(itemOffset, itemOffset + itemSize); - console.group('Item %d/%d at 0x%s', itemIndex, itemCount, itemOffset.toString(16)); - - const [path, pathTrailing] = readUTF16(itemData, pathStart, pathEnd); - console.log("path = %O", stringRot(path, 13)); - if (pathTrailing.some(b => b != 0)) { - console.log(" trailing = %s", pathTrailing.toString("hex")); - } - - console.group("? = %s", itemData.slice(pathEnd, pathEnd + 12).toString("hex")); - console.log("? = %O", itemData.readInt32LE(pathEnd)); - console.log("? = %O", itemData.readInt32LE(pathEnd + 4)); - console.log("? = %O", itemData.readInt32LE(pathEnd + 8)); - console.groupEnd(); - - console.log("last seen = %d-%d", itemData.readUInt16LE(pathEnd + 12), itemData.readUInt16LE(pathEnd + 14)); - - const [tip, tipTrailing] = readUTF16(itemData, tipStart, tipEnd); - console.log("tooltip = %O", stringRot(tip, 13)); - if (tipTrailing.some(b => b != 0)) { - console.log(" trailing = %s", tipTrailing.toString("hex")); - } - console.log("? = %O", itemData.readInt32LE(tipEnd)); - console.log("? = %O", itemData.readInt32LE(tipEnd + 4)); - console.log("order? = %O", itemData.readInt32LE(tipEnd + 8)); - console.log("? = %s", itemData.slice(tipEnd + 12, tipEnd + 40).toString("hex")); - console.log("? = %s", itemData.slice(tipEnd + 40, infoStart).toString("hex")); - - const [info, infoTrailing] = readUTF16(itemData, infoStart, infoEnd); - console.log("info? = %O", stringRot(info, 13)); - console.log("? = %s", infoTrailing.slice(0, 4).toString("hex")); - const [info2, info2Trailing] = readUTF16(infoTrailing, 4); - console.log("? = %O", stringRot(info2, 13)); - if (info2Trailing.some(b => b != 0)) { - console.log(" trailing = %s", info2Trailing.toString("hex")); - } - - console.log("? = %O", itemData.readUInt32LE(infoEnd)); - console.groupEnd(); - } - - console.log("trailer data = %s", buffer.slice(itemListOffset + itemCount * itemSize).toString("hex")); -} - -function stringRot(value, rot) { - const codes = Array(value.length); - for (let i = 0; i != value.length; i++) { - const code = value.charCodeAt(i); - if (65 <= code && code <= 90) { - codes[i] = (code - 65 + rot) % 26 + 65; - } else if (97 <= code && code <= 122) { - codes[i] = (code - 97 + rot) % 26 + 97; - } else { - codes[i] = code; - } - } - return String.fromCharCode(...codes); -} - -function readUTF16(buffer, offset = 0, bufferEnd = buffer.length) { - let end = offset; - while (end < bufferEnd && buffer.readUInt16LE(end)) { - end += 2; - } - const value = buffer.slice(offset, end).toString('utf16le'); - const trailing = buffer.slice(end + 2, bufferEnd); - return [value, trailing]; -} +module.exports = { NotifyIcon, Icon, Menu }; Object.defineProperties(Menu, { createTemplate: { value: createMenuTemplate, enumerable: true }, diff --git a/package.json b/package.json index 39e77ad..dc9b0a4 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,43 @@ { - "name": "@simonbuchan/tray", - "private": true, - "gypfile": false, + "name": "not-the-systray", + "version": "0.1.0", + "license": "MIT", + "homepage": "https://github.com/simonbuchan/node-not-the-systray", + "repository": { + "type": "git", + "url": "https://github.com/simonbuchan/node-not-the-systray.git" + }, + "keywords": [ + "windows", + "icon", + "notify", + "notification", + "systray", + "system tray", + "tray", + "napi" + ], + "main": "index.js", + "types": "index.d.ts", "files": [ "index.js", - "inded.d.ts", - "build/Release/tray.node" + "index.d.ts", + "build/Release/notify_icon.node" ], "scripts": { - "install": "echo using pre-built", - "rebuild": "node-gyp rebuild", - "build": "node-gyp build --silent", - "test": "ts-node -P test/tsconfig.json test/index.ts" + "prepublishOnly": "node-gyp rebuild --release", + "install": "echo Using prebuilt binary", + "clean": "node-gyp clean --silent", + "rebuild": "node-gyp rebuild --silent", + "build": "node-gyp build --silent" + }, + "dependencies": { + "@types/node": ">= 8.0.0" }, "devDependencies": { - "@types/node": "^8.0.0", - "node-gyp": "^3.8.0", - "typescript": "~3.3.3333", - "ts-node": "^8.0.3" - } + "node-gyp": "^3.8.0" + }, + "os": [ + "win32" + ] } \ No newline at end of file diff --git a/src/module.cc b/src/module.cc index c1faa16..2b36e74 100644 --- a/src/module.cc +++ b/src/module.cc @@ -1,75 +1,9 @@ -#include -#include - #include "data.hh" #include "icon-object.hh" #include "menu-object.hh" #include "napi/napi.hh" #include "notify-icon-object.hh" - -// https://gist.github.com/paulcbetts/c4e3412262324b551dda -struct IconStreams { - struct item_t { - wchar_t exe_path[MAX_PATH]; - int32_t unknown1; - int32_t unknown2; - }; - - int32_t header_size; - int32_t unknown1; - int16_t unknown2; - int16_t unknown3; - int32_t count; - int32_t items_offset; - - item_t items[1]; -}; - -constexpr auto icon_stream_key = - L"Software\\Classes\\Local Settings\\Software\\" - L"Microsoft\\Windows\\CurrentVersion\\TrayNotify"; -constexpr auto icon_stream_value = L"IconStreams"; - -napi_value get_icon_stream(napi_env env, napi_callback_info info) { - DWORD size = 0; - if (auto error = - RegGetValueW(HKEY_CURRENT_USER, icon_stream_key, icon_stream_value, - RRF_RT_REG_BINARY, nullptr, nullptr, &size); - error) { - napi_throw_win32_error(env, "RegGetValueW", error); - return nullptr; - } - - void* data = nullptr; - napi_value result = nullptr; - NAPI_THROW_RETURN_NULL_IF_NOT_OK( - env, napi_create_buffer(env, size, &data, &result)); - - if (auto error = - RegGetValueW(HKEY_CURRENT_USER, icon_stream_key, icon_stream_value, - RRF_RT_REG_BINARY, nullptr, data, &size); - error) { - napi_throw_win32_error(env, "RegGetValueW", error); - return nullptr; - } - - return result; -} - -napi_value set_icon_stream(napi_env env, napi_callback_info info) { - napi_buffer_info value; - NAPI_RETURN_NULL_IF_NOT_OK(napi_get_required_args(env, info, &value)); - - if (auto error = - RegSetKeyValueW(HKEY_CURRENT_USER, icon_stream_key, icon_stream_value, - REG_BINARY, value.data, value.size); - error) { - napi_throw_win32_error(env, "RegSetKeyValueW", error); - return nullptr; - } - - return nullptr; -} +#include "reg-icon-stream.hh" NAPI_MODULE_INIT() { EnvData* env_data; @@ -92,8 +26,7 @@ NAPI_MODULE_INIT() { env, napi_define_properties( env, exports, { - napi_getter_setter_property("icon_stream", get_icon_stream, - set_icon_stream), + icon_stream_property(), napi_value_property("NotifyIcon", notify_icon_constructor), napi_value_property("Menu", menu_constructor), napi_value_property("Icon", icon_constructor), diff --git a/src/reg-icon-stream.cc b/src/reg-icon-stream.cc new file mode 100644 index 0000000..65cb2d8 --- /dev/null +++ b/src/reg-icon-stream.cc @@ -0,0 +1,74 @@ +#include "reg-icon-stream.hh" + +#include "napi/napi.hh" + +#include + +// https://gist.github.com/paulcbetts/c4e3412262324b551dda +struct IconStreams { + struct item_t { + wchar_t exe_path[MAX_PATH]; + int32_t unknown1; + int32_t unknown2; + }; + + int32_t header_size; + int32_t unknown1; + int16_t unknown2; + int16_t unknown3; + int32_t count; + int32_t items_offset; + + item_t items[1]; +}; + +constexpr auto icon_stream_key = + L"Software\\Classes\\Local Settings\\Software\\" + L"Microsoft\\Windows\\CurrentVersion\\TrayNotify"; +constexpr auto icon_stream_value = L"IconStreams"; + +static napi_value get_icon_stream(napi_env env, napi_callback_info info) { + DWORD size = 0; + if (auto error = + RegGetValueW(HKEY_CURRENT_USER, icon_stream_key, icon_stream_value, + RRF_RT_REG_BINARY, nullptr, nullptr, &size); + error) { + napi_throw_win32_error(env, "RegGetValueW", error); + return nullptr; + } + + void* data = nullptr; + napi_value result = nullptr; + NAPI_THROW_RETURN_NULL_IF_NOT_OK( + env, napi_create_buffer(env, size, &data, &result)); + + if (auto error = + RegGetValueW(HKEY_CURRENT_USER, icon_stream_key, icon_stream_value, + RRF_RT_REG_BINARY, nullptr, data, &size); + error) { + napi_throw_win32_error(env, "RegGetValueW", error); + return nullptr; + } + + return result; +} + +static napi_value set_icon_stream(napi_env env, napi_callback_info info) { + napi_buffer_info value; + NAPI_RETURN_NULL_IF_NOT_OK(napi_get_required_args(env, info, &value)); + + if (auto error = + RegSetKeyValueW(HKEY_CURRENT_USER, icon_stream_key, icon_stream_value, + REG_BINARY, value.data, value.size); + error) { + napi_throw_win32_error(env, "RegSetKeyValueW", error); + return nullptr; + } + + return nullptr; +} + +napi_property_descriptor icon_stream_property() { + return napi_getter_setter_property("icon_stream", get_icon_stream, + set_icon_stream); +} diff --git a/src/reg-icon-stream.hh b/src/reg-icon-stream.hh new file mode 100644 index 0000000..0821fcb --- /dev/null +++ b/src/reg-icon-stream.hh @@ -0,0 +1,5 @@ +#pragma once + +#include "napi/props.hh" + +napi_property_descriptor icon_stream_property(); diff --git a/test/index.ts b/test/index.ts index 264be02..c6fd464 100644 --- a/test/index.ts +++ b/test/index.ts @@ -1,4 +1,4 @@ -import { NotifyIcon, Icon, Menu } from "../"; +import { NotifyIcon, Icon, Menu } from "not-the-systray"; class TestError extends Error { name = 'TestError'; diff --git a/test/package.json b/test/package.json new file mode 100644 index 0000000..67f424a --- /dev/null +++ b/test/package.json @@ -0,0 +1,16 @@ +{ + "name": "napi-notify-icon-test", + "private": true, + "scripts": { + "start": "ts-node index.ts", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "not-the-systray": "link:.." + }, + "devDependencies": { + "@types/node": "^8.0.0", + "typescript": "~3.3.3333", + "ts-node": "^8.0.3" + } +} \ No newline at end of file diff --git a/test/tsconfig.json b/test/tsconfig.json index 08bcb46..836675a 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "moduleResolution": "node", "target": "esnext", "noEmit": true, "strict": true diff --git a/test/yarn.lock b/test/yarn.lock new file mode 100644 index 0000000..4884984 --- /dev/null +++ b/test/yarn.lock @@ -0,0 +1,71 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/node@>= 8.0.0": + version "11.11.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.4.tgz#8808bd5a82bbf6f5d412eff1c228d178e7c24bb3" + integrity sha512-02tIL+QIi/RW4E5xILdoAMjeJ9kYq5t5S2vciUdFPXv/ikFTb0zK8q9vXkg4+WAJuYXGiVT1H28AkD2C+IkXVw== + +"@types/node@^8.0.0": + version "8.10.44" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.44.tgz#b00cf3595c6a3d75740af9768739a8125053a5a9" + integrity sha512-HY3SK7egERHGUfY8p6ztXIEQWcIPHouYhCGcLAPQin7gE2G/fALFz+epnMwcxKUS6aKqTVoAFdi+t1llQd3xcw== + +arg@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.0.tgz#583c518199419e0037abb74062c37f8519e575f0" + integrity sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg== + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +diff@^3.1.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +make-error@^1.1.1: + version "1.3.5" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" + integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== + +"not-the-systray@link:..": + version "0.0.0" + uid "" + +source-map-support@^0.5.6: + version "0.5.11" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.11.tgz#efac2ce0800355d026326a0ca23e162aeac9a4e2" + integrity sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +ts-node@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.0.3.tgz#aa60b836a24dafd8bf21b54766841a232fdbc641" + integrity sha512-2qayBA4vdtVRuDo11DEFSsD/SFsBXQBRZZhbRGSIkmYmVkWjULn/GGMdG10KVqkaGndljfaTD8dKjWgcejO8YA== + dependencies: + arg "^4.1.0" + diff "^3.1.0" + make-error "^1.1.1" + source-map-support "^0.5.6" + yn "^3.0.0" + +typescript@~3.3.3333: + version "3.3.4000" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.4000.tgz#76b0f89cfdbf97827e1112d64f283f1151d6adf0" + integrity sha512-jjOcCZvpkl2+z7JFn0yBOoLQyLoIkNZAs/fYJkUG6VKy6zLPHJGfQJYFHzibB6GJaF/8QrcECtlQ5cpvRHSMEA== + +yn@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.0.0.tgz#0073c6b56e92aed652fbdfd62431f2d6b9a7a091" + integrity sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q== diff --git a/yarn.lock b/yarn.lock index 27e93c0..e8a374b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^8.0.0": - version "8.10.44" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.44.tgz#b00cf3595c6a3d75740af9768739a8125053a5a9" - integrity sha512-HY3SK7egERHGUfY8p6ztXIEQWcIPHouYhCGcLAPQin7gE2G/fALFz+epnMwcxKUS6aKqTVoAFdi+t1llQd3xcw== +"@types/node@>= 8.0.0": + version "11.11.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.4.tgz#8808bd5a82bbf6f5d412eff1c228d178e7c24bb3" + integrity sha512-02tIL+QIi/RW4E5xILdoAMjeJ9kYq5t5S2vciUdFPXv/ikFTb0zK8q9vXkg4+WAJuYXGiVT1H28AkD2C+IkXVw== abbrev@1: version "1.1.1" @@ -45,11 +45,6 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" -arg@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.0.tgz#583c518199419e0037abb74062c37f8519e575f0" - integrity sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg== - asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" @@ -104,11 +99,6 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -158,11 +148,6 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= -diff@^3.1.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== - ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -365,11 +350,6 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -make-error@^1.1.1: - version "1.3.5" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" - integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== - mime-db@~1.38.0: version "1.38.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad" @@ -582,19 +562,6 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= -source-map-support@^0.5.6: - version "0.5.11" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.11.tgz#efac2ce0800355d026326a0ca23e162aeac9a4e2" - integrity sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - sshpk@^1.7.0: version "1.16.1" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" @@ -665,17 +632,6 @@ tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" -ts-node@^8.0.3: - version "8.0.3" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.0.3.tgz#aa60b836a24dafd8bf21b54766841a232fdbc641" - integrity sha512-2qayBA4vdtVRuDo11DEFSsD/SFsBXQBRZZhbRGSIkmYmVkWjULn/GGMdG10KVqkaGndljfaTD8dKjWgcejO8YA== - dependencies: - arg "^4.1.0" - diff "^3.1.0" - make-error "^1.1.1" - source-map-support "^0.5.6" - yn "^3.0.0" - tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -688,11 +644,6 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -typescript@~3.3.3333: - version "3.3.3333" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3333.tgz#171b2c5af66c59e9431199117a3bcadc66fdcfd6" - integrity sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw== - uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" @@ -737,8 +688,3 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -yn@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.0.0.tgz#0073c6b56e92aed652fbdfd62431f2d6b9a7a091" - integrity sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q==