From 7b8eb623b99f1f4d1d274bb9bf63184afbabd80e Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Sun, 11 Aug 2019 20:59:52 -0500 Subject: [PATCH 01/74] Add beaker.browser.openSidebar --- web-apis/fg/beaker.js | 1 + web-apis/manifests/internal/browser.js | 1 + 2 files changed, 2 insertions(+) diff --git a/web-apis/fg/beaker.js b/web-apis/fg/beaker.js index 4ad82454..0c3e70b0 100644 --- a/web-apis/fg/beaker.js +++ b/web-apis/fg/beaker.js @@ -107,6 +107,7 @@ exports.setup = function (rpc) { beaker.browser.getBuiltinFavicon = beakerBrowserRPC.getBuiltinFavicon beaker.browser.uploadFavicon = beakerBrowserRPC.uploadFavicon beaker.browser.imageToIco = beakerBrowserRPC.imageToIco + beaker.browser.openSidebar = beakerBrowserRPC.openSidebar beaker.browser.toggleSidebar = beakerBrowserRPC.toggleSidebar beaker.browser.toggleLiveReloading = beakerBrowserRPC.toggleLiveReloading beaker.browser.setWindowDimensions = beakerBrowserRPC.setWindowDimensions diff --git a/web-apis/manifests/internal/browser.js b/web-apis/manifests/internal/browser.js index 402f2adb..93b83984 100644 --- a/web-apis/manifests/internal/browser.js +++ b/web-apis/manifests/internal/browser.js @@ -30,6 +30,7 @@ module.exports = { getResourceContentType: 'sync', + openSidebar: 'promise', toggleSidebar: 'promise', toggleLiveReloading: 'promise', setWindowDimensions: 'promise', From 736072341fae5a833b471e3e3df18d551bd072b6 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Tue, 13 Aug 2019 09:53:04 -0500 Subject: [PATCH 02/74] Allow writes via DatArchive to unsaved archives --- web-apis/bg/dat-archive.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/web-apis/bg/dat-archive.js b/web-apis/bg/dat-archive.js index 239066b2..a3aa0f8c 100644 --- a/web-apis/bg/dat-archive.js +++ b/web-apis/bg/dat-archive.js @@ -582,11 +582,6 @@ async function assertWritePermission (archive, sender) { throw new ArchiveNotWritableError() } - // ensure we havent deleted the archive - if (!details.userSettings.isSaved) { - throw new ArchiveNotWritableError('This archive has been deleted. Restore it to continue making changes.') - } - // beaker: always allowed if (sender.getURL().startsWith('beaker:')) { return true From 88f90186cac80c7643b70da26cd1b491db0ce5bd Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 15 Aug 2019 13:39:51 -0500 Subject: [PATCH 03/74] Bump package-lock.json --- package-lock.json | 103 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index d891427f..195502a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,9 +45,9 @@ "integrity": "sha512-6BmYWSBea18+tSjjSC3QIyV93ZKAeNWGM7R6aYt1ryTZXrlHF+QLV0G2yV0viEGVyRkyQsWfMoJ0k/YghBX5sQ==" }, "@types/node": { - "version": "12.6.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.9.tgz", - "integrity": "sha512-+YB9FtyxXGyD54p8rXwWaN1EWEyar5L58GlGWgtH2I9rGmLGBQcw63+0jw+ujqVavNuO47S1ByAjm9zdHMnskw==", + "version": "12.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.1.tgz", + "integrity": "sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==", "optional": true }, "abbrev": { @@ -606,6 +606,31 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz", "integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==" }, + "chrome-dgram": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/chrome-dgram/-/chrome-dgram-3.0.2.tgz", + "integrity": "sha512-Ay741EHF/Ib18un+LUtBNK43NrabD6GOuwVaka7uUbV0gFRLEPULm2Q05YSzRNBtSrbaO4eErmDdniiy/u8Lig==", + "requires": { + "inherits": "^2.0.1", + "run-series": "^1.1.2" + } + }, + "chrome-dns": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/chrome-dns/-/chrome-dns-1.0.1.tgz", + "integrity": "sha512-HqsYJgIc8ljJJOqOzLphjAs79EUuWSX3nzZi2LNkzlw3GIzAeZbaSektC8iT/tKvLqZq8yl1GJu5o6doA4TRbg==", + "requires": { + "chrome-net": "^3.3.2" + } + }, + "chrome-net": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/chrome-net/-/chrome-net-3.3.2.tgz", + "integrity": "sha512-BHxWfA9MDnh0C1By5q1DnF1vRS7vfBi2PrqTHIIt1HA4hM6l2xkHzoazbDlZcrDrMfjNs6fojKG+ZD0JmlnNWg==", + "requires": { + "inherits": "^2.0.1" + } + }, "circular-append-file": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/circular-append-file/-/circular-append-file-1.0.1.tgz", @@ -1909,9 +1934,9 @@ "dev": true }, "graceful-fs": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", - "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==" + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.1.tgz", + "integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==" }, "har-schema": { "version": "2.0.0", @@ -1995,9 +2020,9 @@ } }, "hypercore": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/hypercore/-/hypercore-7.5.1.tgz", - "integrity": "sha512-tgololYj3O6Y0Mg6PK7EJntRu+auKSYuER2a8pVetPqnDSJ1RfAVlyVr3VmuS5W9hS0PwH4OXl4R/uVfkuNNoQ==", + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/hypercore/-/hypercore-7.6.1.tgz", + "integrity": "sha512-ZQ1HdFXa9D5cSwXiu6vldYSE5ro6OBtyWdnFr8L/U3PFDCEpIyhyLvoRTscmP+7U2U9ZYSV3NoNHjWlNPIA8Gw==", "requires": { "array-lru": "^1.1.0", "atomic-batcher": "^1.0.2", @@ -2009,7 +2034,7 @@ "flat-tree": "^1.6.0", "from2": "^2.3.0", "hypercore-crypto": "^1.0.0", - "hypercore-protocol": "^6.4.1", + "hypercore-protocol": "^6.5.0", "inherits": "^2.0.3", "inspect-custom-symbol": "^1.1.0", "last-one-wins": "^1.0.4", @@ -2054,9 +2079,9 @@ } }, "hypercore-protocol": { - "version": "6.11.1", - "resolved": "https://registry.npmjs.org/hypercore-protocol/-/hypercore-protocol-6.11.1.tgz", - "integrity": "sha512-4vyYGzSTRCfpIPnpYO/WN0VeS2oGeIrzCCwIXfz5TL2dyyHu7wF5xiigNuUfTn9n3cTOwwbH+EKsygTNsO2yfw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/hypercore-protocol/-/hypercore-protocol-6.12.0.tgz", + "integrity": "sha512-T3oy9/7QFejqJX2RGcCUU1944e5/eKbLlSz9JPTNN1QbYFJgat/r7eTyOO8SMSLUimUmQx6YBMKhgYbdKzp7Bw==", "requires": { "buffer-alloc-unsafe": "^1.0.0", "buffer-from": "^1.0.0", @@ -2475,9 +2500,9 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "jpeg-js": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.3.5.tgz", - "integrity": "sha512-hvaExqwmQDS8O9qnZAVDXGWU43Tbu1V0wMZmjROjT11jloSgGICZpscG+P6Nyi1BVAvyu2ARRx8qmEW30sxgdQ==" + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.3.6.tgz", + "integrity": "sha512-MUj2XlMB8kpe+8DJUGH/3UJm4XpI8XEgZQ+CiHDeyrGoKPdW/8FJv6ku+3UiYm5Fz3CWaL+iXmD8Q4Ap6aC1Jw==" }, "js-tokens": { "version": "3.0.2", @@ -2574,13 +2599,14 @@ } }, "k-rpc-socket": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/k-rpc-socket/-/k-rpc-socket-1.8.0.tgz", - "integrity": "sha512-f/9TynsO8YYjZ6JjNNtSSH7CJcIHcio1buy3zqByGxb/GX8AWLdL6FZEWTrN8V3/J7W4/E0ZTQQ+Jt2rVq7ELg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/k-rpc-socket/-/k-rpc-socket-1.11.1.tgz", + "integrity": "sha512-8xtA8oqbZ6v1Niryp2/g4GxW16EQh5MvrUylQoOG+zcrDff5CKttON2XUXvMwlIHq4/2zfPVFiinAccJ+WhxoA==", "requires": { "bencode": "^2.0.0", - "buffer-equals": "^1.0.4", - "safe-buffer": "^5.1.1" + "chrome-dgram": "^3.0.2", + "chrome-dns": "^1.0.0", + "chrome-net": "^3.3.2" }, "dependencies": { "bencode": { @@ -2654,9 +2680,9 @@ } }, "length-prefixed-message": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/length-prefixed-message/-/length-prefixed-message-3.0.3.tgz", - "integrity": "sha1-JFR01pq8BhTco2jcNaqAdJgqI6w=", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/length-prefixed-message/-/length-prefixed-message-3.0.4.tgz", + "integrity": "sha512-Tqyx4nggb9nkLD6p4hyIz7UiVNg5u3OnCP2h0hS/HXpheH88rsoNEgNB8xTnpPMw6zWXGZ7Cpg1zhWPlsJ0/TQ==", "requires": { "varint": "^3.0.1" }, @@ -3939,6 +3965,11 @@ "is-promise": "^2.1.0" } }, + "run-series": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.8.tgz", + "integrity": "sha512-+GztYEPRpIsQoCSraWHDBs9WVy4eVME16zhOtDB4H9J4xN0XRhknnmLOl+4gRgZtu8dpp9N/utSPjKH/xmDzXg==" + }, "rusha": { "version": "0.8.13", "resolved": "https://registry.npmjs.org/rusha/-/rusha-0.8.13.tgz", @@ -3983,9 +4014,9 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "scoped-fs": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/scoped-fs/-/scoped-fs-1.3.0.tgz", - "integrity": "sha512-aH9/73pyOAuO1x5YDf7kFogD7MMLsrADRtCcKHC7fD+o7IKwzpVxgbWB6YZyCIWxfTI/+TLCw/rHMcj3B4jXdQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/scoped-fs/-/scoped-fs-1.4.1.tgz", + "integrity": "sha512-7I9UC2eECQg1myIaDyL18j+05FjX11IkuEhkUZ0XzgJGYrkfQ1xxm6dKW0MGomGkaHMamf14uNTbNc+kvuqEFA==", "requires": { "recursive-watch": "^1.1.1" } @@ -4202,14 +4233,22 @@ } }, "sodium-native": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-2.4.3.tgz", - "integrity": "sha512-UCj3G++buo7HFADLMXyG+K7trEl6h17lde/2Sd3Al9ozcfPIQyKohmVqDncHY7ZggWkhzdwHKyDnlFWFQHZ5pg==", + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-2.4.6.tgz", + "integrity": "sha512-Ro9lhTjot8M01nwKLXiqLSmjR7B8o+Wg4HmJUjEShw/q6XPlNMzjPkA1VJKaMH8SO8fJ/sggAKVwreTaFszS2Q==", "optional": true, "requires": { "ini": "^1.3.5", - "nan": "^2.4.0", - "node-gyp-build": "^3.0.0" + "nan": "^2.14.0", + "node-gyp-build": "^4.1.0" + }, + "dependencies": { + "node-gyp-build": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.0.tgz", + "integrity": "sha512-rGLv++nK20BG8gc0MzzcYe1Nl3p3mtwJ74Q2QD0HTEDKZ6NvOFSelY6s2QBPWIHRR8h7hpad0LiwajfClBJfNg==", + "optional": true + } } }, "sodium-signatures": { From 538ef10f08d5c21b454ff36547f2f22ebdd0c576 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Wed, 10 Jul 2019 16:39:14 -0500 Subject: [PATCH 04/74] WIP - move to the new hyperdrive-daemon --- crawler/bookmarks.js | 10 +- crawler/comments.js | 10 +- crawler/discussions.js | 10 +- crawler/follows.js | 14 +- crawler/media.js | 10 +- crawler/posts.js | 10 +- crawler/reactions.js | 12 +- crawler/site-descriptions.js | 20 +- crawler/tags.js | 1 - crawler/util.js | 8 +- crawler/votes.js | 6 +- dat/assets.js | 6 +- dat/daemon.js | 173 + dat/directory-listing-page.js | 4 +- dat/library.js | 245 +- dat/protocol.js | 2 +- dbs/archives.js | 6 +- index.js | 1 - lib/zip.js | 4 +- package-lock.json | 5035 ------------------------- package.json | 4 +- users/index.js | 4 +- web-apis/bg/archives.js | 18 +- web-apis/bg/dat-archive.js | 4 +- web-apis/bg/experimental/dat-peers.js | 16 +- web-apis/bg/library.js | 4 +- 26 files changed, 318 insertions(+), 5319 deletions(-) create mode 100644 dat/daemon.js delete mode 100644 package-lock.json diff --git a/crawler/bookmarks.js b/crawler/bookmarks.js index 3c28f72b..a08cf137 100644 --- a/crawler/bookmarks.js +++ b/crawler/bookmarks.js @@ -22,7 +22,7 @@ const JSON_PATH_REGEX = /^\/data\/bookmarks\/([^/]+)\.json$/i // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * @typedef {import('./util').CrawlSourceRecord} CrawlSourceRecord * @typedef { import("./site-descriptions").SiteDescription } SiteDescription * @@ -56,7 +56,7 @@ exports.removeListener = events.removeListener.bind(events) * @description * Crawl the given site for bookmarks. * - * @param {InternalDatArchive} archive - site to crawl. + * @param {DaemonDatArchive} archive - site to crawl. * @param {CrawlSourceRecord} crawlSource - internal metadata about the crawl target. * @returns {Promise} */ @@ -258,7 +258,7 @@ const getBookmark = exports.getBookmark = async function (url) { * @description * Create a new bookmark. * - * @param {InternalDatArchive} archive - where to write the bookmark to. + * @param {DaemonDatArchive} archive - where to write the bookmark to. * @param {Object} bookmark * @param {string} bookmark.href * @param {string} bookmark.title @@ -294,7 +294,7 @@ exports.addBookmark = async function (archive, bookmark) { * @description * Update the content of an existing bookmark. * - * @param {InternalDatArchive} archive - where to write the bookmark to. + * @param {DaemonDatArchive} archive - where to write the bookmark to. * @param {string} pathname - the pathname of the bookmark. * @param {Object} bookmark * @param {string} bookmark.href @@ -328,7 +328,7 @@ exports.editBookmark = async function (archive, pathname, bookmark) { * @description * Delete an existing bookmark * - * @param {InternalDatArchive} archive - where to write the bookmark to. + * @param {DaemonDatArchive} archive - where to write the bookmark to. * @param {string} pathname - the pathname of the bookmark. * @returns {Promise} */ diff --git a/crawler/comments.js b/crawler/comments.js index ddae39ea..38d47c48 100644 --- a/crawler/comments.js +++ b/crawler/comments.js @@ -23,7 +23,7 @@ const JSON_PATH_REGEX = /^\/data\/comments\/([^/]+)\.json$/i // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * @typedef {import('./util').CrawlSourceRecord} CrawlSourceRecord * @typedef { import("./site-descriptions").SiteDescription } SiteDescription * @@ -68,7 +68,7 @@ exports.removeListener = events.removeListener.bind(events) * @description * Crawl the given site for comments. * - * @param {InternalDatArchive} archive - site to crawl. + * @param {DaemonDatArchive} archive - site to crawl. * @param {CrawlSourceRecord} crawlSource - internal metadata about the crawl target. * @returns {Promise} */ @@ -369,7 +369,7 @@ const get = exports.get = async function (url) { * @description * Create a new comment. * - * @param {InternalDatArchive} archive - where to write the comment to. + * @param {DaemonDatArchive} archive - where to write the comment to. * @param {string} topic * @param {Object} comment * @param {string} comment.replyTo @@ -403,7 +403,7 @@ exports.add = async function (archive, topic, comment) { * @description * Update the content of an existing comment. * - * @param {InternalDatArchive} archive - where to write the comment to. + * @param {DaemonDatArchive} archive - where to write the comment to. * @param {string} pathname - the pathname of the comment. * @param {Object} comment * @param {string} [comment.replyTo] @@ -446,7 +446,7 @@ exports.edit = async function (archive, pathname, comment) { * @description * Delete an existing comment * - * @param {InternalDatArchive} archive - where to write the comment to. + * @param {DaemonDatArchive} archive - where to write the comment to. * @param {string} pathname - the pathname of the comment. * @returns {Promise} */ diff --git a/crawler/discussions.js b/crawler/discussions.js index f6b7e2e0..69adc3a4 100644 --- a/crawler/discussions.js +++ b/crawler/discussions.js @@ -23,7 +23,7 @@ const JSON_PATH_REGEX = /^\/data\/discussions\/([^/]+)\.json$/i // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * @typedef {import('./util').CrawlSourceRecord} CrawlSourceRecord * @typedef { import("./site-descriptions").SiteDescription } SiteDescription * @@ -57,7 +57,7 @@ exports.removeListener = events.removeListener.bind(events) * @description * Crawl the given site for discussions. * - * @param {InternalDatArchive} archive - site to crawl. + * @param {DaemonDatArchive} archive - site to crawl. * @param {CrawlSourceRecord} crawlSource - internal metadata about the crawl target. * @returns {Promise} */ @@ -292,7 +292,7 @@ const get = exports.get = async function (url) { * @description * Create a new discussion. * - * @param {InternalDatArchive} archive - where to write the discussion to. + * @param {DaemonDatArchive} archive - where to write the discussion to. * @param {Object} discussion * @param {string} discussion.title * @param {string} discussion.body @@ -328,7 +328,7 @@ exports.add = async function (archive, discussion) { * @description * Update the content of an existing discussion. * - * @param {InternalDatArchive} archive - where to write the discussion to. + * @param {DaemonDatArchive} archive - where to write the discussion to. * @param {string} pathname - the pathname of the discussion. * @param {Object} discussion * @param {string} [discussion.title] @@ -374,7 +374,7 @@ exports.edit = async function (archive, pathname, discussion) { * @description * Delete an existing discussion * - * @param {InternalDatArchive} archive - where to write the discussion to. + * @param {DaemonDatArchive} archive - where to write the discussion to. * @param {string} pathname - the pathname of the discussion. * @returns {Promise} */ diff --git a/crawler/follows.js b/crawler/follows.js index 1ba5bdd7..1474bc2e 100644 --- a/crawler/follows.js +++ b/crawler/follows.js @@ -24,7 +24,7 @@ const JSON_PATH = '/data/follows.json' // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * @typedef {import('./util').CrawlSourceRecord} CrawlSourceRecord * @typedef {import('./site-descriptions').SiteDescription} SiteDescription * @@ -52,7 +52,7 @@ exports.removeListener = events.removeListener.bind(events) * @description * Crawl the given site for follows. * - * @param {InternalDatArchive} archive - site to crawl. + * @param {DaemonDatArchive} archive - site to crawl. * @param {CrawlSourceRecord} crawlSource - internal metadata about the crawl target. * @returns {Promise} */ @@ -245,7 +245,7 @@ const get = exports.get = async function (author, topic) { * @description * Add a follow to the given archive. * - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @param {string} topic * @param {Object} [opts] * @param {string} [opts.visibility] @@ -273,7 +273,7 @@ exports.add = async function (archive, topic, opts) { * @description * Edit a follow for the given archive. * - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @param {string} topic * @param {Object} [opts] * @param {string} [opts.visibility] @@ -298,7 +298,7 @@ exports.edit = async function (archive, topic, opts) { * @description * Remove a follow from the given archive. * - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @param {string} topic * @returns {Promise} */ @@ -335,7 +335,7 @@ function toOrigin (url) { } /** - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @returns {Promise} */ async function readFollowsFile (archive) { @@ -352,7 +352,7 @@ async function readFollowsFile (archive) { } /** - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @param {function(Object): void} updateFn * @returns {Promise} */ diff --git a/crawler/media.js b/crawler/media.js index 7d018a7a..953e139b 100644 --- a/crawler/media.js +++ b/crawler/media.js @@ -22,7 +22,7 @@ const JSON_PATH_REGEX = /^\/data\/media\/([^/]+)\.json$/i // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * @typedef {import('./util').CrawlSourceRecord} CrawlSourceRecord * @typedef { import("./site-descriptions").SiteDescription } SiteDescription * @@ -57,7 +57,7 @@ exports.removeListener = events.removeListener.bind(events) * @description * Crawl the given site for media. * - * @param {InternalDatArchive} archive - site to crawl. + * @param {DaemonDatArchive} archive - site to crawl. * @param {CrawlSourceRecord} crawlSource - internal metadata about the crawl target. * @returns {Promise} */ @@ -319,7 +319,7 @@ const get = exports.get = async function (url) { * @description * Create a new media. * - * @param {InternalDatArchive} archive - where to write the media to. + * @param {DaemonDatArchive} archive - where to write the media to. * @param {Object} media * @param {string} media.subtype * @param {string} media.href @@ -357,7 +357,7 @@ exports.add = async function (archive, media) { * @description * Update the content of an existing media. * - * @param {InternalDatArchive} archive - where to write the media to. + * @param {DaemonDatArchive} archive - where to write the media to. * @param {string} pathname - the pathname of the media. * @param {Object} media * @param {string} [media.subtype] @@ -405,7 +405,7 @@ exports.edit = async function (archive, pathname, media) { * @description * Delete an existing media * - * @param {InternalDatArchive} archive - where to write the media to. + * @param {DaemonDatArchive} archive - where to write the media to. * @param {string} pathname - the pathname of the media. * @returns {Promise} */ diff --git a/crawler/posts.js b/crawler/posts.js index d7a93f59..db1cc146 100644 --- a/crawler/posts.js +++ b/crawler/posts.js @@ -23,7 +23,7 @@ const JSON_PATH_REGEX = /^\/data\/posts\/([^/]+)\.json$/i // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * @typedef {import('./util').CrawlSourceRecord} CrawlSourceRecord * @typedef { import("./site-descriptions").SiteDescription } SiteDescription * @@ -54,7 +54,7 @@ exports.removeListener = events.removeListener.bind(events) * @description * Crawl the given site for posts. * - * @param {InternalDatArchive} archive - site to crawl. + * @param {DaemonDatArchive} archive - site to crawl. * @param {CrawlSourceRecord} crawlSource - internal metadata about the crawl target. * @returns {Promise} */ @@ -231,7 +231,7 @@ const get = exports.get = async function (url) { * @description * Create a new post. * - * @param {InternalDatArchive} archive - where to write the post to. + * @param {DaemonDatArchive} archive - where to write the post to. * @param {Object} post * @param {string} post.body * @param {string} post.visibility @@ -261,7 +261,7 @@ exports.add = async function (archive, post) { * @description * Update the content of an existing post. * - * @param {InternalDatArchive} archive - where to write the post to. + * @param {DaemonDatArchive} archive - where to write the post to. * @param {string} pathname - the pathname of the post. * @param {Object} post * @param {string} [post.body] @@ -301,7 +301,7 @@ exports.edit = async function (archive, pathname, post) { * @description * Delete an existing post * - * @param {InternalDatArchive} archive - where to write the post to. + * @param {DaemonDatArchive} archive - where to write the post to. * @param {string} pathname - the pathname of the post. * @returns {Promise} */ diff --git a/crawler/reactions.js b/crawler/reactions.js index 96920183..9256f11d 100644 --- a/crawler/reactions.js +++ b/crawler/reactions.js @@ -22,7 +22,7 @@ const JSON_PATH_REGEX = /^\/data\/reactions\/([^/]+)\.json$/i // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * @typedef {import('./util').CrawlSourceRecord} CrawlSourceRecord * * @typedef {Object} Reaction @@ -55,7 +55,7 @@ exports.removeListener = events.removeListener.bind(events) * @description * Crawl the given site for reactions. * - * @param {InternalDatArchive} archive - site to crawl. + * @param {DaemonDatArchive} archive - site to crawl. * @param {CrawlSourceRecord} crawlSource - internal metadata about the crawl target. * @returns {Promise} */ @@ -269,7 +269,7 @@ exports.tabulate = async function (topic, opts) { * @description * Create a new reaction. * - * @param {InternalDatArchive} archive - where to write the reaction to. + * @param {DaemonDatArchive} archive - where to write the reaction to. * @param {string} topic * @param {string} emoji * @returns {Promise} @@ -293,7 +293,7 @@ exports.add = async function (archive, topic, emoji) { * @description * Delete an existing reaction * - * @param {InternalDatArchive} archive - where to write the reaction to. + * @param {DaemonDatArchive} archive - where to write the reaction to. * @param {string} topic * @param {string} emoji * @returns {Promise} @@ -315,7 +315,7 @@ exports.remove = async function (archive, topic, emoji) { // = /** - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @param {string} pathname * @returns {Promise} */ @@ -337,7 +337,7 @@ async function readReactionFile (archive, pathname) { } /** - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @param {string} pathname * @param {string} topic * @param {string|boolean} addEmoji diff --git a/crawler/site-descriptions.js b/crawler/site-descriptions.js index 6011815f..c88c1259 100644 --- a/crawler/site-descriptions.js +++ b/crawler/site-descriptions.js @@ -24,7 +24,7 @@ const JSON_PATH_REGEX = /^\/(dat\.json|data\/known-sites\/([^/]+)\/dat\.json)$/i // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * @typedef {import('./util').CrawlSourceRecord} CrawlSourceRecord * * @typedef {Object} SiteDescription @@ -55,7 +55,7 @@ exports.removeListener = events.removeListener.bind(events) * @description * Crawl the given site for site descriptions. * - * @param {InternalDatArchive} archive - site to crawl. + * @param {DaemonDatArchive} archive - site to crawl. * @param {CrawlSourceRecord} crawlSource - internal metadata about the crawl target. * @returns {Promise} */ @@ -247,8 +247,8 @@ exports.getBest = async function ({subject, author} = {}) { * @description * Capture a site description into the archive's known-sites cache. * - * @param {InternalDatArchive} archive - where to write the capture to. - * @param {(InternalDatArchive|string)} subject - which archive to capture. + * @param {DaemonDatArchive} archive - where to write the capture to. + * @param {(DaemonDatArchive|string)} subject - which archive to capture. * @returns Promise */ exports.capture = async function (archive, subject) { @@ -289,8 +289,8 @@ exports.capture = async function (archive, subject) { * @description * Delete a captured site description in the given archive's known-sites cache. * - * @param {InternalDatArchive} archive - where to remove the capture from. - * @param {(InternalDatArchive|string)} subject - which archive's capture to remove. + * @param {DaemonDatArchive} archive - where to remove the capture from. + * @param {(DaemonDatArchive|string)} subject - which archive's capture to remove. * @returns Promise */ exports.deleteCapture = async function (archive, subject) { @@ -318,7 +318,9 @@ function isString (v) { } /** - * @param {InternalDatArchive} archive + +/** + * @param {DaemonDatArchive} archive * @param {string} name * @returns {string} */ @@ -329,7 +331,7 @@ function getUrlFromDescriptionPath (archive, name) { } /** - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @param {string} pathname * @returns {Promise} */ @@ -339,7 +341,7 @@ async function ensureDirectory (archive, pathname) { } /** - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @param {string} pathname * @returns {Promise} */ diff --git a/crawler/tags.js b/crawler/tags.js index 0aadb130..c2ffd228 100644 --- a/crawler/tags.js +++ b/crawler/tags.js @@ -9,7 +9,6 @@ const {normalizeSchemaUrl} = require('./util') // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive * @typedef {import('./util').CrawlSourceRecord} CrawlSourceRecord * @typedef { import("./site-descriptions").SiteDescription } SiteDescription * diff --git a/crawler/util.js b/crawler/util.js index 484086f4..f844d99a 100644 --- a/crawler/util.js +++ b/crawler/util.js @@ -11,7 +11,7 @@ const READ_TIMEOUT = 30e3 // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * * @typedef {Object} CrawlSourceRecord * @prop {string} id @@ -27,7 +27,7 @@ const crawlerEvents = new EventEmitter() exports.crawlerEvents = crawlerEvents /** - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @param {CrawlSourceRecord} crawlSource * @param {string} crawlDataset * @param {number} crawlDatasetVersion @@ -53,7 +53,7 @@ exports.doCrawl = async function (archive, crawlSource, crawlDataset, crawlDatas } // fetch current archive version - var archiveInfo = await dat.library.getDaemon().getArchiveInfo(archive.key) + var archiveInfo = {}// TODO await dat.library.getDaemon().getArchiveInfo(archive.key) var version = archiveInfo ? archiveInfo.version : 0 // fetch change log @@ -190,7 +190,7 @@ exports.normalizeSchemaUrl = function (url) { } /** - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @param {string} pathname * @returns {Promise} */ diff --git a/crawler/votes.js b/crawler/votes.js index d5d46b7f..02c66087 100644 --- a/crawler/votes.js +++ b/crawler/votes.js @@ -22,7 +22,7 @@ const JSON_PATH_REGEX = /^\/data\/votes\/([^/]+)\.json$/i // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * @typedef {import('./util').CrawlSourceRecord} CrawlSourceRecord * @typedef { import("./site-descriptions").SiteDescription } SiteDescription * @@ -61,7 +61,7 @@ exports.removeListener = events.removeListener.bind(events) * @description * Crawl the given site for votes. * - * @param {InternalDatArchive} archive - site to crawl. + * @param {DaemonDatArchive} archive - site to crawl. * @param {CrawlSourceRecord} crawlSource - internal metadata about the crawl target. * @returns {Promise} */ @@ -311,7 +311,7 @@ const get = exports.get = async function (author, topic) { * @description * Set a vote. * - * @param {InternalDatArchive} archive - where to write the vote to. + * @param {DaemonDatArchive} archive - where to write the vote to. * @param {string} topic * @param {number} vote * @returns {Promise} diff --git a/dat/assets.js b/dat/assets.js index 13a12ad9..a663a3f1 100644 --- a/dat/assets.js +++ b/dat/assets.js @@ -13,7 +13,7 @@ const IDEAL_FAVICON_SIZE = 64 // = /** - * @typedef {import('./library').InternalDatArchive} InternalDatArchive + * @typedef {import('./daemon').DaemonDatArchive} DaemonDatArchive */ // globals @@ -32,7 +32,7 @@ exports.removeListener = events.removeListener.bind(events) * @description * Crawl the given site for assets. * - * @param {InternalDatArchive} archive - site to crawl. + * @param {DaemonDatArchive} archive - site to crawl. * @param {string[]?} filenames - which files to check. * @returns {Promise} */ @@ -73,7 +73,7 @@ function extractAssetType (pathname) { /** * Reads the asset file as a dataurl * - Converts any .ico to .png - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @param {string} pathname * @returns string The asset as a data URL */ diff --git a/dat/daemon.js b/dat/daemon.js new file mode 100644 index 00000000..aae5c136 --- /dev/null +++ b/dat/daemon.js @@ -0,0 +1,173 @@ +const startDaemon = require('hyperdrive-daemon') +const { createMetadata } = require('hyperdrive-daemon/lib/metadata') +const { loadMetadata, HyperdriveClient } = require('hyperdrive-daemon-client') +const datEncoding = require('dat-encoding') +const pda = require('pauls-dat-api') + +// constants +// = + +const DAEMON_STORAGE_PATH = require('path').join(require('os').homedir(), '.dat') +const DAEMON_PORT = 3101 + +// typedefs +// = + +/** +* @typedef {Object} DaemonDatArchive +* @prop {number} sessionId +* @prop {Buffer} key +* @prop {string} url +* @prop {boolean} writable +* @prop {Object} session +* @prop {function(): Promise} session.close +* @prop {function(): Promise} session.publish +* @prop {function(): Promise} session.unpublish +* @prop {function(string, Object=, Function=): any} readFile +* @prop {function(string, any, Object=, Function=): void} writeFile +* @prop {function(string, Object=, Function=): void} readdir +* @prop {DaemonDatArchivePDA} pda + +* @typedef {Object} DaemonDatArchivePDA +* @prop {function(string): Promise} stat +* @prop {function(string, Object=): Promise} readFile +* @prop {function(string, Object=): Promise>} readdir +* @prop {function(string): Promise} readSize +* @prop {function(string, any, Object=): Promise} writeFile +* @prop {function(string): Promise} mkdir +* @prop {function(string, string): Promise} copy +* @prop {function(string, string): Promise} rename +* @prop {function(string): Promise} unlink +* @prop {function(string, Object=): Promise} rmdir +* @prop {function(string=): Promise} download +* @prop {function(string=): NodeJS.ReadableStream} watch +* @prop {function(): NodeJS.ReadableStream} createNetworkActivityStream +* @prop {function(): Promise} readManifest +* @prop {function(Object): Promise} writeManifest +* @prop {function(Object): Promise} updateManifest +*/ + +// globals +// = + +var client // client object created by hyperdrive-daemon-client + +// exported apis +// = + +exports.setup = async function () { + // fetch daemon metadata from disk + var metadata + try { + metadata = await loadMetadata() + } catch (e) { + await createMetadata(`localhost:${DAEMON_PORT}`) + metadata = await loadMetadata() + } + + // instantiate the daemon + // TODO the daemon should be managed in an external promise + await startDaemon({ + storage: DAEMON_STORAGE_PATH, + port: DAEMON_PORT, + metadata + }) + + // TODO + client = new HyperdriveClient(metadata.endpoint, metadata.token) + await client.ready() +} + +/** + * Creates a dat-archive interface to the daemon for the given key + * + * @param {Object} opts + * @param {Buffer} opts.key + * @param {number} [opts.version] + * @param {Buffer} [opts.hash] + * @returns {Promise} + */ +exports.createDatArchiveSession = async function (opts) { + const session = await client.drive.get(opts) + const sessionId = session.id + const key = datEncoding.toStr(opts.key) + var datArchive = { + key: datEncoding.toBuf(key), + url: `dat://${key}`, + writable: false, // TODO + + session: { + async close () { + return client.drive.close(sessionId) + }, + async publish () { + return client.drive.publish(sessionId) + }, + async unpublish () { + return client.drive.unpublish(sessionId) + } + }, + + stat: (...args) => { + // wrap the callback with a method which fixes the stat object output + var cb = args.pop() + args.push((err, st) => { + if (st) fixStatObject(st) + cb(err, st) + }) + client.drive.stat(sessionId, ...args) + }, + readFile: (...args) => client.drive.readFile(sessionId, ...args), + writeFile: (...args) => client.drive.writeFile(sessionId, ...args), + readdir: (...args) => client.drive.readdir(sessionId, ...args), + // ready: makeArchiveProxyCbFn(key, version, 'ready'), + // download: makeArchiveProxyCbFn(key, version, 'download'), + // history: makeArchiveProxyReadStreamFn(key, version, 'history'), + // createReadStream: makeArchiveProxyReadStreamFn(key, version, 'createReadStream'), + // createDiffStream: makeArchiveProxyReadStreamFn(key, version, 'createDiffStream'), + // createWriteStream: makeArchiveProxyWriteStreamFn(key, version, 'createWriteStream'), + // unlink: makeArchiveProxyCbFn(key, version, 'unlink'), + // mkdir: makeArchiveProxyCbFn(key, version, 'mkdir'), + // rmdir: makeArchiveProxyCbFn(key, version, 'rmdir'), + // lstat: makeArchiveProxyCbFn(key, version, 'lstat'), + // access: makeArchiveProxyCbFn(key, version, 'access') + } + datArchive.pda = createDatArchiveSessionPDA(datArchive) + return /** @type DaemonDatArchive */(datArchive) +} + +// internal methods +// = + +/** + * Converts the stat object to the expected form + * @param {Object} st + * @returns {void} + */ +function fixStatObject (st) { + st.atime = (new Date(st.atime)).getTime() + st.mtime = (new Date(st.mtime)).getTime() + st.ctime = (new Date(st.ctime)).getTime() + st.isSocket = () => false + st.isSymbolicLink = () => false + st.isFile = () => (st.mode & 32768) === 32768 + st.isBlockDevice = () => false + st.isDirectory = () => (st.mode & 16384) === 16384 + st.isCharacterDevice = () => false + st.isFIFO = () => false +} + +/** + * Provides a pauls-dat-api object for the given archive + * @param {Object} datArchive + * @returns {DaemonDatArchivePDA} + */ +function createDatArchiveSessionPDA (datArchive) { + var obj = {} + for (let k in pda) { + if (typeof pda[k] === 'function') { + obj[k] = pda[k].bind(pda, datArchive) + } + } + return obj +} \ No newline at end of file diff --git a/dat/directory-listing-page.js b/dat/directory-listing-page.js index 18a75881..51bc4c43 100644 --- a/dat/directory-listing-page.js +++ b/dat/directory-listing-page.js @@ -2,7 +2,7 @@ const {pluralize, makeSafe} = require('../lib/strings') const {stat, readdir} = require('pauls-dat-api') const {join, relative} = require('path') -/** @typedef {import('./library').InternalDatArchive} InternalDatArchive */ +/** @typedef {import('./daemon').DaemonDatArchive} DaemonDatArchive */ const styles = `` /** - * @prop {InternalDatArchive} archive + * @prop {DaemonDatArchive} archive * @prop {string} dirPath * @prop {string} webRoot * @returns {Promise} diff --git a/dat/library.js b/dat/library.js index 6a656315..6d24733f 100644 --- a/dat/library.js +++ b/dat/library.js @@ -16,6 +16,7 @@ const archivesDb = require('../dbs/archives') const datDnsDb = require('../dbs/dat-dns') // dat modules +const daemon = require('./daemon') const datGC = require('./garbage-collector') const datAssets = require('./assets') @@ -27,53 +28,13 @@ const { DAT_PRESERVED_FIELDS_ON_FORK } = require('../lib/const') const {InvalidURLError, TimeoutError} = require('beaker-error-constants') -const DAT_DAEMON_MANIFEST = require('./daemon/manifest') // typedefs // = /** - * @typedef {import('./daemon/manifest').DatDaemon} DatDaemon * @typedef {import('../dbs/archives').LibraryArchiveRecord} LibraryArchiveRecord - * - * @typedef {Object} InternalDatArchive - * @prop {Buffer} key - * @prop {string} url - * @prop {string?} domain - * @prop {Buffer} discoveryKey - * @prop {boolean} writable - * @prop {function(Function): void} ready - * @prop {function(Object, Function=): void} download - * @prop {function(Object=): NodeJS.ReadableStream} history - * @prop {function(Object=): NodeJS.ReadableStream} createReadStream - * @prop {function(string, Object=, Function=): any} readFile - * @prop {function(number, Object=): NodeJS.ReadableStream} createDiffStream - * @prop {function(string, Object=): NodeJS.WritableStream} createWriteStream - * @prop {function(string, any, Object=, Function=): void} writeFile - * @prop {function(string, Function=): void} unlink - * @prop {function(string, Object=, Function=): void} mkdir - * @prop {function(string, Function=): void} rmdir - * @prop {function(string, Object=, Function=): void} readdir - * @prop {function(string, Object=, Function=): void} stat - * @prop {function(string, Object=, Function=): void} lstat - * @prop {function(string, Object=, Function=): void} access - * @prop {Object} pda - * @prop {function(string): Promise} pda.stat - * @prop {function(string, Object=): Promise} pda.readFile - * @prop {function(string, Object=): Promise>} pda.readdir - * @prop {function(string): Promise} pda.readSize - * @prop {function(string, any, Object=): Promise} pda.writeFile - * @prop {function(string): Promise} pda.mkdir - * @prop {function(string, string): Promise} pda.copy - * @prop {function(string, string): Promise} pda.rename - * @prop {function(string): Promise} pda.unlink - * @prop {function(string, Object=): Promise} pda.rmdir - * @prop {function(string=): Promise} pda.download - * @prop {function(string=): NodeJS.ReadableStream} pda.watch - * @prop {function(): NodeJS.ReadableStream} pda.createNetworkActivityStream - * @prop {function(): Promise} pda.readManifest - * @prop {function(Object): Promise} pda.writeManifest - * @prop {function(Object): Promise} pda.updateManifest + * @typedef {import('./daemon').DaemonDatArchive} DaemonDatArchive */ // globals @@ -81,9 +42,9 @@ const DAT_DAEMON_MANIFEST = require('./daemon/manifest') var archives = {} // in-memory cache of archive objects. key -> archive var archiveLoadPromises = {} // key -> promise +var archiveSessionCheckouts = {} // key+version -> DaemonDatArchive var archivesEvents = new EventEmitter() -var daemonEvents -var daemon = /** @type DatDaemon */({}) +// var daemonEvents TODO // exported API // = @@ -95,17 +56,17 @@ var daemon = /** @type DatDaemon */({}) * @param {string[]} opts.disallowedSavePaths * @return {Promise} */ -exports.setup = async function setup ({rpcAPI, datDaemonProcess, disallowedSavePaths}) { +exports.setup = async function setup ({rpcAPI, disallowedSavePaths}) { // connect to the daemon - daemon = rpcAPI.importAPI('dat-daemon', DAT_DAEMON_MANIFEST, {proc: datDaemonProcess, timeout: false}) - daemon.setup({disallowedSavePaths, datPath: archivesDb.getDatPath()}) - daemonEvents = emitStream(daemon.createEventStream()) + await daemon.setup() + // daemonEvents = emitStream(daemon.createEventStream()) TODO // pipe the log - var daemonLogEvents = emitStream(daemon.createLogStream()) - daemonLogEvents.on('log', ({level, message, etc}) => { - baseLogger.log(level, message, etc) - }) + // TODO needed? + // var daemonLogEvents = emitStream(daemon.createLogStream()) + // daemonLogEvents.on('log', ({level, message, etc}) => { + // baseLogger.log(level, message, etc) + // }) // wire up event handlers archivesDb.on('update:archive-user-settings', async (key, userSettings, newUserSettings) => { @@ -131,7 +92,7 @@ exports.setup = async function setup ({rpcAPI, datDaemonProcess, disallowedSaveP } // update the download based on these settings - daemon.configureArchive(key, userSettings) + // daemon.configureArchive(key, userSettings) TODO }) datDnsDb.on('update', ({key, name}) => { var archive = getArchive(key) @@ -141,9 +102,10 @@ exports.setup = async function setup ({rpcAPI, datDaemonProcess, disallowedSaveP }) // re-export events - daemonEvents.on('network-changed', evt => archivesEvents.emit('network-changed', evt)) - daemonEvents.on('folder-synced', evt => archivesEvents.emit('folder-synced', evt)) - daemonEvents.on('folder-sync-error', evt => archivesEvents.emit('folder-sync-error', evt)) + // TODO + // daemonEvents.on('network-changed', evt => archivesEvents.emit('network-changed', evt)) + // daemonEvents.on('folder-synced', evt => archivesEvents.emit('folder-synced', evt)) + // daemonEvents.on('folder-sync-error', evt => archivesEvents.emit('folder-sync-error', evt)) // configure the bandwidth throttle settingsDb.getAll().then(({dat_bandwidth_limit_up, dat_bandwidth_limit_down}) => { @@ -160,11 +122,6 @@ exports.setup = async function setup ({rpcAPI, datDaemonProcess, disallowedSaveP logger.info('Initialized dat library') } -/** - * @returns {DatDaemon} - */ -exports.getDaemon = () => daemon - /** * @returns {Promise} */ @@ -201,14 +158,15 @@ exports.createEventStream = function createEventStream () { * @returns {Promise} */ exports.getDebugLog = function getDebugLog (key) { - return daemon.getDebugLog(key) + return '' // TODO needed? daemon.getDebugLog(key) } /** * @returns {NodeJS.ReadableStream} */ exports.createDebugStream = function createDebugStream () { - return daemon.createDebugStream() + // TODO needed? + // return daemon.createDebugStream() } // read metadata for the archive, and store it in the meta db @@ -226,7 +184,7 @@ const pullLatestArchiveMeta = exports.pullLatestArchiveMeta = async function pul var [manifest, oldMeta, size] = await Promise.all([ archive.pda.readManifest().catch(_ => {}), archivesDb.getMeta(key), - daemon.updateSizeTracking(key) + 0 // TODO daemon.updateSizeTracking(key) ]) var {title, description, type} = (manifest || {}) var isOwner = archive.writable @@ -318,12 +276,14 @@ exports.forkArchive = async function forkArchive (srcArchiveUrl, manifest = {}, // copy files var ignore = ['/.dat', '/.git', '/dat.json'] - await daemon.exportArchiveToArchive({ - srcArchive: datEncoding.toStr(srcArchive.key), - dstArchive: datEncoding.toStr(dstArchive.key), - skipUndownloadedFiles: true, - ignore - }) + // TODO replace this + console.warn('Fork did not copy data, exportArchiveToArchive() not yet implemented') + // await daemon.exportArchiveToArchive({ + // srcArchive: datEncoding.toStr(srcArchive.key), + // dstArchive: datEncoding.toStr(dstArchive.key), + // skipUndownloadedFiles: true, + // ignore + // }) // write a .datignore if DNE try { @@ -395,16 +355,11 @@ async function loadArchiveInner (key, secretKey, userSettings = null) { var metaPath = archivesDb.getArchiveMetaPath(key) mkdirp.sync(metaPath) - // load the archive in the daemon - var archiveInfo = await daemon.loadArchive({ - key, - secretKey, - metaPath, - userSettings - }) + // create the archive session with the daemon + var archive = daemon.createDatArchiveSession({key}) - // create the archive proxy instance - var archive = createArchiveProxy(key, undefined, archiveInfo) + // put the archive on the network + archive.session.publish() // fetch dns name if known let dnsRecord = await datDnsDb.getCurrentByKey(datEncoding.toStr(key)) @@ -435,7 +390,7 @@ const getArchive = exports.getArchive = function getArchive (key) { return archives[key] } -exports.getArchiveCheckout = function getArchiveCheckout (archive, version) { +exports.getArchiveCheckout = async function getArchiveCheckout (archive, version) { var isHistoric = false var isPreview = false var checkoutFS = archive @@ -446,13 +401,21 @@ exports.getArchiveCheckout = function getArchiveCheckout (archive, version) { // ignore, we use latest by default } else if (version === 'preview') { isPreview = true - checkoutFS = createArchiveProxy(archive.key, 'preview', archive) - checkoutFS.domain = archive.domain + // TODO need to move scoped-fs management here + // checkoutFS = createArchiveProxy(archive.key, 'preview', archive) + // checkoutFS.domain = archive.domain } else { throw new Error('Invalid version identifier:' + version) } } else { - checkoutFS = createArchiveProxy(archive.key, version, archive) + let checkoutKey = `${archive.key}+${version}` + if (!(checkoutKey in archiveSessionCheckouts)) { + archiveSessionCheckouts[checkoutKey] = daemon.createDatArchiveSession({ + key: archive.key, + version + }) + } + checkoutFS = archiveSessionCheckouts[checkoutKey] checkoutFS.domain = archive.domain isHistoric = true } @@ -482,7 +445,8 @@ exports.unloadArchive = async function unloadArchive (key) { archive.fileActStream = null } delete archives[key] - await daemon.unloadArchive(key) + archive.session.unpublish() + archive.session.close() } const isArchiveLoaded = exports.isArchiveLoaded = function isArchiveLoaded (key) { @@ -491,7 +455,8 @@ const isArchiveLoaded = exports.isArchiveLoaded = function isArchiveLoaded (key) } exports.updateSizeTracking = function updateSizeTracking (archive) { - return daemon.updateSizeTracking(datEncoding.toStr(archive.key)) + return 0 // TODO + // return daemon.updateSizeTracking(datEncoding.toStr(archive.key)) } // archive fetch/query @@ -512,7 +477,7 @@ exports.queryArchives = async function queryArchives (query) { await Promise.all(archiveInfos.map(async (archiveInfo) => { var archive = getArchive(archiveInfo.key) if (archive) { - var info = await daemon.getArchiveInfo(archiveInfo.key) + var info = {}//await daemon.getArchiveInfo(archiveInfo.key) TODO archiveInfo.isSwarmed = archiveInfo.userSettings.networked archiveInfo.size = info.size archiveInfo.peers = info.peers @@ -536,7 +501,7 @@ exports.getArchiveInfo = async function getArchiveInfo (key) { archivesDb.getMeta(key), archivesDb.getUserSettings(0, key), archive.pda.readManifest().catch(_ => {}), - daemon.getArchiveInfo(key) + {} // TODO daemon.getArchiveInfo(key) ]) manifest = manifest || {} meta.key = key @@ -566,12 +531,12 @@ exports.getArchiveInfo = async function getArchiveInfo (key) { exports.getArchiveNetworkStats = async function getArchiveNetworkStats (key) { key = await fromURLToKey(key, true) - return daemon.getArchiveNetworkStats(key) + return {} // TODO daemon.getArchiveNetworkStats(key) } exports.clearFileCache = async function clearFileCache (key) { var userSettings = await archivesDb.getUserSettings(0, key) - return daemon.clearFileCache(key, userSettings) + return {} // TODO daemon.clearFileCache(key, userSettings) } /** @@ -658,107 +623,3 @@ const fromKeyToURL = exports.fromKeyToURL = function fromKeyToURL (key) { } return key } - -// archive proxy -// = - -function makeArchiveProxyCbFn (key, version, method) { - return (...args) => daemon.callArchiveAsyncMethod(key, version, method, ...args) -} - -function makeArchiveProxyReadStreamFn (key, version, method) { - return (...args) => daemon.callArchiveReadStreamMethod(key, version, method, ...args) -} - -function makeArchiveProxyWriteStreamFn (key, version, method) { - return (...args) => daemon.callArchiveWriteStreamMethod(key, version, method, ...args) -} - -function makeArchiveProxyPDAPromiseFn (key, version, method) { - return (...args) => daemon.callArchivePDAPromiseMethod(key, version, method, ...args) -} - -function makeArchiveProxyPDAReadStreamFn (key, version, method) { - return (...args) => daemon.callArchivePDAReadStreamMethod(key, version, method, ...args) -} - -function fixStatObject (st) { - st.atime = (new Date(st.atime)).getTime() - st.mtime = (new Date(st.mtime)).getTime() - st.ctime = (new Date(st.ctime)).getTime() - st.isSocket = () => false - st.isSymbolicLink = () => false - st.isFile = () => (st.mode & 32768) === 32768 - st.isBlockDevice = () => false - st.isDirectory = () => (st.mode & 16384) === 16384 - st.isCharacterDevice = () => false - st.isFIFO = () => false -} - -/** - * - * @param {string|Buffer} key - * @param {number} version - * @param {Object} archiveInfo - * @returns {InternalDatArchive} - */ -function createArchiveProxy (key, version, archiveInfo) { - key = datEncoding.toStr(key) - const stat = makeArchiveProxyCbFn(key, version, 'stat') - const pdaStat = makeArchiveProxyPDAPromiseFn(key, version, 'stat') - return { - key: datEncoding.toBuf(key), - get url () { - return `dat://${this.domain || key}${version ? '+' + version : ''}` - }, - domain: undefined, - discoveryKey: datEncoding.toBuf(archiveInfo.discoveryKey), - writable: archiveInfo.writable, - - ready: makeArchiveProxyCbFn(key, version, 'ready'), - download: makeArchiveProxyCbFn(key, version, 'download'), - history: makeArchiveProxyReadStreamFn(key, version, 'history'), - createReadStream: makeArchiveProxyReadStreamFn(key, version, 'createReadStream'), - readFile: makeArchiveProxyCbFn(key, version, 'readFile'), - createDiffStream: makeArchiveProxyReadStreamFn(key, version, 'createDiffStream'), - createWriteStream: makeArchiveProxyWriteStreamFn(key, version, 'createWriteStream'), - writeFile: makeArchiveProxyCbFn(key, version, 'writeFile'), - unlink: makeArchiveProxyCbFn(key, version, 'unlink'), - mkdir: makeArchiveProxyCbFn(key, version, 'mkdir'), - rmdir: makeArchiveProxyCbFn(key, version, 'rmdir'), - readdir: makeArchiveProxyCbFn(key, version, 'readdir'), - stat: (...args) => { - var cb = args.pop() - args.push((err, st) => { - if (st) fixStatObject(st) - cb(err, st) - }) - stat(...args) - }, - lstat: makeArchiveProxyCbFn(key, version, 'lstat'), - access: makeArchiveProxyCbFn(key, version, 'access'), - - pda: { - stat: async (...args) => { - var st = await pdaStat(...args) - if (st) fixStatObject(st) - return st - }, - readFile: makeArchiveProxyPDAPromiseFn(key, version, 'readFile'), - readdir: makeArchiveProxyPDAPromiseFn(key, version, 'readdir'), - readSize: makeArchiveProxyPDAPromiseFn(key, version, 'readSize'), - writeFile: makeArchiveProxyPDAPromiseFn(key, version, 'writeFile'), - mkdir: makeArchiveProxyPDAPromiseFn(key, version, 'mkdir'), - copy: makeArchiveProxyPDAPromiseFn(key, version, 'copy'), - rename: makeArchiveProxyPDAPromiseFn(key, version, 'rename'), - unlink: makeArchiveProxyPDAPromiseFn(key, version, 'unlink'), - rmdir: makeArchiveProxyPDAPromiseFn(key, version, 'rmdir'), - download: makeArchiveProxyPDAPromiseFn(key, version, 'download'), - watch: makeArchiveProxyPDAReadStreamFn(key, version, 'watch'), - createNetworkActivityStream: makeArchiveProxyPDAReadStreamFn(key, version, 'createNetworkActivityStream'), - readManifest: makeArchiveProxyPDAPromiseFn(key, version, 'readManifest'), - writeManifest: makeArchiveProxyPDAPromiseFn(key, version, 'writeManifest'), - updateManifest: makeArchiveProxyPDAPromiseFn(key, version, 'updateManifest') - } - } -} diff --git a/dat/protocol.js b/dat/protocol.js index 6de06db0..f035670d 100644 --- a/dat/protocol.js +++ b/dat/protocol.js @@ -134,7 +134,7 @@ exports.electronHandler = async function (request, respond) { // checkout version if needed try { - var {checkoutFS} = datLibrary.getArchiveCheckout(archive, urlp.version) + var {checkoutFS} = await datLibrary.getArchiveCheckout(archive, urlp.version) if (urlp.version === 'preview') { await checkoutFS.pda.stat('/') // run a stat to ensure preview mode exists } diff --git a/dbs/archives.js b/dbs/archives.js index 0c320592..e8b3bbb2 100644 --- a/dbs/archives.js +++ b/dbs/archives.js @@ -16,7 +16,7 @@ const { // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * * @typedef {Object} LibraryArchiveRecord * @prop {string} key @@ -97,7 +97,7 @@ exports.getDatPath = function () { /** * @description Get the path to an archive's files. - * @param {string | Buffer | InternalDatArchive} archiveOrKey + * @param {string | Buffer | DaemonDatArchive} archiveOrKey * @returns {string} */ // @@ -115,7 +115,7 @@ const getArchiveMetaPath = exports.getArchiveMetaPath = function (archiveOrKey) /** * @description Get the path to an archive's temporary local sync path. - * @param {string | Buffer | InternalDatArchive} archiveOrKey + * @param {string | Buffer | DaemonDatArchive} archiveOrKey * @returns {string} */ const getInternalLocalSyncPath = exports.getInternalLocalSyncPath = function (archiveOrKey) { diff --git a/index.js b/index.js index 4c6df73f..f063ec3d 100644 --- a/index.js +++ b/index.js @@ -32,7 +32,6 @@ module.exports = { assert(typeof opts.userDataPath === 'string', 'userDataPath must be a string') assert(typeof opts.homePath === 'string', 'homePath must be a string') assert(typeof opts.templatesPath === 'string', 'templatesPath must be a string') - assert(!!opts.datDaemonProcess, 'must provide datDaemonProcess') assert(!!opts.permsAPI, 'must provide permsAPI') assert(!!opts.uiAPI, 'must provide uiAPI') assert(!!opts.rpcAPI, 'must provide rpcAPI') diff --git a/lib/zip.js b/lib/zip.js index 51004cbd..136fd9ab 100644 --- a/lib/zip.js +++ b/lib/zip.js @@ -2,12 +2,12 @@ const {join} = require('path') const yazl = require('yazl') /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * @typedef {import('stream').Readable} Readable */ /** - * @param {InternalDatArchive} archive + * @param {DaemonDatArchive} archive * @param {string} [dirpath = '/'] * @returns {Readable} */ diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 195502a0..00000000 --- a/package-lock.json +++ /dev/null @@ -1,5035 +0,0 @@ -{ - "name": "@beaker/core", - "version": "3.0.2", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/polyfill": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.4.4.tgz", - "integrity": "sha512-WlthFLfhQQhh+A2Gn5NSFl0Huxz36x86Jn+E9OW7ibK8edKPq+KLy4apM1yDpQ8kJOVi1OVjpP4vSDLdrI04dg==", - "requires": { - "core-js": "^2.6.5", - "regenerator-runtime": "^0.13.2" - } - }, - "@beaker/dat-ephemeral-ext-msg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@beaker/dat-ephemeral-ext-msg/-/dat-ephemeral-ext-msg-1.0.2.tgz", - "integrity": "sha512-LfuokfkHB4HnHEYxdQS8ulNEVhhixviYGN8CXo1JCuNC9LdtzMVvsggD+aMiZ73MtoBYuDY6bwTpfAEHDlCxkQ==", - "requires": { - "protocol-buffers-encodings": "^1.1.0" - } - }, - "@beaker/dat-serve-resolve-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@beaker/dat-serve-resolve-path/-/dat-serve-resolve-path-1.0.0.tgz", - "integrity": "sha512-ohW9nPTY9gft09Hss8V78Y4rzgYOkbESDjeIDm2KcJIIEEQzdvNFgbGWiPYyPRguYW5ppF7ZorM6huWRbo3bGA==", - "requires": { - "parse-dat-url": "^3.0.2" - } - }, - "@beaker/dat-session-data-ext-msg": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@beaker/dat-session-data-ext-msg/-/dat-session-data-ext-msg-1.1.1.tgz", - "integrity": "sha512-8AofrhwBqfcyK998mCp7Um4d4DJ5udwRDIR9ASQfLPEDIetC5oOKIWAHc+vXC9HN6qzZko31IDSoQvuzgOmwsg==" - }, - "@beaker/datignore": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@beaker/datignore/-/datignore-1.0.0.tgz", - "integrity": "sha512-UMOvwf+efn01go0fV/JqAZIgrrObphXwdROgCoPZM+g6iCzeoA9G2vQwfULuw5W4XGHIj+Ro689zFNKfRXTHiw==" - }, - "@types/bluebird": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.27.tgz", - "integrity": "sha512-6BmYWSBea18+tSjjSC3QIyV93ZKAeNWGM7R6aYt1ryTZXrlHF+QLV0G2yV0viEGVyRkyQsWfMoJ0k/YghBX5sQ==" - }, - "@types/node": { - "version": "12.7.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.1.tgz", - "integrity": "sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==", - "optional": true - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "dev": true, - "requires": { - "acorn": "^3.0.4" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } - } - }, - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", - "dev": true - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "append-tree": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/append-tree/-/append-tree-2.4.4.tgz", - "integrity": "sha512-rPMUMkR8JjjPDDHHDZ/YeLO0KIbUGCrXgy921F6sBkEXBR9jYYxK8LUlwpZkUVi70cMR6r8uSmHZ/5HvtrntHg==", - "requires": { - "array-lru": "^1.1.1", - "codecs": "^1.2.0", - "from2": "^2.3.0", - "inherits": "^2.0.3", - "mutexify": "^1.1.0", - "process-nextick-args": "^1.0.7", - "protocol-buffers-encodings": "^1.1.0", - "varint": "^5.0.0" - }, - "dependencies": { - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" - } - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" - }, - "array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=" - }, - "array-lru": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-lru/-/array-lru-1.1.1.tgz", - "integrity": "sha1-DH4bTgIq4Wb/HoRIxZXzGB/NMzc=" - }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" - }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "requires": { - "lodash": "^4.17.14" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" - }, - "atomic-batcher": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/atomic-batcher/-/atomic-batcher-1.0.2.tgz", - "integrity": "sha1-0WkB0QzOxZUWwZe5zNiTBom4E7Q=" - }, - "await-lock": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-1.1.3.tgz", - "integrity": "sha512-e0jRB8X/VVxulahjW16cM1dHsO7xjyZBP8p2AnVmg2Vn3q5xJ5sTUAybmkp96+s+QcrtidSJqpCGfWhVOX7NGg==" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - } - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "beaker-error-constants": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/beaker-error-constants/-/beaker-error-constants-1.4.0.tgz", - "integrity": "sha512-F3iMA2F01w0q5eiZgD/wUQULNDdLCA99GR6yFEjhvyZfK10WdeESRUGTPeJk83qiIn0F8ZSmR6YWOG6I0EkoLA==" - }, - "bencode": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/bencode/-/bencode-1.0.0.tgz", - "integrity": "sha512-N+VOSP5MkoX+xgnp6Y056iCY5TmCZg9rgPNPQe0bIiXchxYFP4vs/Tf0dTdQ+qQhP7HM2gvfFq+sUVjQsGy5Zw==", - "requires": { - "safe-buffer": "^5.1.1" - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" - }, - "bitfield-rle": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bitfield-rle/-/bitfield-rle-2.2.1.tgz", - "integrity": "sha512-wrDhHe7LUkqaytxgbsFXoemzHRv6e8FrVNWWsQCgUfmuVYW6ke44hoGc9VdpjgfIsJ/ejmCFA8wDtDqACNAvyw==", - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "varint": "^4.0.0" - }, - "dependencies": { - "varint": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/varint/-/varint-4.0.1.tgz", - "integrity": "sha1-SQgpuULSSEY7KzUJeZXDv3NxmOk=" - } - } - }, - "bittorrent-dht": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/bittorrent-dht/-/bittorrent-dht-7.10.0.tgz", - "integrity": "sha512-fvb6M58Ceiv/S94nu6zeaiMoJvUYOeIqRbgaClm+kJTzCAqJPtAR/31pXNYB5iEReOoKqQB5zY33gY0W6ZRWQQ==", - "requires": { - "bencode": "^1.0.0", - "buffer-equals": "^1.0.3", - "debug": "^3.1.0", - "inherits": "^2.0.1", - "k-bucket": "^3.3.0", - "k-rpc": "^4.2.1", - "lru": "^3.1.0", - "randombytes": "^2.0.5", - "safe-buffer": "^5.0.1", - "simple-sha1": "^2.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "blake2b": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.3.tgz", - "integrity": "sha512-pkDss4xFVbMb4270aCyGD3qLv92314Et+FsKzilCLxDz5DuZ2/1g3w4nmBbu6nKApPspnjG7JcwTjGZnduB1yg==", - "requires": { - "blake2b-wasm": "^1.1.0", - "nanoassert": "^1.0.0" - } - }, - "blake2b-wasm": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/blake2b-wasm/-/blake2b-wasm-1.1.7.tgz", - "integrity": "sha512-oFIHvXhlz/DUgF0kq5B1CqxIDjIJwh9iDeUUGQUcvgiGz7Wdw03McEO7CfLBy7QKGdsydcMCgO9jFNBAFCtFcA==", - "requires": { - "nanoassert": "^1.0.0" - } - }, - "bluebird": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", - "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" - }, - "bmp-js": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", - "integrity": "sha1-4Fpj95amwf8l9Hcex62twUjAcjM=" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" - }, - "buffer-equals": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/buffer-equals/-/buffer-equals-1.0.4.tgz", - "integrity": "sha1-A1O1T9B/2VZBcGca5vZrnPENJ/U=" - }, - "buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "bulk-write-stream": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bulk-write-stream/-/bulk-write-stream-1.1.4.tgz", - "integrity": "sha512-GtKwd/4etuk1hNeprXoESBO1RSeRYJMXKf+O0qHmWdUomLT8ysNEfX/4bZFXr3BK6eukpHiEnhY2uMtEHDM2ng==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.1.4" - } - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" - }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, - "requires": { - "callsites": "^0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "dev": true - }, - "chownr": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz", - "integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==" - }, - "chrome-dgram": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/chrome-dgram/-/chrome-dgram-3.0.2.tgz", - "integrity": "sha512-Ay741EHF/Ib18un+LUtBNK43NrabD6GOuwVaka7uUbV0gFRLEPULm2Q05YSzRNBtSrbaO4eErmDdniiy/u8Lig==", - "requires": { - "inherits": "^2.0.1", - "run-series": "^1.1.2" - } - }, - "chrome-dns": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/chrome-dns/-/chrome-dns-1.0.1.tgz", - "integrity": "sha512-HqsYJgIc8ljJJOqOzLphjAs79EUuWSX3nzZi2LNkzlw3GIzAeZbaSektC8iT/tKvLqZq8yl1GJu5o6doA4TRbg==", - "requires": { - "chrome-net": "^3.3.2" - } - }, - "chrome-net": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/chrome-net/-/chrome-net-3.3.2.tgz", - "integrity": "sha512-BHxWfA9MDnh0C1By5q1DnF1vRS7vfBi2PrqTHIIt1HA4hM6l2xkHzoazbDlZcrDrMfjNs6fojKG+ZD0JmlnNWg==", - "requires": { - "inherits": "^2.0.1" - } - }, - "circular-append-file": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/circular-append-file/-/circular-append-file-1.0.1.tgz", - "integrity": "sha512-BUDFvrBTCdeVhg9E05PX4XgMegk6xWB69uGwyuATEg7PMfa9lGU1mzFSK0xWNW2O0i9CAQHN0oIdXI/kI2hPkg==", - "requires": { - "multistream": "^2.1.0" - } - }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "codecs": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/codecs/-/codecs-1.2.1.tgz", - "integrity": "sha512-SPnx+ZHXVJ0qTInRXmnxuyu8PDvSzvop5MXp1BOr/urFQI3yL2n5ewE755skTklF/hKVlWj8cinGxdR2gvLvTA==" - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", - "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "color-string": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", - "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "colorette": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.0.8.tgz", - "integrity": "sha512-X6Ck90ReaF+EfKdVGB7vdIQ3dr651BbIrBwY5YBKg13fjH+940sTtp7/Pkx33C6ntYfQcRumOs/aUQhaRPpbTQ==" - }, - "colornames": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", - "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" - }, - "colors": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", - "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==" - }, - "colorspace": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", - "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", - "requires": { - "color": "3.0.x", - "text-hex": "1.0.x" - } - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "connections": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/connections/-/connections-1.4.2.tgz", - "integrity": "sha1-eJBIK/XHGvbFyhkr4xNq7XRCiq0=" - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" - }, - "core-js": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", - "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "count-trailing-zeros": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/count-trailing-zeros/-/count-trailing-zeros-1.0.1.tgz", - "integrity": "sha1-q6bFgzvkENRbHso+bVg4RM5oLHc=" - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "crypto-random-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "dat-dns": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/dat-dns/-/dat-dns-3.2.1.tgz", - "integrity": "sha512-gCfU2FBg41Qg7RgqYBRD3bjYWAaJFO6UvKfCU9SA1LBy6vZ3EoTZH5doCYdTTQmVEsAxMef18W0lnvr1Z7rx0g==", - "requires": { - "call-me-maybe": "^1.0.1", - "concat-stream": "^1.6.0", - "debug": "^4.1.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "dat-encoding": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/dat-encoding/-/dat-encoding-5.0.1.tgz", - "integrity": "sha512-PET9PlGt6ejgqU07hbPLx3tP2siDMMFumUe+xwmm4+5W+0cOlpzreCPoMVUBzxWeR4sPdxL+AS53odQTBtzEqA==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "datland-swarm-defaults": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/datland-swarm-defaults/-/datland-swarm-defaults-1.0.2.tgz", - "integrity": "sha1-J3uJWjnxqn+WpJWgL7NmKl7Z8uA=", - "requires": { - "xtend": "^4.0.1" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "decode-bmp": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/decode-bmp/-/decode-bmp-0.1.0.tgz", - "integrity": "sha512-i7ImaOawHIwQNIt3IpO8X04ZRGI4A7gqX3vPw5aMIqMwsAk5xs/pnWLKmXc97nII5rSGJB9QyauO5FwctFiYoQ==", - "requires": { - "to-data-view": "^1.0.0" - } - }, - "decode-ico": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/decode-ico/-/decode-ico-0.3.1.tgz", - "integrity": "sha512-Ejv981YSYeAVyebE+g/Z/3hhE9wLE0uOBmiglqnhRfVMbLu1mf0CCesOoFWjdDqDYBOWIYLHJ6+uQxjlID3FEg==", - "requires": { - "decode-bmp": "^0.1.0", - "to-data-view": "^1.0.0" - } - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" - }, - "diagnostics": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", - "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", - "requires": { - "colorspace": "1.1.x", - "enabled": "1.0.x", - "kuler": "1.0.x" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" - }, - "diff-file-tree": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/diff-file-tree/-/diff-file-tree-2.2.0.tgz", - "integrity": "sha512-2vvgzQLCQGNnc6WRVHhvn2L+C5/Lam7DYgY/vPfuXno3OpNhcuhZf+B86zptQm8yEzxthzmdslIO08wodMB5Bw==", - "requires": { - "debug": "^2.6.4", - "es6-promisify": "^5.0.0", - "pump": "^1.0.2", - "stream-equal": "^1.0.0", - "tempy": "^0.1.0" - }, - "dependencies": { - "pump": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", - "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, - "discovery-channel": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/discovery-channel/-/discovery-channel-5.5.1.tgz", - "integrity": "sha512-EEmZQFE0PiOsJj7G3KVCwFGbYs4QchUvzA91iHtZ6HfkIqfBEDSTGLygJrUlY1Tr77WDV+qZVrZuNghHxSL/vw==", - "requires": { - "bittorrent-dht": "^7.10.0", - "buffer-from": "^1.0.0", - "debug": "^2.6.9", - "dns-discovery": "^6.0.1", - "pretty-hash": "^1.0.1", - "thunky": "^0.1.0" - } - }, - "discovery-swarm": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/discovery-swarm/-/discovery-swarm-6.0.0.tgz", - "integrity": "sha512-ByfwygfLCB4umpSBVz9tGxgmng1D3YWg6A80cip8dgdpC5dRyGsL5w6KoC9srQ15xydKtYPgcxUC2YtSzPCtHA==", - "requires": { - "connections": "^1.4.2", - "debug": "^4.1.1", - "discovery-channel": "^5.5.1", - "length-prefixed-message": "^3.0.3", - "pump": "^3.0.0", - "to-buffer": "^1.0.1", - "utp-native": "^2.1.3" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "dns-discovery": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/dns-discovery/-/dns-discovery-6.2.3.tgz", - "integrity": "sha512-ZULG1R5J9QHZfaXo5XFGVG22LIcnZorbEa7f83FYgCGDaQrVfyVmty3Z89OvBLpCPetwW+LzjCcT60ekhbQ+9g==", - "requires": { - "circular-append-file": "^1.0.1", - "debug": "^2.6.9", - "dns-socket": "^3.0.0", - "lru": "^2.0.0", - "minimist": "^1.2.0", - "multicast-dns": "^7.1.1", - "network-address": "^1.1.2", - "pump": "^3.0.0", - "speedometer": "^1.0.0", - "unordered-set": "^1.1.0" - }, - "dependencies": { - "lru": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/lru/-/lru-2.0.1.tgz", - "integrity": "sha1-+XmHHhYuP1yiVL5GhExT1MU2RUQ=", - "requires": { - "inherits": "^2.0.1" - } - } - } - }, - "dns-packet": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-4.2.0.tgz", - "integrity": "sha512-bn1AKpfkFbm0MIioOMHZ5qJzl2uypdBwI4nYNsqvhjsegBhcKJUlCrMPWLx6JEezRjxZmxhtIz/FkBEur2l8Cw==", - "requires": { - "ip": "^1.1.5", - "safe-buffer": "^5.1.1" - } - }, - "dns-socket": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/dns-socket/-/dns-socket-3.0.0.tgz", - "integrity": "sha512-M0WkByoJ/mTm+HtwBQLsRJPe5uGIC/lYVOp+s6ZzhbZ5iq4GxjFyxYPQhB85dgCLvVb43aJQXHDC9aUgyKGc/Q==", - "requires": { - "dns-packet": "^4.1.0" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "emit-stream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/emit-stream/-/emit-stream-0.1.2.tgz", - "integrity": "sha1-DiBVCKDQ1tM0YHhC98R2nb+/Fug=", - "requires": { - "through": "~2.3.4" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "enabled": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", - "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", - "requires": { - "env-variable": "0.0.x" - } - }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "requires": { - "once": "^1.4.0" - } - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, - "env-variable": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", - "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", - "dev": true, - "requires": { - "ajv": "^5.3.0", - "babel-code-frame": "^6.22.0", - "chalk": "^2.1.0", - "concat-stream": "^1.6.0", - "cross-spawn": "^5.1.0", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.4", - "esquery": "^1.0.0", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.0.1", - "ignore": "^3.3.3", - "imurmurhash": "^0.1.4", - "inquirer": "^3.0.6", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.9.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.4", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^1.0.1", - "require-uncached": "^1.0.3", - "semver": "^5.3.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "~2.0.1", - "table": "4.0.2", - "text-table": "~0.2.0" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", - "dev": true - }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", - "dev": true, - "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", - "dev": true, - "requires": { - "estraverse": "^4.0.0" - } - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "requires": { - "fill-range": "^2.1.0" - }, - "dependencies": { - "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-bitfield": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/fast-bitfield/-/fast-bitfield-1.2.2.tgz", - "integrity": "sha512-t8HYqkuE3YEqNcyWlAfh55479aTxO+GpYwvQvJppYqyBfSmRdNIhzY2m09FKN/MENTzq4wH6heHOIvsPyMAwvQ==", - "requires": { - "count-trailing-zeros": "^1.0.1" - } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fast-safe-stringify": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", - "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==" - }, - "fd-lock": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fd-lock/-/fd-lock-1.0.2.tgz", - "integrity": "sha512-8O4zSv6rlNNghVfzVkj/p7LUIeBm7Xxk6QnhfmR1WJm/W4kwS8IyShy4X1peRnFUYZUYLlcwEMKXF8QWxJCMvg==", - "optional": true, - "requires": { - "napi-macros": "^1.8.2", - "node-gyp-build": "^3.8.0" - } - }, - "fecha": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", - "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "dev": true, - "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - } - }, - "file-type": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz", - "integrity": "sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw==" - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", - "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" - } - }, - "flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" - }, - "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", - "dev": true, - "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" - } - }, - "flat-tree": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/flat-tree/-/flat-tree-1.6.0.tgz", - "integrity": "sha1-/KMM3bkAb7ZW6168ea6ydOf96e0=" - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "requires": { - "for-in": "^1.0.1" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "requires": { - "map-cache": "^0.2.2" - } - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs-jetpack": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/fs-jetpack/-/fs-jetpack-1.3.1.tgz", - "integrity": "sha512-oCrJI4kSredslsM3iZoZ19RKUt78XyyOSJuwzg/JGIxCBmjaoqPpvqAy5ZaUNI/QHJPL0UkKeX/yarAd39vP/Q==", - "requires": { - "minimatch": "^3.0.2" - } - }, - "fs-minipass": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz", - "integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==", - "requires": { - "minipass": "^2.2.1" - } - }, - "fs-reverse": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/fs-reverse/-/fs-reverse-0.0.3.tgz", - "integrity": "sha512-zu+5yhmaWueDBAWm7y6ejj2PipVep3EQlQYdfS6r3zsfzIfTVkcdbrsqye2UovisDqogu5dJFxae/dUAOYQqBA==", - "requires": { - "from": "~0.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "function-queue": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/function-queue/-/function-queue-0.0.12.tgz", - "integrity": "sha1-us+7w90sMqWnY+/aGZ+wBgDQ/Zo=" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" - }, - "getopts": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.4.tgz", - "integrity": "sha512-Rz7DGyomZjrenu9Jx4qmzdlvJgvrEFHXHvjK0FcZtcTC1U5FmES7OdZHUwMuSnEE6QvBvwse1JODKj7TgbSEjQ==" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "requires": { - "is-glob": "^2.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.1.tgz", - "integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==" - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "hypercore": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/hypercore/-/hypercore-7.6.1.tgz", - "integrity": "sha512-ZQ1HdFXa9D5cSwXiu6vldYSE5ro6OBtyWdnFr8L/U3PFDCEpIyhyLvoRTscmP+7U2U9ZYSV3NoNHjWlNPIA8Gw==", - "requires": { - "array-lru": "^1.1.0", - "atomic-batcher": "^1.0.2", - "bitfield-rle": "^2.2.1", - "bulk-write-stream": "^1.1.3", - "codecs": "^2.0.0", - "fast-bitfield": "^1.2.2", - "fd-lock": "^1.0.2", - "flat-tree": "^1.6.0", - "from2": "^2.3.0", - "hypercore-crypto": "^1.0.0", - "hypercore-protocol": "^6.5.0", - "inherits": "^2.0.3", - "inspect-custom-symbol": "^1.1.0", - "last-one-wins": "^1.0.4", - "memory-pager": "^1.0.2", - "merkle-tree-stream": "^3.0.3", - "pretty-hash": "^1.0.1", - "random-access-file": "^2.1.0", - "sodium-universal": "^2.0.0", - "sparse-bitfield": "^3.0.0", - "thunky": "^1.0.1", - "uint64be": "^2.0.1", - "unordered-array-remove": "^1.0.2", - "unordered-set": "^2.0.0" - }, - "dependencies": { - "codecs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/codecs/-/codecs-2.0.0.tgz", - "integrity": "sha512-WXvpJRAgc693oqYvZte9uYEiL5YHtfrxyEq12uVny9oBJ1k37zSva5vVz7trsnt6R9Y15hEgOSC7VFZT2pfYnA==" - }, - "thunky": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", - "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==" - }, - "unordered-set": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", - "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==" - } - } - }, - "hypercore-crypto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hypercore-crypto/-/hypercore-crypto-1.0.0.tgz", - "integrity": "sha512-xFwOnNlOt8L+SovC7dTNchKaNYJb5l8rKZZwpWQnCme1r7CU4Hlhp1RDqPES6b0OpS7DkTo9iU0GltQGkpsjMw==", - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-from": "^1.1.0", - "sodium-universal": "^2.0.0", - "uint64be": "^2.0.2" - } - }, - "hypercore-protocol": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/hypercore-protocol/-/hypercore-protocol-6.12.0.tgz", - "integrity": "sha512-T3oy9/7QFejqJX2RGcCUU1944e5/eKbLlSz9JPTNN1QbYFJgat/r7eTyOO8SMSLUimUmQx6YBMKhgYbdKzp7Bw==", - "requires": { - "buffer-alloc-unsafe": "^1.0.0", - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "protocol-buffers-encodings": "^1.1.0", - "readable-stream": "^2.2.6", - "sodium-universal": "^2.0.0", - "sorted-indexof": "^1.0.0", - "varint": "^5.0.0" - } - }, - "hyperdrive": { - "version": "9.16.0", - "resolved": "https://registry.npmjs.org/hyperdrive/-/hyperdrive-9.16.0.tgz", - "integrity": "sha512-2iw4baOLmYEs8hWzGUmdgqLHIvjjhiM125kKhQv1aFaiwqDMLtZJ8JsxyeaRZZmMSaC9TuXwjUmU/rrPPgIoVA==", - "requires": { - "append-tree": "^2.3.5", - "duplexify": "^3.5.0", - "from2": "^2.3.0", - "hypercore": "^7.5.0", - "inherits": "^2.0.3", - "mutexify": "^1.1.0", - "protocol-buffers-encodings": "^1.1.0", - "random-access-file": "^2.0.1", - "sodium-universal": "^2.0.0", - "stream-collector": "^1.0.1", - "stream-each": "^1.2.0", - "thunky": "^1.0.2", - "uint64be": "^2.0.1", - "unixify": "^1.0.0" - }, - "dependencies": { - "thunky": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", - "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==" - } - } - }, - "hyperdrive-network-speed": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hyperdrive-network-speed/-/hyperdrive-network-speed-2.1.0.tgz", - "integrity": "sha512-JolPS374h6oS1rmz1iebFfeDDvA2nAtiHbx9VJJGMgSDSx4Q77eeY09hDgZwY7KatSKUGWnnSyydSgVUb3+8Lw==", - "requires": { - "debug": "^3.1.0", - "speedometer": "^1.0.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "icojs": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/icojs/-/icojs-0.12.3.tgz", - "integrity": "sha512-7c/U6GVyBW6iw7SqmO0XLh2+q+KuaDZ2SoJcG+GrBqjAtvr9e0mtiUOxkpRx7ym6XcZQDvjgc0usjskyROJ+gg==", - "requires": { - "bmp-js": "0.1.0", - "decode-ico": "^0.3.1", - "file-type": "^10.7.0", - "jpeg-js": "^0.3.3", - "pngjs": "^3.3.3", - "to-data-view": "^1.0.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "identify-filetype": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/identify-filetype/-/identify-filetype-1.0.0.tgz", - "integrity": "sha1-zm4pqnYvAxuChSojkqOBY/rXkOs=" - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true - }, - "ignore-walk": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", - "requires": { - "minimatch": "^3.0.4" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" - }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "inspect-custom-symbol": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/inspect-custom-symbol/-/inspect-custom-symbol-1.1.0.tgz", - "integrity": "sha512-vtI2YXBRZBkU6DlfHfd0GtZENfiEiTacAXUd0ZY6HA+X7aPznpFfPmzSC+tHKXAkz9KDSdI4AYfwAMXR5t+isg==" - }, - "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" - }, - "into-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", - "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", - "requires": { - "from2": "^2.1.1", - "p-is-promise": "^1.1.0" - } - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==" - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "requires": { - "is-primitive": "^2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "^3.0.1" - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", - "requires": { - "is-unc-path": "^1.0.0" - } - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", - "requires": { - "unc-path-regex": "^0.1.2" - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "jpeg-js": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.3.6.tgz", - "integrity": "sha512-MUj2XlMB8kpe+8DJUGH/3UJm4XpI8XEgZQ+CiHDeyrGoKPdW/8FJv6ku+3UiYm5Fz3CWaL+iXmD8Q4Ap6aC1Jw==" - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "k-bucket": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/k-bucket/-/k-bucket-3.3.1.tgz", - "integrity": "sha512-kgwWqYT79rAahn4maIVTP8dIe+m1KulufWW+f1bB9DlZrRFiGpZ4iJOg2HUp4xJYBWONP3+rOPIWF/RXABU6mw==", - "requires": { - "buffer-equals": "^1.0.3", - "inherits": "^2.0.1", - "randombytes": "^2.0.3" - } - }, - "k-rpc": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/k-rpc/-/k-rpc-4.3.1.tgz", - "integrity": "sha512-mgAJZeFYbpP0xzJzmS0TQTYoFI0sjy3GnKFhg8wyboL+KvWg2WLaA2Oy9PthLPx2Rxz4WeBMk4y3MSOrDJ95FA==", - "requires": { - "buffer-equals": "^1.0.3", - "k-bucket": "^4.0.0", - "k-rpc-socket": "^1.7.2", - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.1" - }, - "dependencies": { - "k-bucket": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/k-bucket/-/k-bucket-4.0.1.tgz", - "integrity": "sha512-YvDpmY3waI999h1zZoW1rJ04fZrgZ+5PAlVmvwDHT6YO/Q1AOhdel07xsKy9eAvJjQ9xZV1wz3rXKqEfaWvlcQ==", - "requires": { - "inherits": "^2.0.1", - "randombytes": "^2.0.3" - } - } - } - }, - "k-rpc-socket": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/k-rpc-socket/-/k-rpc-socket-1.11.1.tgz", - "integrity": "sha512-8xtA8oqbZ6v1Niryp2/g4GxW16EQh5MvrUylQoOG+zcrDff5CKttON2XUXvMwlIHq4/2zfPVFiinAccJ+WhxoA==", - "requires": { - "bencode": "^2.0.0", - "chrome-dgram": "^3.0.2", - "chrome-dns": "^1.0.0", - "chrome-net": "^3.3.2" - }, - "dependencies": { - "bencode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/bencode/-/bencode-2.0.1.tgz", - "integrity": "sha512-2uhEl8FdjSBUyb69qDTgOEeeqDTa+n3yMQzLW0cOzNf1Ow5bwcg3idf+qsWisIKRH8Bk8oC7UXL8irRcPA8ZEQ==", - "requires": { - "safe-buffer": "^5.1.1" - } - } - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - }, - "knex": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/knex/-/knex-0.17.6.tgz", - "integrity": "sha512-4SKp8jaBxqlEoaveenmpfnHEv5Kzo6/vhIj8UhW1srGw/FKqARTr+7Fv8C1C1qeVHDjv0coQWuUzN5eermHUsw==", - "requires": { - "@babel/polyfill": "^7.4.4", - "@types/bluebird": "^3.5.27", - "bluebird": "^3.5.5", - "colorette": "1.0.8", - "commander": "^2.20.0", - "debug": "4.1.1", - "getopts": "2.2.4", - "inherits": "~2.0.3", - "interpret": "^1.2.0", - "liftoff": "3.1.0", - "lodash": "^4.17.11", - "mkdirp": "^0.5.1", - "pg-connection-string": "2.0.0", - "tarn": "^1.1.5", - "tildify": "1.2.0", - "uuid": "^3.3.2", - "v8flags": "^3.1.3" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "kuler": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", - "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", - "requires": { - "colornames": "^1.1.1" - } - }, - "last-one-wins": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/last-one-wins/-/last-one-wins-1.0.4.tgz", - "integrity": "sha1-wb/Qy8tGeQ7JFWuNGu6Py4bNoio=" - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "requires": { - "invert-kv": "^2.0.0" - } - }, - "length-prefixed-message": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/length-prefixed-message/-/length-prefixed-message-3.0.4.tgz", - "integrity": "sha512-Tqyx4nggb9nkLD6p4hyIz7UiVNg5u3OnCP2h0hS/HXpheH88rsoNEgNB8xTnpPMw6zWXGZ7Cpg1zhWPlsJ0/TQ==", - "requires": { - "varint": "^3.0.1" - }, - "dependencies": { - "varint": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/varint/-/varint-3.0.1.tgz", - "integrity": "sha1-nT9T4DbAqxIACnS8LSTL8JOlgdk=" - } - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", - "requires": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - } - }, - "limiter": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.4.tgz", - "integrity": "sha512-XCpr5bElgDI65vVgstP8TWjv6/QKWm9GU5UG0Pr5sLQ3QLo8NVKsioe+Jed5/3vFOe3IQuqE7DKwTvKQkjTHvg==" - }, - "linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", - "requires": { - "uc.micro": "^1.0.1" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" - }, - "lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "lodash.groupby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", - "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=" - }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" - }, - "lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" - }, - "lodash.throttle": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" - }, - "lodash.uniqwith": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", - "integrity": "sha1-egy/ZfQ7WShiWp1NDcVLGMrcfvM=" - }, - "logform": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", - "integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==", - "requires": { - "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", - "fecha": "^2.3.3", - "ms": "^2.1.1", - "triple-beam": "^1.3.0" - } - }, - "lru": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lru/-/lru-3.1.0.tgz", - "integrity": "sha1-6n+4VG2DczOWoTCR12z+tMBoN9U=", - "requires": { - "inherits": "^2.0.1" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - }, - "dependencies": { - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, - "make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", - "requires": { - "kind-of": "^6.0.2" - } - }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "requires": { - "p-defer": "^1.0.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "requires": { - "object-visit": "^1.0.0" - } - }, - "markdown-it": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", - "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", - "requires": { - "argparse": "^1.0.7", - "entities": "~1.1.1", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - } - }, - "math-random": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==" - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - }, - "dependencies": { - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" - } - } - }, - "memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" - }, - "merkle-tree-stream": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/merkle-tree-stream/-/merkle-tree-stream-3.0.3.tgz", - "integrity": "sha1-+KBkdg0355eK1fn208EZpJT1cIE=", - "requires": { - "flat-tree": "^1.3.0", - "readable-stream": "^2.0.5" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" - }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "requires": { - "mime-db": "1.40.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, - "minipass": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", - "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", - "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", - "requires": { - "minipass": "^2.2.1" - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - } - } - }, - "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "multicast-dns": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.0.tgz", - "integrity": "sha512-Tu2QORGOFANB124NWQ/JTRhMf/ODouVLEuvu5Dz8YWEU55zQgRgFGnBHfIh5PbfNDAuaRl7yLB+pgWhSqVxi2Q==", - "requires": { - "dns-packet": "^4.0.0", - "thunky": "^1.0.2" - }, - "dependencies": { - "thunky": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", - "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==" - } - } - }, - "multistream": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/multistream/-/multistream-2.1.1.tgz", - "integrity": "sha512-xasv76hl6nr1dEy3lPvy7Ej7K/Lx3O/FCvwge8PeVJpciPPoNCbaANcNiBug3IpdvTveZUcAV0DJzdnUDMesNQ==", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.5" - } - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "mutexify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mutexify/-/mutexify-1.2.0.tgz", - "integrity": "sha512-oprzxd2zhfrJqEuB98qc1dRMMonClBQ57UPDjnbcrah4orEMTq1jq3+AcdFe5ePzdbJXI7zmdhfftIdMnhYFoQ==" - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" - }, - "nanoassert": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-1.1.0.tgz", - "integrity": "sha1-TzFS4JVA/eKMdvRLGbvNHVpCR40=" - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "napi-macros": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-1.8.2.tgz", - "integrity": "sha512-Tr0DNY4RzTaBG2W2m3l7ZtFuJChTH6VZhXVhkGGjF/4cZTt+i8GcM9ozD+30Lmr4mDoZ5Xx34t2o4GJqYWDGcg==" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "needle": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", - "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "network-address": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/network-address/-/network-address-1.1.2.tgz", - "integrity": "sha1-Sqe/1D8D8LgclwKxPWqFjdsybz4=" - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "node-gyp-build": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", - "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==" - }, - "node-pre-gyp": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", - "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "normalize-url": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" - }, - "npm-bundled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", - "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==" - }, - "npm-packlist": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.4.tgz", - "integrity": "sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==", - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "requires": { - "isobject": "^3.0.0" - } - }, - "object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", - "requires": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - }, - "dependencies": { - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "requires": { - "for-in": "^1.0.1" - } - } - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "requires": { - "isobject": "^3.0.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "one-time": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", - "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - }, - "dependencies": { - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - } - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "os-shim": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", - "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-is-promise": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", - "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=" - }, - "parse-dat-url": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/parse-dat-url/-/parse-dat-url-3.0.3.tgz", - "integrity": "sha512-7a/rNzaZqhOHlZ1rwxz4xmERI47PpnAkuqbnkne9IH91D/pQ2T0+g5jK9kVUCp+jKHYRA0j4kbsyaluiF9XoaA==" - }, - "parse-filepath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", - "requires": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" - } - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", - "requires": { - "path-root-regex": "^0.1.0" - } - }, - "path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" - }, - "pauls-dat-api": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/pauls-dat-api/-/pauls-dat-api-8.1.0.tgz", - "integrity": "sha512-DTxj5BIPjKJ5dDgQJxMsUfTVUVVi6RSgR3AWz4dl6pwAmQoh4YMYz+cfwfoQRIituMUdczRJkbs/JXD9yaa8dQ==", - "requires": { - "anymatch": "^1.3.2", - "beaker-error-constants": "^1.4.0", - "call-me-maybe": "^1.0.1", - "dat-encoding": "^4.0.2", - "diff-file-tree": "^2.1.1", - "emit-stream": "^0.1.2", - "fs-extra": "^4.0.3", - "pump": "^1.0.3" - }, - "dependencies": { - "anymatch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", - "requires": { - "micromatch": "^2.1.5", - "normalize-path": "^2.0.0" - } - }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "dat-encoding": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/dat-encoding/-/dat-encoding-4.0.2.tgz", - "integrity": "sha1-sBBo/g0IDz0+SYWgxK0ht8FGdfY=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "pump": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", - "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "pg-connection-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.0.0.tgz", - "integrity": "sha1-Pu/lmX4G2Ugh5NUC5CtqHHP434I=" - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true - }, - "pngjs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" - }, - "pre-commit": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", - "integrity": "sha1-287g7p3nI15X95xW186UZBpp7sY=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "spawn-sync": "^1.0.15", - "which": "1.2.x" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "which": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" - }, - "pretty-hash": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pretty-hash/-/pretty-hash-1.0.1.tgz", - "integrity": "sha1-FuBXkYje9WvbVliSvNBaXWUySAc=" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "protocol-buffers-encodings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/protocol-buffers-encodings/-/protocol-buffers-encodings-1.1.0.tgz", - "integrity": "sha512-SmjEuAf3hc3h3rWZ6V1YaaQw2MNJWK848gLJgzx/sefOJdNLujKinJVXIS0q2cBQpQn2Q32TinawZyDZPzm4kQ==", - "requires": { - "signed-varint": "^2.0.1", - "varint": "^5.0.0" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "psl": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.3.0.tgz", - "integrity": "sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "random-access-file": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/random-access-file/-/random-access-file-2.1.3.tgz", - "integrity": "sha512-AE0Z1ywR5gIkzACMC1lCsR6LP8g4ynNm7oYWYdKPSSU6Y3H+mGDJxBqfcV9B9KstfHNemhfX3nYmx99ZC9f/yg==", - "requires": { - "mkdirp": "^0.5.1", - "random-access-storage": "^1.1.1" - } - }, - "random-access-indexed-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/random-access-indexed-file/-/random-access-indexed-file-2.0.0.tgz", - "integrity": "sha512-IDPRktIPbitqJ0WFQqxyjuE4OhvZ7VyWdJYGCcfi1HKVUByPa4JgS+v8r93xoLbKkMPJDKhiMfyYhGoAPNEzPA==", - "requires": { - "await-lock": "^1.1.3", - "mkdirp": "^0.5.1", - "random-access-storage": "^1.3.0", - "uint48be": "^2.0.1" - } - }, - "random-access-storage": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/random-access-storage/-/random-access-storage-1.4.0.tgz", - "integrity": "sha512-7oszloM/+PdqWp/oFGyL6SeI14liqo8AAisHAZQGkWdHISyAnngKjNPL0JYIazeLxbHPY6oed2yUffowdq/o6A==", - "requires": { - "inherits": "^2.0.3" - } - }, - "randomatic": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", - "requires": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" - } - } - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "requires": { - "resolve": "^1.1.6" - } - }, - "recursive-watch": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/recursive-watch/-/recursive-watch-1.1.4.tgz", - "integrity": "sha512-fWejAmdLi7B/jipBUjTLnqId+PK+573fbGNbdaNA/AiAnQAx6OYOLCGWRs0W5+PyM1rLzZSWK2f40QpHSR49PQ==", - "requires": { - "ttl": "^1.3.0" - } - }, - "regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", - "dev": true - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - } - }, - "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "requires": { - "glob": "^7.1.3" - } - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, - "requires": { - "is-promise": "^2.1.0" - } - }, - "run-series": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.8.tgz", - "integrity": "sha512-+GztYEPRpIsQoCSraWHDBs9WVy4eVME16zhOtDB4H9J4xN0XRhknnmLOl+4gRgZtu8dpp9N/utSPjKH/xmDzXg==" - }, - "rusha": { - "version": "0.8.13", - "resolved": "https://registry.npmjs.org/rusha/-/rusha-0.8.13.tgz", - "integrity": "sha1-mghOe4YLF7/zAVuSxnpqM2GRUTo=" - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "dev": true, - "requires": { - "rx-lite": "*" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "scoped-fs": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/scoped-fs/-/scoped-fs-1.4.1.tgz", - "integrity": "sha512-7I9UC2eECQg1myIaDyL18j+05FjX11IkuEhkUZ0XzgJGYrkfQ1xxm6dKW0MGomGkaHMamf14uNTbNc+kvuqEFA==", - "requires": { - "recursive-watch": "^1.1.1" - } - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "signed-varint": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/signed-varint/-/signed-varint-2.0.1.tgz", - "integrity": "sha1-UKmYnafJjCxh2tEZvJdHDvhSgSk=", - "requires": { - "varint": "~5.0.0" - } - }, - "simple-sha1": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/simple-sha1/-/simple-sha1-2.1.2.tgz", - "integrity": "sha512-TQl9rm4rdKAVmhO++sXAb8TNN0D6JAD5iyI1mqEPNpxUzTRrtm4aOG1pDf/5W/qCFihiaoK6uuL9rvQz1x1VKw==", - "requires": { - "rusha": "^0.8.1" - } - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "requires": { - "is-arrayish": "^0.3.1" - } - }, - "siphash24": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/siphash24/-/siphash24-1.1.1.tgz", - "integrity": "sha512-dKKwjIoTOa587TARYLlBRXq2lkbu5Iz35XrEVWpelhBP1m8r2BGOy1QlaZe84GTFHG/BTucEUd2btnNc8QzIVA==", - "requires": { - "nanoassert": "^1.0.0" - } - }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } - } - }, - "slugify": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.4.tgz", - "integrity": "sha512-KP0ZYk5hJNBS8/eIjGkFDCzGQIoZ1mnfQRYS5WM3273z+fxGWXeN0fkwf2ebEweydv9tioZIHGZKoF21U07/nw==" - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "sodium-javascript": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/sodium-javascript/-/sodium-javascript-0.5.5.tgz", - "integrity": "sha512-UMmCHovws/sxIBZsIRhIl8uRPou/RFDD0vVop81T1hG106NLLgqajKKuHAOtAP6hflnZ0UrVA2VFwddTd/NQyA==", - "requires": { - "blake2b": "^2.1.1", - "nanoassert": "^1.0.0", - "siphash24": "^1.0.1", - "xsalsa20": "^1.0.0" - } - }, - "sodium-native": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-2.4.6.tgz", - "integrity": "sha512-Ro9lhTjot8M01nwKLXiqLSmjR7B8o+Wg4HmJUjEShw/q6XPlNMzjPkA1VJKaMH8SO8fJ/sggAKVwreTaFszS2Q==", - "optional": true, - "requires": { - "ini": "^1.3.5", - "nan": "^2.14.0", - "node-gyp-build": "^4.1.0" - }, - "dependencies": { - "node-gyp-build": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.0.tgz", - "integrity": "sha512-rGLv++nK20BG8gc0MzzcYe1Nl3p3mtwJ74Q2QD0HTEDKZ6NvOFSelY6s2QBPWIHRR8h7hpad0LiwajfClBJfNg==", - "optional": true - } - } - }, - "sodium-signatures": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/sodium-signatures/-/sodium-signatures-2.1.1.tgz", - "integrity": "sha512-Alr0buBPROZJJdUSgg/7t027pV7YWxVg9CNy2f/SEsoh3cYgyd9iUiiNJ/W+Qf5ir6yk51cruqQVYpLYju0dbw==", - "requires": { - "buffer-alloc-unsafe": "^1.0.0", - "sodium-universal": "^2.0.0" - } - }, - "sodium-universal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sodium-universal/-/sodium-universal-2.0.0.tgz", - "integrity": "sha512-csdVyakzHJRyCevY4aZC2Eacda8paf+4nmRGF2N7KxCLKY2Ajn72JsExaQlJQ2BiXJncp44p3T+b80cU+2TTsg==", - "requires": { - "sodium-javascript": "~0.5.0", - "sodium-native": "^2.0.0" - } - }, - "sorted-indexof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sorted-indexof/-/sorted-indexof-1.0.0.tgz", - "integrity": "sha1-F8dC/3zxh+L1mhXfm4HxemLOCJk=" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" - }, - "sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", - "requires": { - "memory-pager": "^1.0.2" - } - }, - "spawn-sync": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", - "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", - "dev": true, - "requires": { - "concat-stream": "^1.4.7", - "os-shim": "^0.1.2" - } - }, - "speedometer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-1.1.0.tgz", - "integrity": "sha512-z/wAiTESw2XVPssY2XRcme4niTc4S5FkkJ4gknudtVoc33Zil8TdTxHy5torRcgqMqksJV2Yz8HQcvtbsnw0mQ==" - }, - "spellchecker": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/spellchecker/-/spellchecker-3.7.0.tgz", - "integrity": "sha512-saQT4BR9nivbK70s0YjyIlSbZzO6bfWRULcGL2JU7fi7wotOnWl70P0QoUwwLywNQJQ47osgCo6GmOlqzRTxbQ==", - "requires": { - "any-promise": "^1.3.0", - "nan": "^2.14.0" - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "split2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", - "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", - "requires": { - "through2": "^2.0.2" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "sqlite3": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.0.9.tgz", - "integrity": "sha512-IkvzjmsWQl9BuBiM4xKpl5X8WCR4w0AeJHRdobCdXZ8dT/lNc1XS6WqvY35N6+YzIIgzSBeY5prdFObID9F9tA==", - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.11.0", - "request": "^2.87.0" - } - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "stream-collector": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-collector/-/stream-collector-1.0.1.tgz", - "integrity": "sha1-TU5V8XE1YSGyxfZVn5RHBaso2xU=", - "requires": { - "once": "^1.3.1" - } - }, - "stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-equal/-/stream-equal-1.1.1.tgz", - "integrity": "sha512-SaZxkvxujYBR6NTumhRTg/yztw2p30fzZ/jvSgQtlZFEGI7tdSNDaPbvT47QF92hx6Tar8hAhpr7ErpTNvtuCQ==", - "requires": { - "@types/node": "*" - } - }, - "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" - }, - "stream-throttle": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", - "integrity": "sha1-rdV8jXzHOoFjDTHNVdOWHPr7qcM=", - "requires": { - "commander": "^2.2.0", - "limiter": "^1.0.5" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "supports-sparse-files": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/supports-sparse-files/-/supports-sparse-files-1.0.2.tgz", - "integrity": "sha512-45nB+UT0Tv06fTGkYCHMR+WfAL/gIgbdHqICw2vIb0Gb68QEmi1LX1s+ODA5NJbk4RS4ug2VBHBVO1tFywJzUw==" - }, - "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", - "dev": true, - "requires": { - "ajv": "^5.2.3", - "ajv-keywords": "^2.1.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "tar": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz", - "integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==", - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.5", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - } - }, - "tarn": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.5.tgz", - "integrity": "sha512-PMtJ3HCLAZeedWjJPgGnCvcphbCOMbtZpjKgLq3qM5Qq9aQud+XHrL0WlrlgnTyS8U+jrjGbEXprFcQrxPy52g==" - }, - "temp-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", - "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=" - }, - "tempy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.1.0.tgz", - "integrity": "sha1-hSdBPNBxAINPzJy7gkK+lboOH+4=", - "requires": { - "pify": "^2.3.0", - "temp-dir": "^1.0.0", - "unique-string": "^1.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } - } - }, - "text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "textextensions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.5.0.tgz", - "integrity": "sha512-1IkVr355eHcomgK7fgj1Xsokturx6L5S2JRT5WcRdA6v5shk9sxWuO/w/VbpQexwkXJMQIa/j1dBi3oo7+HhcA==" - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "thunky": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz", - "integrity": "sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=" - }, - "tildify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", - "requires": { - "os-homedir": "^1.0.0" - } - }, - "timeout-refresh": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-1.0.0.tgz", - "integrity": "sha512-y5ajDPPtyhumr7xRnQgOMMVR5/EXMCVHPwM7RWnMUZx9UzT8FGRBtwG4/rh2AWHkDr7JR8dBHU6NDGx7tEiEAg==" - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" - }, - "to-data-view": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-1.0.0.tgz", - "integrity": "sha512-pz/bdULSupr+shtVLFHRBXstHfeBByfT9oa1oVOMBR4FWJkuFuD/OFdXZkR8sWONbtfKO7m3Tin/tKM+k3Qt8Q==" - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } - } - }, - "triple-beam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", - "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" - }, - "ttl": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/ttl/-/ttl-1.3.1.tgz", - "integrity": "sha512-+bGy9iDAqg3WSfc2ZrprToSPJhZjqy7vUv9wupQzsiv+BVPVx1T2a6G4T0290SpQj+56Toaw9BiLO5j5Bd7QzA==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" - }, - "uint48be": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/uint48be/-/uint48be-2.0.1.tgz", - "integrity": "sha512-LQvWofTo3RCz+XaQR3VNch+dDFwpIvWr/98imhQne++vFhpQP16YAC/a8w9N00Heqqra00ACjHT18cgvn5H+bg==" - }, - "uint64be": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/uint64be/-/uint64be-2.0.2.tgz", - "integrity": "sha512-9QqdvpGQTXgxthP+lY4e/gIBy+RuqcBaC6JVwT5I3bDLgT/btL6twZMR0pI3/Fgah9G/pdwzIprE5gL6v9UvyQ==", - "requires": { - "buffer-alloc": "^1.1.0" - } - }, - "unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", - "requires": { - "crypto-random-string": "^1.0.0" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "unixify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz", - "integrity": "sha1-OmQcjC/7zk2mg6XHDwOkYpQMIJA=", - "requires": { - "normalize-path": "^2.1.1" - } - }, - "unordered-array-remove": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz", - "integrity": "sha1-xUbo+I4xegzyZEyX7LV9umbSUO8=" - }, - "unordered-set": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-1.1.0.tgz", - "integrity": "sha1-K6fvMW7dC5WQzFR8dPdqLxZP7Mo=" - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" - } - } - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "utp-native": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/utp-native/-/utp-native-2.1.4.tgz", - "integrity": "sha512-FYjr3bHBnJpw8yD0CmFCh5USyDgr6VtuncEIun100GqCUdgqnkAx9irSY3tA4UrzRH56qmiocP2fs1QjQ7ZDZA==", - "requires": { - "napi-macros": "^1.8.1", - "node-gyp-build": "^3.5.0", - "readable-stream": "^3.0.2", - "timeout-refresh": "^1.0.0", - "unordered-set": "^2.0.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "unordered-set": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", - "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==" - } - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - }, - "v8flags": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", - "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "varint": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", - "integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "winston": { - "version": "github:winstonjs/winston#b4ced895b3e1ead8a616590189b003cfd9d7acca", - "from": "github:winstonjs/winston#b4ced895b3e1ead8a616590189b003cfd9d7acca", - "requires": { - "async": "^2.6.1", - "diagnostics": "^1.1.1", - "is-stream": "^1.1.0", - "logform": "^2.0.0", - "one-time": "0.0.4", - "readable-stream": "^3.1.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.3.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "winston-transport": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", - "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", - "requires": { - "readable-stream": "^2.3.6", - "triple-beam": "^1.2.0" - } - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "xsalsa20": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/xsalsa20/-/xsalsa20-1.0.2.tgz", - "integrity": "sha512-g1DFmZ5JJ9Qzvt4dMw6m9IydqoCSP381ucU5zm46Owbk3bwmqAr8eEJirOPc7PrXRn45drzOpAyDp8jsnoyXyw==" - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" - }, - "yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "requires": { - "buffer-crc32": "~0.2.3" - } - } - } -} diff --git a/package.json b/package.json index b8a941b9..2479c718 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,8 @@ "fs-jetpack": "^1.3.1", "fs-reverse": "0.0.3", "function-queue": "0.0.12", - "hypercore-protocol": "^6.11.1", - "hyperdrive": "^9.16.0", + "hyperdrive-daemon": "^0.9.13", + "hyperdrive-daemon-client": "^0.9.9", "hyperdrive-network-speed": "^2.1.0", "icojs": "^0.12.3", "identify-filetype": "^1.0.0", diff --git a/users/index.js b/users/index.js index 8f35c5c0..83531760 100644 --- a/users/index.js +++ b/users/index.js @@ -23,13 +23,13 @@ const LABEL_REGEX = /[a-z0-9-]/i // = /** - * @typedef {import('../dat/library').InternalDatArchive} InternalDatArchive + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * * @typedef {Object} User * @prop {number} id * @prop {string} label * @prop {string} url - * @prop {InternalDatArchive} archive + * @prop {DaemonDatArchive} archive * @prop {boolean} isDefault * @prop {boolean} isTemporary * @prop {string} title diff --git a/web-apis/bg/archives.js b/web-apis/bg/archives.js index 88b11a80..c602bea1 100644 --- a/web-apis/bg/archives.js +++ b/web-apis/bg/archives.js @@ -98,7 +98,7 @@ module.exports = { // make sure the path is good try { - await datLibrary.getDaemon().fs_assertSafePath(localSyncPath) + // TODO await datLibrary.getDaemon().fs_assertSafePath(localSyncPath) } catch (e) { if (e.notFound) { return {doesNotExist: true} @@ -108,7 +108,7 @@ module.exports = { // check for conflicts var archive = await datLibrary.getOrLoadArchive(key) - var diff = await datLibrary.getDaemon().fs_diffListing(archive, {localSyncPath}) + var diff = [] // TODO await datLibrary.getDaemon().fs_diffListing(archive, {localSyncPath}) diff = diff.filter(d => d.change === 'mod' && d.path !== '/dat.json') if (diff.length) { return {hasConflicts: true, conflicts: diff.map(d => d.path)} @@ -128,7 +128,7 @@ module.exports = { if (opts.deleteSyncPath && oldSettings.localSyncPath) { try { - await datLibrary.getDaemon().fs_assertSafePath(oldSettings.localSyncPath) + // TODO await datLibrary.getDaemon().fs_assertSafePath(oldSettings.localSyncPath) await jetpack.removeAsync(oldSettings.localSyncPath) } catch (_) {} } @@ -143,7 +143,7 @@ module.exports = { // make sure the path is good try { - await datLibrary.getDaemon().fs_assertSafePath(localSyncPath) + // TODO await datLibrary.getDaemon().fs_assertSafePath(localSyncPath) } catch (e) { if (e.notFound) { // just create the folder @@ -172,7 +172,7 @@ module.exports = { }) // ensure sync - await datLibrary.getDaemon().fs_ensureSyncFinished(archive) + // TODO await datLibrary.getDaemon().fs_ensureSyncFinished(archive) }, // diff & publish @@ -188,7 +188,7 @@ module.exports = { archive = await datLibrary.getOrLoadArchive(key) }) - return datLibrary.getDaemon().fs_diffListing(archive, opts) + return [] // TODO datLibrary.getDaemon().fs_diffListing(archive, opts) }, async diffLocalSyncPathFile (key, filepath) { @@ -201,7 +201,7 @@ module.exports = { archive = await datLibrary.getOrLoadArchive(key) }) - return datLibrary.getDaemon().fs_diffFile(archive, filepath) + return [] // TODO datLibrary.getDaemon().fs_diffFile(archive, filepath) }, async publishLocalSyncPathListing (key, opts = {}) { @@ -215,7 +215,7 @@ module.exports = { }) opts.shallow = false - return datLibrary.getDaemon().fs_syncFolderToArchive(archive, opts) + return [] // TODO datLibrary.getDaemon().fs_syncFolderToArchive(archive, opts) }, async revertLocalSyncPathListing (key, opts = {}) { @@ -229,7 +229,7 @@ module.exports = { }) opts.shallow = false - return datLibrary.getDaemon().fs_syncArchiveToFolder(archive, opts) + return null // TODO datLibrary.getDaemon().fs_syncArchiveToFolder(archive, opts) }, // drafts diff --git a/web-apis/bg/dat-archive.js b/web-apis/bg/dat-archive.js index a3aa0f8c..b33e677a 100644 --- a/web-apis/bg/dat-archive.js +++ b/web-apis/bg/dat-archive.js @@ -232,7 +232,7 @@ module.exports = { var reverse = opts.reverse === true var {start, end} = opts var {archive, checkoutFS, isPreview} = await lookupArchive(this.sender, url, opts) - var archiveInfo = await datLibrary.getDaemon().getArchiveInfo(archive.key) + var archiveInfo = {} // TODO await datLibrary.getDaemon().getArchiveInfo(archive.key) if (isPreview) { // dont use the checkout FS in previews, it has no history() api @@ -743,7 +743,7 @@ async function lookupArchive (sender, url, opts = {}) { if (!archive) archive = await datLibrary.loadArchive(archiveKey) // get specific checkout - var {checkoutFS, isHistoric, isPreview} = datLibrary.getArchiveCheckout(archive, version) + var {checkoutFS, isHistoric, isPreview} = await datLibrary.getArchiveCheckout(archive, version) return {archive, filepath, version, isHistoric, isPreview, checkoutFS} } diff --git a/web-apis/bg/experimental/dat-peers.js b/web-apis/bg/experimental/dat-peers.js index 55b82f26..920b5f67 100644 --- a/web-apis/bg/experimental/dat-peers.js +++ b/web-apis/bg/experimental/dat-peers.js @@ -20,48 +20,48 @@ module.exports = { async list () { await globals.permsAPI.checkLabsPerm(Object.assign({sender: this.sender}, LAB_PERMS_OBJ)) var archive = await getSenderArchive(this.sender) - return datLibrary.getDaemon().ext_listPeers(archive.key.toString('hex')) + // TODO return datLibrary.getDaemon().ext_listPeers(archive.key.toString('hex')) }, async get (peerId) { await globals.permsAPI.checkLabsPerm(Object.assign({sender: this.sender}, LAB_PERMS_OBJ)) var archive = await getSenderArchive(this.sender) - return datLibrary.getDaemon().ext_getPeer(archive.key.toString('hex'), peerId) + // TODO return datLibrary.getDaemon().ext_getPeer(archive.key.toString('hex'), peerId) }, async broadcast (data) { await globals.permsAPI.checkLabsPerm(Object.assign({sender: this.sender}, LAB_PERMS_OBJ)) var archive = await getSenderArchive(this.sender) - return datLibrary.getDaemon().ext_broadcastEphemeralMessage(archive.key.toString('hex'), data) + // TODO return datLibrary.getDaemon().ext_broadcastEphemeralMessage(archive.key.toString('hex'), data) }, async send (peerId, data) { await globals.permsAPI.checkLabsPerm(Object.assign({sender: this.sender}, LAB_PERMS_OBJ)) var archive = await getSenderArchive(this.sender) - return datLibrary.getDaemon().ext_sendEphemeralMessage(archive.key.toString('hex'), peerId, data) + // TODO return datLibrary.getDaemon().ext_sendEphemeralMessage(archive.key.toString('hex'), peerId, data) }, async getSessionData () { await globals.permsAPI.checkLabsPerm(Object.assign({sender: this.sender}, LAB_PERMS_OBJ)) var archive = await getSenderArchive(this.sender) - return datLibrary.getDaemon().ext_getSessionData(archive.key.toString('hex')) + // TODO return datLibrary.getDaemon().ext_getSessionData(archive.key.toString('hex')) }, async setSessionData (sessionData) { await globals.permsAPI.checkLabsPerm(Object.assign({sender: this.sender}, LAB_PERMS_OBJ)) var archive = await getSenderArchive(this.sender) - return datLibrary.getDaemon().ext_setSessionData(archive.key.toString('hex'), sessionData) + // TODO return datLibrary.getDaemon().ext_setSessionData(archive.key.toString('hex'), sessionData) }, async createEventStream () { await globals.permsAPI.checkLabsPerm(Object.assign({sender: this.sender}, LAB_PERMS_OBJ)) var archive = await getSenderArchive(this.sender) - return datLibrary.getDaemon().ext_createDatPeersStream(archive.key.toString('hex')) + // TODO return datLibrary.getDaemon().ext_createDatPeersStream(archive.key.toString('hex')) }, async getOwnPeerId () { await globals.permsAPI.checkLabsPerm(Object.assign({sender: this.sender}, LAB_PERMS_OBJ)) - return datLibrary.getDaemon().ext_getOwnPeerId() + // TODO return datLibrary.getDaemon().ext_getOwnPeerId() } } diff --git a/web-apis/bg/library.js b/web-apis/bg/library.js index ffcc2c54..b941b6c0 100644 --- a/web-apis/bg/library.js +++ b/web-apis/bg/library.js @@ -275,7 +275,7 @@ async function validateLocalPath (key, v) { // make sure the folder is usable try { - await datLibrary.getDaemon().fs_assertSafePath(v) + // TODO await datLibrary.getDaemon().fs_assertSafePath(v) } catch (e) { if (e.notFound) { var e2 = new Error('The target local folder can not be found') @@ -287,7 +287,7 @@ async function validateLocalPath (key, v) { // make sure there are no conflicts with existing files var archive = await datLibrary.getOrLoadArchive(key) - var diff = await datLibrary.getDaemon().fs_diffListing(archive, {localSyncPath: v}) + var diff = [] // TODO await datLibrary.getDaemon().fs_diffListing(archive, {localSyncPath: v}) diff = diff.filter(d => d.change === 'mod' && d.path !== '/dat.json') if (diff.length) { var e = new Error('There are conflicting files in the target local folder') From 7c563c806b8d2e432d0d91d78ac6a05eccc1acdf Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 11 Jul 2019 09:51:05 -0500 Subject: [PATCH 05/74] Add temporary DaemonDatArchive.getInfo() method --- crawler/util.js | 2 +- dat/daemon.js | 10 ++++++++++ dat/debugging.js | 3 --- dat/library.js | 8 ++------ web-apis/bg/dat-archive.js | 2 +- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/crawler/util.js b/crawler/util.js index f844d99a..182cf845 100644 --- a/crawler/util.js +++ b/crawler/util.js @@ -53,7 +53,7 @@ exports.doCrawl = async function (archive, crawlSource, crawlDataset, crawlDatas } // fetch current archive version - var archiveInfo = {}// TODO await dat.library.getDaemon().getArchiveInfo(archive.key) + var archiveInfo = await archive.getInfo() var version = archiveInfo ? archiveInfo.version : 0 // fetch change log diff --git a/dat/daemon.js b/dat/daemon.js index aae5c136..bee34031 100644 --- a/dat/daemon.js +++ b/dat/daemon.js @@ -23,6 +23,7 @@ const DAEMON_PORT = 3101 * @prop {function(): Promise} session.close * @prop {function(): Promise} session.publish * @prop {function(): Promise} session.unpublish +* @prop {function(): Promise} getInfo * @prop {function(string, Object=, Function=): any} readFile * @prop {function(string, any, Object=, Function=): void} writeFile * @prop {function(string, Object=, Function=): void} readdir @@ -108,6 +109,15 @@ exports.createDatArchiveSession = async function (opts) { } }, + async getInfo () { + // TODO pull from daemon + return { + version: 0, + size: 0, + peers: 0, + networkStats: {} + } + }, stat: (...args) => { // wrap the callback with a method which fixes the stat object output var cb = args.pop() diff --git a/dat/debugging.js b/dat/debugging.js index b7dc0351..9d1d1aa0 100644 --- a/dat/debugging.js +++ b/dat/debugging.js @@ -17,9 +17,6 @@ exports.archivesDebugPage = function () { Content DKey${a.content.discoveryKey.toString('hex')} Meta Key${a.key.toString('hex')} Content Key${a.content.key.toString('hex')} - ${a.replicationStreams.map((s, i) => ` - Peer ${i}${s.peerInfo.type} ${s.peerInfo.host}:${s.peerInfo.port} - `).join('')} ` }).join('')} diff --git a/dat/library.js b/dat/library.js index 6d24733f..715aaade 100644 --- a/dat/library.js +++ b/dat/library.js @@ -477,15 +477,13 @@ exports.queryArchives = async function queryArchives (query) { await Promise.all(archiveInfos.map(async (archiveInfo) => { var archive = getArchive(archiveInfo.key) if (archive) { - var info = {}//await daemon.getArchiveInfo(archiveInfo.key) TODO + var info = await archive.getInfo() archiveInfo.isSwarmed = archiveInfo.userSettings.networked archiveInfo.size = info.size archiveInfo.peers = info.peers - archiveInfo.peerHistory = info.peerHistory } else { archiveInfo.isSwarmed = false archiveInfo.peers = 0 - archiveInfo.peerHistory = [] } })) return isArray ? archiveInfos : archiveInfos[0] @@ -501,7 +499,7 @@ exports.getArchiveInfo = async function getArchiveInfo (key) { archivesDb.getMeta(key), archivesDb.getUserSettings(0, key), archive.pda.readManifest().catch(_ => {}), - {} // TODO daemon.getArchiveInfo(key) + archive.getInfo() ]) manifest = manifest || {} meta.key = key @@ -522,8 +520,6 @@ exports.getArchiveInfo = async function getArchiveInfo (key) { previewMode: userSettings.previewMode } meta.peers = archiveInfo.peers - meta.peerInfo = archiveInfo.peerInfo - meta.peerHistory = archiveInfo.peerHistory meta.networkStats = archiveInfo.networkStats return meta diff --git a/web-apis/bg/dat-archive.js b/web-apis/bg/dat-archive.js index b33e677a..f16b863d 100644 --- a/web-apis/bg/dat-archive.js +++ b/web-apis/bg/dat-archive.js @@ -232,7 +232,7 @@ module.exports = { var reverse = opts.reverse === true var {start, end} = opts var {archive, checkoutFS, isPreview} = await lookupArchive(this.sender, url, opts) - var archiveInfo = {} // TODO await datLibrary.getDaemon().getArchiveInfo(archive.key) + var archiveInfo = await archive.getInfo() if (isPreview) { // dont use the checkout FS in previews, it has no history() api From 9c5d5c4c7d306735349a8693bf65f54d70b62f4a Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 11 Jul 2019 11:23:16 -0500 Subject: [PATCH 06/74] Move folder-sync and preview-mode scopedFS from the old dat-daemon to beaker core --- dat/folder-sync.js | 611 ++++++++++++++++++++++++++++++++++++++++ dat/library.js | 40 ++- web-apis/bg/archives.js | 19 +- 3 files changed, 655 insertions(+), 15 deletions(-) create mode 100644 dat/folder-sync.js diff --git a/dat/folder-sync.js b/dat/folder-sync.js new file mode 100644 index 00000000..36795729 --- /dev/null +++ b/dat/folder-sync.js @@ -0,0 +1,611 @@ +const bytes = require('bytes') +const dft = require('diff-file-tree') +const diff = require('diff') +const anymatch = require('anymatch') +const fs = require('fs') +const jetpack = require('fs-jetpack') +const path = require('path') +const EventEmitter = require('events') +const datEncoding = require('dat-encoding') +const pda = require('pauls-dat-api') +const mkdirp = require('mkdirp') +const isEqual = require('lodash.isequal') +const {toAnymatchRules} = require('@beaker/datignore') +const logger = require('../logger').child({category: 'dat', subcategory: 'folder-sync'}) +const {isFileNameBinary, isFileContentBinary} = require('../lib/mime') +const lock = require('../lib/lock') +const scopedFSes = require('../lib/scoped-fses') +const { + NotFoundError, + NotAFolderError, + ProtectedFileNotWritableError, + ArchiveNotWritableError, + InvalidEncodingError, + SourceTooLargeError +} = require('beaker-error-constants') + +const MAX_DIFF_SIZE = bytes('100kb') + +// typedefs +// = + +/** + * @typedef {import('./daemon').DaemonDatArchive} DaemonDatArchive + */ + +// globals +// = + +var datPath = '' +var disallowedSavePaths = [] +var localSyncSettings = {} // key -> settings object +var syncEventQueues = {} // key -> queue object +var stopWatchingLocalFolderFns = {} // key -> function +var stopWatchingDatIgnoreFns = {} // key -> function +var compareContentCaches = {} // key -> object +var datIgnoreRules = {} // key -> object +var syncCallCounts = {} // key -> number +var activeSyncs = {} // key -> number + +// exported api +// = + +const events = exports.events = new EventEmitter() + +exports.setup = function (opts) { + datPath = opts.datPath + disallowedSavePaths = opts.disallowedSavePaths +} + +exports.reconfigureArchive = function (archive, userSettings) { + var oldLocalSyncSettings = localSyncSettings[archive.key] + localSyncSettings[archive.key] = getLocalSyncSettings(archive, userSettings) + + if (!isEqual(localSyncSettings[archive.key], oldLocalSyncSettings)) { + // configure the local folder watcher if a change occurred + configureFolderToArchiveWatcher(archive) + } + + if (!localSyncSettings[archive.key] || !localSyncSettings[archive.key].isUsingInternal) { + // clear the internal directory if it's not in use + jetpack.removeAsync(getInternalLocalSyncPath(archive)) + } +} + +/** + * @desc Sync dat to the folder + * @param {DaemonDatArchive} archive + * @param {Object} [opts] + * @param {boolean} [opts.shallow=true] dont descend into changed folders (default true) + * @param {boolean} [opts.compareContent=true] compare the actual content (default true) + * @param {string[]} [opts.paths] a whitelist of files to compare + * @param {string} [opts.localSyncPath] override the archive localSyncPath + * @param {boolean} [opts.addOnly=false] dont modify or remove any files (default false) + * @returns {Promise} + */ +const syncArchiveToFolder = exports.syncArchiveToFolder = function (archive, opts = {}) { + opts = opts || {} + return sync(archive, false, opts) +} + +/** + * @desc sync folder to the dat + * @param {DaemonDatArchive} archive + * @param {Object} [opts] + * @param {boolean} [opts.shallow=true] dont descend into changed folders (default true) + * @param {boolean} [opts.compareContent=true] compare the actual content (default true) + * @param {string[]} [opts.paths] a whitelist of files to compare + * @param {string} [opts.localSyncPath] override the archive localSyncPath + * @param {boolean} [opts.addOnly=false] dont modify or remove any files (default false) + * @returns {Promise} + */ +const syncFolderToArchive = exports.syncFolderToArchive = function (archive, opts = {}) { + opts = opts || {} + if (!archive.writable) throw new ArchiveNotWritableError() + return sync(archive, true, opts) +} + +/** + * @desc Helper to wait for sync on an archive to be finished + * @param {DaemonDatArchive} archive + * @returns {Promise} + */ +const ensureSyncFinished = exports.ensureSyncFinished = async function (archive) { + var isFinished + var release = await getArchiveSyncLock(archive) + try { isFinished = (activeSyncs[archive.key] == 0) } + finally { release() } + if (!isFinished) { + return ensureSyncFinished(archive) // check again + } +} + +/** + * @desc Queue a sync event from folder->archive or archive->folder + * - debounces the sync event with a 500ms timeout + * - call with toFolder: true to sync from archive->folder + * - call with toArchive: true to sync from folder->archive + * - if both toFolder && toArchive are queued, toArchive wins (local folder wins) + * - this *will* result in lost changes in the archive if simultaneous changes happen in the local folder, + * but it creates very deterministic results + * @param {DaemonDatArchive} archive + * @param {Object} opts + * @param {boolean} [opts.toFolder=false] + * @param {boolean} [opts.toArchive=false] + * @returns {void} + */ +const queueSyncEvent = exports.queueSyncEvent = function (archive, {toFolder, toArchive}) { + if (!syncEventQueues[archive.key]) { + syncEventQueues[archive.key] = newQueueObj() + } + var queue = syncEventQueues[archive.key] + + // ignore if currently syncing + if (queue.isSyncing) { + logger.silly('Already syncing, ignored') + return + } + + // debounce the handler + if (queue.timeout) { + clearTimeout(queue.timeout) + } + + // queue + if (toFolder) queue.toFolder = true + if (toArchive) queue.toArchive = true + queue.timeout = setTimeout(async () => { + const localSyncPath = localSyncSettings[archive.key].path + const {toArchive, toFolder} = queue + + // lock + queue.isSyncing = true + logger.silly('Ok timed out, beginning sync', {details: {toArchive, toFolder}}) + + try { + let st = await stat(fs, localSyncPath) + if (!st) { + // folder has been removed + stopWatchingLocalFolderFns[archive.key]() + stopWatchingLocalFolderFns[archive.key] = null + logger.warn('Local sync folder not found, aborting watch', {details: {path: localSyncPath}}) + return + } + // sync with priority given to the local folder + if (toArchive) await syncFolderToArchive(archive, {localSyncPath, shallow: false}) + else if (toFolder) await syncArchiveToFolder(archive, {localSyncPath, shallow: false}) + } catch (e) { + logger.error('Error syncing folder', {details: {path: localSyncPath, error: e.toString()}}) + if (e.name === 'CycleError') { + events.emit('error', archive.key, e) + } + } finally { + // reset the queue + queue = newQueueObj() + } + }, 500) +} +function newQueueObj () { + return {timeout: null, toFolder: false, toArchive: false, isSyncing: false} +} + +/** + * @desc Attach/detach a watcher on the local folder and sync it to the dat. + * @param {DaemonDatArchive} archive + * @returns {Promise} + */ +const configureFolderToArchiveWatcher = exports.configureFolderToArchiveWatcher = async function (archive) { + // HACKish + // it's possible that configureFolderToArchiveWatcher() could be called multiple times in sequence + // (for instance because of multiple settings changes) + // this is problematic because the method is async, and a previous call may still be in progress + // shouldAbort() tracks whether such an event has occurred and lets you drop out + // put this after every await: + // + // if (shouldAbort()) return + // + // -prf + var callCount = syncCallCounts[archive.key] = (syncCallCounts[archive.key] || 0) + 1 + const shouldAbort = () => callCount !== syncCallCounts[archive.key] + + // teardown the existing watch (his watch has ended) + // = + + if (stopWatchingLocalFolderFns[archive.key]) { + // stop watching + stopWatchingLocalFolderFns[archive.key]() + stopWatchingLocalFolderFns[archive.key] = null + if (syncEventQueues[archive.key] && syncEventQueues[archive.key].timeout) { + clearTimeout(syncEventQueues[archive.key].timeout) + syncEventQueues[archive.key] = null + } + } + if (stopWatchingDatIgnoreFns[archive.key]) { + stopWatchingDatIgnoreFns[archive.key]() + stopWatchingDatIgnoreFns[archive.key] = null + } + + // start a new watch + // = + + if (localSyncSettings[archive.key]) { + logger.silly('Configuring archive sync', {details: {key: archive.key.toString('hex'), settings: localSyncSettings[archive.key]}}) + + // create diff cache + compareContentCaches[archive.key] = {} + + // create internal folder if needed + if (localSyncSettings[archive.key].isUsingInternal) { + mkdirp.sync(localSyncSettings[archive.key].path) + } + + // make sure the folder exists + let st = await stat(fs, localSyncSettings[archive.key].path) + if (shouldAbort()) return + if (!st) { + logger.warn('Local sync folder not found, aborting watch', {details: {path: localSyncSettings[archive.key].path}}) + } + var scopedFS = scopedFSes.get(localSyncSettings[archive.key].path) + + // track datignore rules + readDatIgnore(scopedFS).then(rules => { datIgnoreRules[archive.key] = rules }) + stopWatchingDatIgnoreFns[archive.key] = scopedFS.watch('/.datignore', async () => { + datIgnoreRules[archive.key] = await readDatIgnore(scopedFS) + }) + + if (!localSyncSettings[archive.key].autoPublish) { + // no need to setup watcher + // just do an add-only sync from archive->folder + await sync(archive, false, {shallow: false, addOnly: true}) + if (shouldAbort()) return + } else { + // sync up + try { + await mergeArchiveAndFolder(archive, localSyncSettings[archive.key].path) + } catch (err) { + logger.error('Failed to merge local sync folder', {details: {err}}) + } + if (shouldAbort()) return + + // start watching + stopWatchingLocalFolderFns[archive.key] = scopedFS.watch('/', path => { + // TODO + // it would be possible to make this more efficient by ignoring changes that match .datignore + // but you need to make sure you have the latest .datignore and reading that on every change-event isnt efficient + // so you either need to: + // A. queue up all the changed paths, then read the datignore inside the timeout and filter, if filteredList.length === 0 then abort + // B. maintain an in-memory copy of the datignore and keep it up-to-date, and then check at time of the event + // -prf + + logger.silly('Change detected', {details: {path}}) + queueSyncEvent(archive, {toArchive: true}) + }) + } + } else { + // clear diff cache + compareContentCaches[archive.key] = {} + } +} + +/** + * @desc List the files that differ. + * @param {DaemonDatArchive} archive + * @param {Object} opts + * @param {boolean} [opts.shallow=true] dont descend into changed folders (default true) + * @param {boolean} [opts.compareContent=true] compare the actual content (default true) + * @param {string[]} [opts.paths] a whitelist of files to compare + * @param {string} [opts.localSyncPath] override the archive localSyncPath + * @returns {Promise} + */ +exports.diffListing = async function (archive, opts = {}) { + opts = opts || {} + var localSyncPath = opts.localSyncPath || (localSyncSettings[archive.key] && localSyncSettings[archive.key].path) + if (!localSyncPath) { + logger.warn('Sanity check failed - diffListing() aborting, no localSyncPath') + return [] + } + var scopedFS = scopedFSes.get(localSyncPath) + opts = massageDiffOpts(opts) + + // build ignore rules + var newOpts = /** @type Object */({...opts}) + if (opts.paths) { + newOpts.filter = makeDiffFilterByPaths(opts.paths) + } else { + const ignoreRules = await readDatIgnore(scopedFS) + newOpts.filter = (filepath) => anymatch(ignoreRules, filepath) + } + + // run diff + newOpts.compareContentCache = compareContentCaches[archive.key] + return dft.diff({fs: scopedFS}, {fs: archive}, newOpts) +} + +/** + * @desc Diff an individual file + * @param {DaemonDatArchive} archive + * @param {string} filepath the path of the file in the archive/folder + * @returns {Promise} + */ +exports.diffFile = async function (archive, filepath) { + if (!localSyncSettings[archive.key].path) { + logger.warn('Sanity check failed - diffFile() aborting, no localSyncPath') + return [] + } + var scopedFS = scopedFSes.get(localSyncSettings[archive.key].path) + filepath = path.normalize(filepath) + + // check the filename to see if it's binary + var isBinary = isFileNameBinary(filepath) + if (isBinary === true) { + throw new InvalidEncodingError('Cannot diff a binary file') + } + + // make sure we can handle the buffers involved + let st + st = await stat(scopedFS, filepath) + if (isBinary !== false && st && st.isFile() && await isFileContentBinary(scopedFS, filepath)) { + throw new InvalidEncodingError('Cannot diff a binary file') + } + if (st && st.isFile() && st.size > MAX_DIFF_SIZE) { + throw new SourceTooLargeError() + } + st = await stat(archive, filepath) + if (isBinary !== false && st && st.isFile() && await isFileContentBinary(archive, filepath)) { + throw new InvalidEncodingError('Cannot diff a binary file') + } + if (st && st.isFile() && st.size > MAX_DIFF_SIZE) { + throw new SourceTooLargeError() + } + + // read the file in both sources + const [newFile, oldFile] = await Promise.all([readFile(scopedFS, filepath), readFile(archive, filepath)]) + + // return the diff + return diff.diffLines(oldFile, newFile) +} + +/** + * @desc Validate a path to be used for sync. + * @param {string} p + */ +exports.assertSafePath = async function (p) { + // check whether this is an OS path + for (let disallowedSavePath of disallowedSavePaths) { + if (path.normalize(p) === path.normalize(disallowedSavePath)) { + throw new ProtectedFileNotWritableError(`This is a protected folder. Please pick another folder or subfolder.`) + } + } + + // stat the folder + const stat = await new Promise(resolve => { + fs.stat(p, (_, st) => resolve(st)) + }) + + if (!stat) { + throw new NotFoundError() + } + + if (!stat.isDirectory()) { + throw new NotAFolderError('Invalid target folder: not a folder') + } +} + +/** + * @desc Read a datignore from a fs space and turn it into anymatch rules. + * @param {Object} fs + * @returns {Promise} + */ +const readDatIgnore = exports.readDatIgnore = async function (fs) { + var rulesRaw = await readFile(fs, '.datignore') + return toAnymatchRules(rulesRaw) +} + +/** + * @desc Filter function used by scoped-fs to hide files in the datignore. + * @param {DaemonDatArchive} archive + * @param {string} filepath + * @return {boolean} + */ +exports.applyDatIgnoreFilter = function (archive, filepath) { + const rules = datIgnoreRules[archive.key] || toAnymatchRules('') + var filepaths = explodeFilePaths(filepath) // we need to check parent paths in addition to the target path + var res = filepaths.filter(p => anymatch(rules, p)).length === 0 + return res +} + +/** + * @desc Merge the dat.json in the folder and then merge files, with preference to folder files. + * @param {DaemonDatArchive} archive + * @param {string} localSyncPath + * @returns {Promise} + */ +const mergeArchiveAndFolder = exports.mergeArchiveAndFolder = async function (archive, localSyncPath) { + logger.silly('Merging archive and folder', {details: {path: localSyncPath, key: archive.key.toString('hex')}}) + const readManifest = async (fs) => { + try { return await pda.readManifest(fs) } catch (e) { return {} } + } + var localFS = scopedFSes.get(localSyncPath) + var localManifest = await readManifest(localFS) + var archiveManifest = await readManifest(archive) + var mergedManifest = Object.assign(archiveManifest || {}, localManifest || {}) + await pda.writeManifest(localFS, mergedManifest) + await sync(archive, false, {localSyncPath, shallow: false, addOnly: true}) // archive -> folder (add-only) + await sync(archive, true, {localSyncPath, shallow: false}) // folder -> archive + events.emit('merge:' + archive.key.toString('hex'), archive.key) + logger.silly('Done merging archive and folder', {details: {path: localSyncPath, key: archive.key.toString('hex')}}) +} + +// internal methods +// = + +/** + * @desc Sync the dat & folder content + * @param {DaemonDatArchive} archive + * @param {boolean} toArchive true to sync folder to archive, false to sync archive to folder + * @param {Object} [opts] + * @param {boolean} [opts.shallow=true] dont descend into changed folders (default true) + * @param {boolean} [opts.compareContent=true] compare the actual content (default true) + * @param {string[]} [opts.paths] a whitelist of files to compare + * @param {string} [opts.localSyncPath] override the archive localSyncPath + * @param {boolean} [opts.addOnly=false] dont modify or remove any files (default false) + * @returns {Promise} + */ +async function sync (archive, toArchive, opts = {}) { + opts = opts || {} + var localSyncPath = opts.localSyncPath || (localSyncSettings[archive.key] && localSyncSettings[archive.key].path) + if (!localSyncPath) { + logger.warn('Sanity check failed - sync() aborting, no localSyncPath') + return + } + + activeSyncs[archive.key] = (activeSyncs[archive.key] || 0) + 1 + var release = await getArchiveSyncLock(archive) + try { + var scopedFS = scopedFSes.get(localSyncPath) + opts = massageDiffOpts(opts) + var diffOpts = /** @type Object */({...opts}) + + // build ignore rules + if (opts.paths) { + diffOpts.filter = makeDiffFilterByPaths(opts.paths) + } else { + let ignoreRules = await readDatIgnore(scopedFS) + diffOpts.filter = (filepath) => anymatch(ignoreRules, filepath) + } + + // choose direction + var left = toArchive ? {fs: scopedFS} : {fs: archive} + var right = toArchive ? {fs: archive} : {fs: scopedFS} + + // run diff + diffOpts.compareContentCache = compareContentCaches[archive.key] + var diff = await dft.diff(left, right, diffOpts) + if (opts.addOnly) { + diff = diff.filter(d => d.change === 'add') + } + logger.silly(`Syncing to ${toArchive ? 'archive' : 'folder'}`, {details: {key: archive.key.toString('hex'), path: localSyncPath}}) + + // sync data + await dft.applyRight(left, right, diff) + events.emit('sync', archive.key, toArchive ? 'archive' : 'folder') + events.emit('sync:' + archive.key.toString('hex'), archive.key, toArchive ? 'archive' : 'folder') + + // decrement active syncs + activeSyncs[archive.key]-- + } catch (err) { + logger.error('Failed to sync archive to local path', {details: {key: archive.key.toString('hex'), path: localSyncPath, err: err.toString()}}) + } finally { + release() + } +} + +/** + * @param {DaemonDatArchive} archive + * @returns {Promise} + */ +function getArchiveSyncLock (archive) { + return lock('sync:' + archive.key.toString('hex')) +} + +/** + * @param {string[]} targetPaths + * @return {Function(string): boolean} + */ +function makeDiffFilterByPaths (targetPaths) { + targetPaths = targetPaths.map(path.normalize) + return (filepath) => { + for (let i = 0; i < targetPaths.length; i++) { + let targetPath = targetPaths[i] + + if (targetPath.endsWith(path.sep)) { + // a directory + if (filepath === targetPath.slice(0, -1)) return false // the directory itself + if (filepath.startsWith(targetPath)) return false // a file within the directory + } else { + // a file + if (filepath === targetPath) return false + } + if (targetPath.startsWith(filepath) && targetPath.charAt(filepath.length) === path.sep) { + return false // a parent folder + } + } + return true + } +} + +/** + * @param {Object} opts + * @returns {Object} + */ +function massageDiffOpts (opts) { + return { + compareContent: typeof opts.compareContent === 'boolean' ? opts.compareContent : true, + shallow: typeof opts.shallow === 'boolean' ? opts.shallow : true, + paths: Array.isArray(opts.paths) ? opts.paths.filter(v => typeof v === 'string') : false, + addOnly: typeof opts.addOnly === 'boolean' ? opts.addOnly : false + } +} + +/** + * @param {string|DaemonDatArchive} archiveOrKey + * @returns {string} + */ +function getInternalLocalSyncPath (archiveOrKey) { + var key = datEncoding.toStr(typeof archiveOrKey === 'string' ? archiveOrKey : archiveOrKey.key) + return path.join(datPath, 'Archives', 'LocalCopy', key.slice(0, 2), key.slice(2)) +} + +/** + * @param {DaemonDatArchive} archive + * @param {Object} userSettings + * @returns {Object} + */ +function getLocalSyncSettings (archive, userSettings) { + if (!archive.writable || !userSettings.isSaved) { + return false + } + if (userSettings.localSyncPath) { + return { + path: userSettings.localSyncPath, + autoPublish: !userSettings.previewMode + } + } + if (userSettings.previewMode) { + return { + path: getInternalLocalSyncPath(archive), + autoPublish: false, + isUsingInternal: true + } + } + return false +} + +// helper to read a file via promise and return a null on fail +async function stat (fs, filepath) { + return new Promise(resolve => { + fs.stat(filepath, (_, data) => { + resolve(data || null) + }) + }) +} + +// helper to read a file via promise and return an empty string on fail +async function readFile (fs, filepath) { + return new Promise(resolve => { + fs.readFile(filepath, {encoding: 'utf8'}, (_, data) => { + resolve(data || '') + }) + }) +} + +// helper to go from '/foo/bar/baz' to ['/', '/foo', '/foo/bar', '/foo/bar/baz'] +function explodeFilePaths (str) { + str = str.replace(/^\/|\/$/g, '') // strip leading and trailing slashes + var paths = str.split('/') + let lastPath = '' + for (let i = 0; i < paths.length; i++) { + lastPath = paths[i] = `${lastPath}/${paths[i]}` + } + return paths +} diff --git a/dat/library.js b/dat/library.js index 715aaade..50c79905 100644 --- a/dat/library.js +++ b/dat/library.js @@ -6,6 +6,7 @@ const signatures = require('sodium-signatures') const parseDatURL = require('parse-dat-url') const _debounce = require('lodash.debounce') const mkdirp = require('mkdirp') +const scopedFSes = require('../lib/scoped-fses') const baseLogger = require('../logger').get() const logger = baseLogger.child({category: 'dat', subcategory: 'library'}) @@ -19,6 +20,7 @@ const datDnsDb = require('../dbs/dat-dns') const daemon = require('./daemon') const datGC = require('./garbage-collector') const datAssets = require('./assets') +const folderSync = require('./folder-sync') // constants // = @@ -43,6 +45,7 @@ const {InvalidURLError, TimeoutError} = require('beaker-error-constants') var archives = {} // in-memory cache of archive objects. key -> archive var archiveLoadPromises = {} // key -> promise var archiveSessionCheckouts = {} // key+version -> DaemonDatArchive +var localSyncSettings = {} // key -> object var archivesEvents = new EventEmitter() // var daemonEvents TODO @@ -59,6 +62,10 @@ var archivesEvents = new EventEmitter() exports.setup = async function setup ({rpcAPI, disallowedSavePaths}) { // connect to the daemon await daemon.setup() + folderSync.setup({ + datPath: archivesDb.getDatPath(), + disallowedSavePaths + }) // daemonEvents = emitStream(daemon.createEventStream()) TODO // pipe the log @@ -91,8 +98,11 @@ exports.setup = async function setup ({rpcAPI, disallowedSavePaths}) { siteData.clearPermissionAllOrigins('modifyDat:' + key) } - // update the download based on these settings - // daemon.configureArchive(key, userSettings) TODO + // update the archive based on these settings + let archive = getArchive(key) + if (archive) { + folderSync.reconfigureArchive(archive, userSettings) + } }) datDnsDb.on('update', ({key, name}) => { var archive = getArchive(key) @@ -356,7 +366,7 @@ async function loadArchiveInner (key, secretKey, userSettings = null) { mkdirp.sync(metaPath) // create the archive session with the daemon - var archive = daemon.createDatArchiveSession({key}) + var archive = await daemon.createDatArchiveSession({key}) // put the archive on the network archive.session.publish() @@ -370,6 +380,9 @@ async function loadArchiveInner (key, secretKey, userSettings = null) { await pullLatestArchiveMeta(archive) datAssets.update(archive) + // configure subsystems + folderSync.reconfigureArchive(archive, userSettings) + // wire up events archive.pullLatestArchiveMeta = _debounce(opts => pullLatestArchiveMeta(archive, opts), 1e3) archive.fileActStream = archive.pda.watch() @@ -379,6 +392,21 @@ async function loadArchiveInner (key, secretKey, userSettings = null) { datAssets.update(archive, [path]) } }) + // TODO + // archive.fileActStream = pda.watch(archive) + // archive.fileActStream.on('data', ([event, {path}]) => { + // if (event === 'changed') { + // if (!archive.localSyncSettings) return + // // need to sync this change to the local folder + // if (archive.localSyncSettings.autoPublish) { + // // bidirectional sync: use the sync queue + // folderSync.queueSyncEvent(archive, {toFolder: true}) + // } else { + // // preview mode: just write this update to disk + // folderSync.syncArchiveToFolder(archive, {paths: [path], shallow: false}) + // } + // } + // }) // now store in main archives listing, as loaded archives[datEncoding.toStr(archive.key)] = archive @@ -401,9 +429,9 @@ exports.getArchiveCheckout = async function getArchiveCheckout (archive, version // ignore, we use latest by default } else if (version === 'preview') { isPreview = true - // TODO need to move scoped-fs management here - // checkoutFS = createArchiveProxy(archive.key, 'preview', archive) - // checkoutFS.domain = archive.domain + checkoutFS = scopedFSes.get(localSyncSettings[archive.key].path) + checkoutFS.setFilter(p => folderSync.applyDatIgnoreFilter(archive, p)) + checkoutFS.domain = archive.domain } else { throw new Error('Invalid version identifier:' + version) } diff --git a/web-apis/bg/archives.js b/web-apis/bg/archives.js index c602bea1..6d87f927 100644 --- a/web-apis/bg/archives.js +++ b/web-apis/bg/archives.js @@ -4,6 +4,7 @@ const jetpack = require('fs-jetpack') const datDns = require('../../dat/dns') const datLibrary = require('../../dat/library') const datGC = require('../../dat/garbage-collector') +const datFolderSync = require('../../dat/folder-sync') const archivesDb = require('../../dbs/archives') const archiveDraftsDb = require('../../dbs/archive-drafts') const {cbPromise} = require('../../lib/functions') @@ -98,7 +99,7 @@ module.exports = { // make sure the path is good try { - // TODO await datLibrary.getDaemon().fs_assertSafePath(localSyncPath) + await datFolderSync.assertSafePath(localSyncPath) } catch (e) { if (e.notFound) { return {doesNotExist: true} @@ -108,7 +109,7 @@ module.exports = { // check for conflicts var archive = await datLibrary.getOrLoadArchive(key) - var diff = [] // TODO await datLibrary.getDaemon().fs_diffListing(archive, {localSyncPath}) + var diff = await datFolderSync.diffListing(archive, {localSyncPath}) diff = diff.filter(d => d.change === 'mod' && d.path !== '/dat.json') if (diff.length) { return {hasConflicts: true, conflicts: diff.map(d => d.path)} @@ -128,7 +129,7 @@ module.exports = { if (opts.deleteSyncPath && oldSettings.localSyncPath) { try { - // TODO await datLibrary.getDaemon().fs_assertSafePath(oldSettings.localSyncPath) + await datFolderSync.assertSafePath(oldSettings.localSyncPath) await jetpack.removeAsync(oldSettings.localSyncPath) } catch (_) {} } @@ -143,7 +144,7 @@ module.exports = { // make sure the path is good try { - // TODO await datLibrary.getDaemon().fs_assertSafePath(localSyncPath) + await datFolderSync.assertSafePath(localSyncPath) } catch (e) { if (e.notFound) { // just create the folder @@ -172,7 +173,7 @@ module.exports = { }) // ensure sync - // TODO await datLibrary.getDaemon().fs_ensureSyncFinished(archive) + await datFolderSync.ensureSyncFinished(archive) }, // diff & publish @@ -188,7 +189,7 @@ module.exports = { archive = await datLibrary.getOrLoadArchive(key) }) - return [] // TODO datLibrary.getDaemon().fs_diffListing(archive, opts) + return datFolderSync.diffListing(archive, opts) }, async diffLocalSyncPathFile (key, filepath) { @@ -201,7 +202,7 @@ module.exports = { archive = await datLibrary.getOrLoadArchive(key) }) - return [] // TODO datLibrary.getDaemon().fs_diffFile(archive, filepath) + return datFolderSync.diffFile(archive, filepath) }, async publishLocalSyncPathListing (key, opts = {}) { @@ -215,7 +216,7 @@ module.exports = { }) opts.shallow = false - return [] // TODO datLibrary.getDaemon().fs_syncFolderToArchive(archive, opts) + return datFolderSync.syncFolderToArchive(archive, opts) }, async revertLocalSyncPathListing (key, opts = {}) { @@ -229,7 +230,7 @@ module.exports = { }) opts.shallow = false - return null // TODO datLibrary.getDaemon().fs_syncArchiveToFolder(archive, opts) + return datFolderSync.syncArchiveToFolder(archive, opts) }, // drafts From d14753608e8c797a0bfc0beb7a6d8aa4e31248b9 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 11 Jul 2019 11:25:04 -0500 Subject: [PATCH 07/74] Replace fork exportArchiveToArchive call --- dat/library.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/dat/library.js b/dat/library.js index 50c79905..5f6a92d7 100644 --- a/dat/library.js +++ b/dat/library.js @@ -6,6 +6,7 @@ const signatures = require('sodium-signatures') const parseDatURL = require('parse-dat-url') const _debounce = require('lodash.debounce') const mkdirp = require('mkdirp') +const pda = require('pauls-dat-api') const scopedFSes = require('../lib/scoped-fses') const baseLogger = require('../logger').get() const logger = baseLogger.child({category: 'dat', subcategory: 'library'}) @@ -286,14 +287,12 @@ exports.forkArchive = async function forkArchive (srcArchiveUrl, manifest = {}, // copy files var ignore = ['/.dat', '/.git', '/dat.json'] - // TODO replace this - console.warn('Fork did not copy data, exportArchiveToArchive() not yet implemented') - // await daemon.exportArchiveToArchive({ - // srcArchive: datEncoding.toStr(srcArchive.key), - // dstArchive: datEncoding.toStr(dstArchive.key), - // skipUndownloadedFiles: true, - // ignore - // }) + await pda.exportArchiveToArchive({ + srcArchive, + dstArchive, + skipUndownloadedFiles: true, + ignore + }) // write a .datignore if DNE try { From 0dc95f1b2564c06ff9ac9c642ed0940a28da1f90 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Sun, 14 Jul 2019 09:29:06 -0500 Subject: [PATCH 08/74] Various fixes to make the hyperdrive-daemon work --- dat/daemon.js | 28 ++++++++++++++++----- dat/library.js | 65 +++++++++++++++++++++++-------------------------- dat/protocol.js | 10 ++++++++ package.json | 2 +- users/index.js | 1 + 5 files changed, 64 insertions(+), 42 deletions(-) diff --git a/dat/daemon.js b/dat/daemon.js index bee34031..11674e42 100644 --- a/dat/daemon.js +++ b/dat/daemon.js @@ -60,10 +60,20 @@ exports.setup = async function () { // fetch daemon metadata from disk var metadata try { - metadata = await loadMetadata() + metadata = await new Promise((resolve, reject) => { + loadMetadata((err, metadata) => { + if (err) reject(err) + else resolve(metadata) + }) + }) } catch (e) { await createMetadata(`localhost:${DAEMON_PORT}`) - metadata = await loadMetadata() + metadata = await new Promise((resolve, reject) => { + loadMetadata((err, metadata) => { + if (err) reject(err) + else resolve(metadata) + }) + }) } // instantiate the daemon @@ -71,6 +81,7 @@ exports.setup = async function () { await startDaemon({ storage: DAEMON_STORAGE_PATH, port: DAEMON_PORT, + bootstrap: [], metadata }) @@ -91,11 +102,11 @@ exports.setup = async function () { exports.createDatArchiveSession = async function (opts) { const session = await client.drive.get(opts) const sessionId = session.id - const key = datEncoding.toStr(opts.key) + const key = datEncoding.toStr(session.opts.key) var datArchive = { key: datEncoding.toBuf(key), url: `dat://${key}`, - writable: false, // TODO + writable: true, // TODO session: { async close () { @@ -127,8 +138,13 @@ exports.createDatArchiveSession = async function (opts) { }) client.drive.stat(sessionId, ...args) }, - readFile: (...args) => client.drive.readFile(sessionId, ...args), - writeFile: (...args) => client.drive.writeFile(sessionId, ...args), + // readFile: (...args) => client.drive.readFile(sessionId, ...args), TODO opts not accepted by daemon yet + readFile: (path, opts, cb) => { + client.drive.readFile(sessionId, path, cb ? cb : opts) + }, + // writeFile: (...args) => client.drive.writeFile(sessionId, ...args), TODO encoding/opts not accepted by daemon yet + writeFile: (path, content, encoding, cb) => client.drive.writeFile(sessionId, path, content, cb), + readdir: (...args) => client.drive.readdir(sessionId, ...args), // ready: makeArchiveProxyCbFn(key, version, 'ready'), // download: makeArchiveProxyCbFn(key, version, 'download'), diff --git a/dat/library.js b/dat/library.js index 5f6a92d7..ffb7e5fe 100644 --- a/dat/library.js +++ b/dat/library.js @@ -119,14 +119,15 @@ exports.setup = async function setup ({rpcAPI, disallowedSavePaths}) { // daemonEvents.on('folder-sync-error', evt => archivesEvents.emit('folder-sync-error', evt)) // configure the bandwidth throttle - settingsDb.getAll().then(({dat_bandwidth_limit_up, dat_bandwidth_limit_down}) => { - daemon.setBandwidthThrottle({ - up: dat_bandwidth_limit_up, - down: dat_bandwidth_limit_down - }) - }) - settingsDb.on('set:dat_bandwidth_limit_up', up => daemon.setBandwidthThrottle({up})) - settingsDb.on('set:dat_bandwidth_limit_down', down => daemon.setBandwidthThrottle({down})) + // TODO + // settingsDb.getAll().then(({dat_bandwidth_limit_up, dat_bandwidth_limit_down}) => { + // daemon.setBandwidthThrottle({ + // up: dat_bandwidth_limit_up, + // down: dat_bandwidth_limit_down + // }) + // }) + // settingsDb.on('set:dat_bandwidth_limit_up', up => daemon.setBandwidthThrottle({up})) + // settingsDb.on('set:dat_bandwidth_limit_down', down => daemon.setBandwidthThrottle({down})) // start the GC manager datGC.setup() @@ -185,9 +186,6 @@ const pullLatestArchiveMeta = exports.pullLatestArchiveMeta = async function pul try { var key = archive.key.toString('hex') - // ready() just in case (we need .blocks) - await pify(archive.ready.bind(archive))() - // trigger DNS update confirmDomain(key) @@ -309,7 +307,6 @@ exports.forkArchive = async function forkArchive (srcArchiveUrl, manifest = {}, const loadArchive = exports.loadArchive = async function loadArchive (key, userSettings = null) { // validate key - var secretKey if (key) { if (!Buffer.isBuffer(key)) { // existing dat @@ -319,35 +316,32 @@ const loadArchive = exports.loadArchive = async function loadArchive (key, userS } key = datEncoding.toBuf(key) } - } else { - // new dat, generate keys - var kp = signatures.keyPair() - key = kp.publicKey - secretKey = kp.secretKey } // fallback to the promise, if possible - var keyStr = datEncoding.toStr(key) - if (keyStr in archiveLoadPromises) { + var keyStr = key ? datEncoding.toStr(key) : null + if (keyStr && keyStr in archiveLoadPromises) { return archiveLoadPromises[keyStr] } // run and cache the promise - var p = loadArchiveInner(key, secretKey, userSettings) - archiveLoadPromises[keyStr] = p + var p = loadArchiveInner(key, userSettings) + if (key) archiveLoadPromises[keyStr] = p p.catch(err => { console.error('Failed to load archive', keyStr, err.toString()) }) // when done, clear the promise - const clear = () => delete archiveLoadPromises[keyStr] - p.then(clear, clear) + if (key) { + const clear = () => delete archiveLoadPromises[keyStr] + p.then(clear, clear) + } return p } // main logic, separated out so we can capture the promise -async function loadArchiveInner (key, secretKey, userSettings = null) { +async function loadArchiveInner (key, userSettings = null) { // load the user settings as needed if (!userSettings) { try { @@ -361,8 +355,9 @@ async function loadArchiveInner (key, secretKey, userSettings = null) { } // ensure the folders exist - var metaPath = archivesDb.getArchiveMetaPath(key) - mkdirp.sync(metaPath) + // TODO needed? + // var metaPath = archivesDb.getArchiveMetaPath(key) + // mkdirp.sync(metaPath) // create the archive session with the daemon var archive = await daemon.createDatArchiveSession({key}) @@ -375,22 +370,22 @@ async function loadArchiveInner (key, secretKey, userSettings = null) { archive.domain = dnsRecord ? dnsRecord.name : undefined // update db - archivesDb.touch(key).catch(err => console.error('Failed to update lastAccessTime for archive', key, err)) + archivesDb.touch(archive.key).catch(err => console.error('Failed to update lastAccessTime for archive', archive.key, err)) await pullLatestArchiveMeta(archive) datAssets.update(archive) - // configure subsystems folderSync.reconfigureArchive(archive, userSettings) // wire up events archive.pullLatestArchiveMeta = _debounce(opts => pullLatestArchiveMeta(archive, opts), 1e3) - archive.fileActStream = archive.pda.watch() - archive.fileActStream.on('data', ([event, {path}]) => { - if (event === 'changed') { - archive.pullLatestArchiveMeta({updateMTime: true}) - datAssets.update(archive, [path]) - } - }) + // TODO + // archive.fileActStream = archive.pda.watch() + // archive.fileActStream.on('data', ([event, {path}]) => { + // if (event === 'changed') { + // archive.pullLatestArchiveMeta({updateMTime: true}) + // datAssets.update(archive, [path]) + // } + // }) // TODO // archive.fileActStream = pda.watch(archive) // archive.fileActStream.on('data', ([event, {path}]) => { diff --git a/dat/protocol.js b/dat/protocol.js index f035670d..9d372761 100644 --- a/dat/protocol.js +++ b/dat/protocol.js @@ -321,6 +321,16 @@ ${html}` }) } + // TODO + // replace this with createReadStream when that method is available + var content = await checkoutFS.pda.readFile(entry.path) + Object.assign(headers, { + 'Content-Type': mime.identify(entry.path) + }) + respond({statusCode, headers, data: intoStream(content)}) + cleanup() + return + // fetch the entry and stream the response fileReadStream = checkoutFS.createReadStream(entry.path, range) var dataStream = fileReadStream diff --git a/package.json b/package.json index 2479c718..ee13367a 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "fs-reverse": "0.0.3", "function-queue": "0.0.12", "hyperdrive-daemon": "^0.9.13", - "hyperdrive-daemon-client": "^0.9.9", + "hyperdrive-daemon-client": "^0.9.10", "hyperdrive-network-speed": "^2.1.0", "icojs": "^0.12.3", "identify-filetype": "^1.0.0", diff --git a/users/index.js b/users/index.js index 83531760..49606951 100644 --- a/users/index.js +++ b/users/index.js @@ -436,6 +436,7 @@ async function validateUserUrl (url) { * @returns {void} */ function startWatch (user) { + return // TODO /* dont await */crawler.watchSite(user.archive) watchThumb(user) watchAndSyncBookmarks(user) From 64f33df781acd0b6d01e78471dd9959cab792bdc Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 8 Aug 2019 13:42:05 -0500 Subject: [PATCH 09/74] Update to latest hyperdrive-daemon & client (0.9.16 and 0.10.1) --- dat/daemon.js | 90 +- dat/library.js | 1 + package-lock.json | 7201 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 4 +- 4 files changed, 7237 insertions(+), 59 deletions(-) create mode 100644 package-lock.json diff --git a/dat/daemon.js b/dat/daemon.js index 11674e42..c41e3eb7 100644 --- a/dat/daemon.js +++ b/dat/daemon.js @@ -1,15 +1,10 @@ -const startDaemon = require('hyperdrive-daemon') +const HyperdriveDaemon = require('hyperdrive-daemon') const { createMetadata } = require('hyperdrive-daemon/lib/metadata') -const { loadMetadata, HyperdriveClient } = require('hyperdrive-daemon-client') +const constants = require('hyperdrive-daemon-client/lib/constants') +const { HyperdriveClient } = require('hyperdrive-daemon-client') const datEncoding = require('dat-encoding') const pda = require('pauls-dat-api') -// constants -// = - -const DAEMON_STORAGE_PATH = require('path').join(require('os').homedir(), '.dat') -const DAEMON_PORT = 3101 - // typedefs // = @@ -18,6 +13,7 @@ const DAEMON_PORT = 3101 * @prop {number} sessionId * @prop {Buffer} key * @prop {string} url +* @prop {string} domain * @prop {boolean} writable * @prop {Object} session * @prop {function(): Promise} session.close @@ -57,36 +53,15 @@ var client // client object created by hyperdrive-daemon-client // = exports.setup = async function () { - // fetch daemon metadata from disk - var metadata - try { - metadata = await new Promise((resolve, reject) => { - loadMetadata((err, metadata) => { - if (err) reject(err) - else resolve(metadata) - }) - }) - } catch (e) { - await createMetadata(`localhost:${DAEMON_PORT}`) - metadata = await new Promise((resolve, reject) => { - loadMetadata((err, metadata) => { - if (err) reject(err) - else resolve(metadata) - }) - }) - } - // instantiate the daemon - // TODO the daemon should be managed in an external promise - await startDaemon({ - storage: DAEMON_STORAGE_PATH, - port: DAEMON_PORT, - bootstrap: [], - metadata - }) + // TODO the daemon should be managed in an external process + await createMetadata(`localhost:${constants.port}`) + var daemon = new HyperdriveDaemon() + await daemon.start() + process.on('exit', () => daemon.stop()) // TODO - client = new HyperdriveClient(metadata.endpoint, metadata.token) + client = new HyperdriveClient() await client.ready() } @@ -100,23 +75,23 @@ exports.setup = async function () { * @returns {Promise} */ exports.createDatArchiveSession = async function (opts) { - const session = await client.drive.get(opts) - const sessionId = session.id - const key = datEncoding.toStr(session.opts.key) + const drive = await client.drive.get(opts) + const key = datEncoding.toStr(drive.key) var datArchive = { key: datEncoding.toBuf(key), url: `dat://${key}`, - writable: true, // TODO + writable: drive.writable, + domain: undefined, session: { async close () { - return client.drive.close(sessionId) + return drive.close() }, async publish () { - return client.drive.publish(sessionId) + return drive.publish() }, async unpublish () { - return client.drive.unpublish(sessionId) + return drive.unpublish() } }, @@ -136,27 +111,28 @@ exports.createDatArchiveSession = async function (opts) { if (st) fixStatObject(st) cb(err, st) }) - client.drive.stat(sessionId, ...args) + drive.stat(...args) }, - // readFile: (...args) => client.drive.readFile(sessionId, ...args), TODO opts not accepted by daemon yet - readFile: (path, opts, cb) => { - client.drive.readFile(sessionId, path, cb ? cb : opts) + lstat (path, opts = {}) { + opts.lstat = true + return this.stat(path, opts) }, + // readFile: (...args) => client.drive.readFile(sessionId, ...args), TODO opts not accepted by daemon yet + readFile: (path, opts, cb) => drive.readFile(path, cb ? cb : opts), // writeFile: (...args) => client.drive.writeFile(sessionId, ...args), TODO encoding/opts not accepted by daemon yet - writeFile: (path, content, encoding, cb) => client.drive.writeFile(sessionId, path, content, cb), - - readdir: (...args) => client.drive.readdir(sessionId, ...args), - // ready: makeArchiveProxyCbFn(key, version, 'ready'), + writeFile: (path, content, opts, cb) => drive.writeFile(path, content, cb ? cb : opts), // download: makeArchiveProxyCbFn(key, version, 'download'), // history: makeArchiveProxyReadStreamFn(key, version, 'history'), - // createReadStream: makeArchiveProxyReadStreamFn(key, version, 'createReadStream'), + createReadStream: (...args) => drive.createReadStream(...args), // createDiffStream: makeArchiveProxyReadStreamFn(key, version, 'createDiffStream'), - // createWriteStream: makeArchiveProxyWriteStreamFn(key, version, 'createWriteStream'), - // unlink: makeArchiveProxyCbFn(key, version, 'unlink'), - // mkdir: makeArchiveProxyCbFn(key, version, 'mkdir'), - // rmdir: makeArchiveProxyCbFn(key, version, 'rmdir'), - // lstat: makeArchiveProxyCbFn(key, version, 'lstat'), - // access: makeArchiveProxyCbFn(key, version, 'access') + createWriteStream: (...args) => drive.createWriteStream(...args), + unlink: (...args) => drive.unlink(...args), + readdir: (...args) => drive.readdir(...args), + mkdir: (...args) => drive.mkdir(...args), + rmdir: (...args) => drive.rmdir(...args), + // access: makeArchiveProxyCbFn(key, version, 'access'), + mount: (...args) => drive.mount(...args), + unmount: (...args) => drive.unmount(...args), } datArchive.pda = createDatArchiveSessionPDA(datArchive) return /** @type DaemonDatArchive */(datArchive) diff --git a/dat/library.js b/dat/library.js index ffb7e5fe..01660eae 100644 --- a/dat/library.js +++ b/dat/library.js @@ -361,6 +361,7 @@ async function loadArchiveInner (key, userSettings = null) { // create the archive session with the daemon var archive = await daemon.createDatArchiveSession({key}) + key = archive.key // put the archive on the network archive.session.publish() diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..16c83895 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,7201 @@ +{ + "name": "@beaker/core", + "version": "3.0.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/polyfill": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.4.4.tgz", + "integrity": "sha512-WlthFLfhQQhh+A2Gn5NSFl0Huxz36x86Jn+E9OW7ibK8edKPq+KLy4apM1yDpQ8kJOVi1OVjpP4vSDLdrI04dg==", + "requires": { + "core-js": "^2.6.5", + "regenerator-runtime": "^0.13.2" + } + }, + "@beaker/dat-ephemeral-ext-msg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@beaker/dat-ephemeral-ext-msg/-/dat-ephemeral-ext-msg-1.0.2.tgz", + "integrity": "sha512-LfuokfkHB4HnHEYxdQS8ulNEVhhixviYGN8CXo1JCuNC9LdtzMVvsggD+aMiZ73MtoBYuDY6bwTpfAEHDlCxkQ==", + "requires": { + "protocol-buffers-encodings": "^1.1.0" + } + }, + "@beaker/dat-serve-resolve-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@beaker/dat-serve-resolve-path/-/dat-serve-resolve-path-1.0.0.tgz", + "integrity": "sha512-ohW9nPTY9gft09Hss8V78Y4rzgYOkbESDjeIDm2KcJIIEEQzdvNFgbGWiPYyPRguYW5ppF7ZorM6huWRbo3bGA==", + "requires": { + "parse-dat-url": "^3.0.2" + } + }, + "@beaker/dat-session-data-ext-msg": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@beaker/dat-session-data-ext-msg/-/dat-session-data-ext-msg-1.1.1.tgz", + "integrity": "sha512-8AofrhwBqfcyK998mCp7Um4d4DJ5udwRDIR9ASQfLPEDIetC5oOKIWAHc+vXC9HN6qzZko31IDSoQvuzgOmwsg==" + }, + "@beaker/datignore": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@beaker/datignore/-/datignore-1.0.0.tgz", + "integrity": "sha512-UMOvwf+efn01go0fV/JqAZIgrrObphXwdROgCoPZM+g6iCzeoA9G2vQwfULuw5W4XGHIj+Ro689zFNKfRXTHiw==" + }, + "@grpc/grpc-js": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-0.5.2.tgz", + "integrity": "sha512-NE1tP/1AF6BqhLdILElnF7aOBfoky+4ZOdZU/0NmKo2d+9F9QD8zGoElpBk/5BfyQZ3u1Zs+wFbDOFpVUzDx1w==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@hyperswarm/dht": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@hyperswarm/dht/-/dht-1.0.0.tgz", + "integrity": "sha512-tfg2K44ddpQZ7M25Lys3gDtXIK+5EcUA5sAGOCLtANGNjXc1T8qYLlviJIWdo0ucKnrEJK8Ag+7L3U9hbNTyFg==", + "requires": { + "dht-rpc": "^4.1.6", + "end-of-stream": "^1.4.1", + "hashlru": "^2.3.0", + "ipv4-peers": "^2.0.0", + "protocol-buffers-encodings": "^1.1.0", + "record-cache": "^1.1.0", + "sodium-universal": "^2.0.0" + } + }, + "@hyperswarm/discovery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@hyperswarm/discovery/-/discovery-1.4.0.tgz", + "integrity": "sha512-UqQCX5kqAvMoXWA90212o9MNCMyzDZ6i8k6vJSAMcWvvr/qDSbaHIEiRBKGsOzE9J0LbY/lDBTuNjO/6UZu20Q==", + "requires": { + "@hyperswarm/dht": "^1.0.0", + "multicast-dns": "^7.2.0" + } + }, + "@hyperswarm/network": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@hyperswarm/network/-/network-1.0.0.tgz", + "integrity": "sha512-mWoUbg35uPKDVbtXKr5+OcK/mrsNRWPPrYfOXvSBUeWMh6+Kcbw8PMOYdKPFYiVw/MKh+gOYI4zkD+IpcW6cFA==", + "requires": { + "@hyperswarm/discovery": "^1.2.0", + "nanoresource": "^1.0.0", + "utp-native": "^2.1.3" + } + }, + "@mafintosh/streamx": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mafintosh/streamx/-/streamx-1.1.0.tgz", + "integrity": "sha512-m2Cy1Pne981Uyg6Odd7ysc4cIDs4bBFoB7JrTp9kRwWYGVGEXwEPDMJnX5VyaKIrw8ypzlR2NO+wVIb/bnKtWw==", + "requires": { + "fast-fifo": "^1.0.0", + "nanoassert": "^2.0.0" + }, + "dependencies": { + "nanoassert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz", + "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==" + } + } + }, + "@types/bluebird": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.27.tgz", + "integrity": "sha512-6BmYWSBea18+tSjjSC3QIyV93ZKAeNWGM7R6aYt1ryTZXrlHF+QLV0G2yV0viEGVyRkyQsWfMoJ0k/YghBX5sQ==" + }, + "@types/node": { + "version": "12.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.1.tgz", + "integrity": "sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==", + "optional": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "abstract-leveldown": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-5.0.0.tgz", + "integrity": "sha512-5mU5P1gXtsMIXg65/rsYGsi93+MlogXZ9FA8JnwKurHQg64bfXwGYVdVdijNTVNOlAsuIiOwHdvFFD5JqCJQ7A==", + "requires": { + "xtend": "~4.0.0" + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=" + }, + "array-lru": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-lru/-/array-lru-1.1.1.tgz", + "integrity": "sha1-DH4bTgIq4Wb/HoRIxZXzGB/NMzc=" + }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "atomic-batcher": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/atomic-batcher/-/atomic-batcher-1.0.2.tgz", + "integrity": "sha1-0WkB0QzOxZUWwZe5zNiTBom4E7Q=" + }, + "await-lock": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-1.1.3.tgz", + "integrity": "sha512-e0jRB8X/VVxulahjW16cM1dHsO7xjyZBP8p2AnVmg2Vn3q5xJ5sTUAybmkp96+s+QcrtidSJqpCGfWhVOX7NGg==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "beaker-error-constants": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/beaker-error-constants/-/beaker-error-constants-1.4.0.tgz", + "integrity": "sha512-F3iMA2F01w0q5eiZgD/wUQULNDdLCA99GR6yFEjhvyZfK10WdeESRUGTPeJk83qiIn0F8ZSmR6YWOG6I0EkoLA==" + }, + "bencode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bencode/-/bencode-1.0.0.tgz", + "integrity": "sha512-N+VOSP5MkoX+xgnp6Y056iCY5TmCZg9rgPNPQe0bIiXchxYFP4vs/Tf0dTdQ+qQhP7HM2gvfFq+sUVjQsGy5Zw==", + "requires": { + "safe-buffer": "^5.1.1" + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, + "bindings": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.1.tgz", + "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==" + }, + "bitfield-rle": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bitfield-rle/-/bitfield-rle-2.2.1.tgz", + "integrity": "sha512-wrDhHe7LUkqaytxgbsFXoemzHRv6e8FrVNWWsQCgUfmuVYW6ke44hoGc9VdpjgfIsJ/ejmCFA8wDtDqACNAvyw==", + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "varint": "^4.0.0" + }, + "dependencies": { + "varint": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/varint/-/varint-4.0.1.tgz", + "integrity": "sha1-SQgpuULSSEY7KzUJeZXDv3NxmOk=" + } + } + }, + "bittorrent-dht": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/bittorrent-dht/-/bittorrent-dht-7.10.0.tgz", + "integrity": "sha512-fvb6M58Ceiv/S94nu6zeaiMoJvUYOeIqRbgaClm+kJTzCAqJPtAR/31pXNYB5iEReOoKqQB5zY33gY0W6ZRWQQ==", + "requires": { + "bencode": "^1.0.0", + "buffer-equals": "^1.0.3", + "debug": "^3.1.0", + "inherits": "^2.0.1", + "k-bucket": "^3.3.0", + "k-rpc": "^4.2.1", + "lru": "^3.1.0", + "randombytes": "^2.0.5", + "safe-buffer": "^5.0.1", + "simple-sha1": "^2.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "blake2b": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.3.tgz", + "integrity": "sha512-pkDss4xFVbMb4270aCyGD3qLv92314Et+FsKzilCLxDz5DuZ2/1g3w4nmBbu6nKApPspnjG7JcwTjGZnduB1yg==", + "requires": { + "blake2b-wasm": "^1.1.0", + "nanoassert": "^1.0.0" + } + }, + "blake2b-wasm": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/blake2b-wasm/-/blake2b-wasm-1.1.7.tgz", + "integrity": "sha512-oFIHvXhlz/DUgF0kq5B1CqxIDjIJwh9iDeUUGQUcvgiGz7Wdw03McEO7CfLBy7QKGdsydcMCgO9jFNBAFCtFcA==", + "requires": { + "nanoassert": "^1.0.0" + } + }, + "bluebird": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" + }, + "bmp-js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", + "integrity": "sha1-4Fpj95amwf8l9Hcex62twUjAcjM=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "broadway": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/broadway/-/broadway-0.3.6.tgz", + "integrity": "sha1-fb7waLlUt5B5Jf1USWO1eKkCuno=", + "requires": { + "cliff": "0.1.9", + "eventemitter2": "0.4.14", + "nconf": "0.6.9", + "utile": "0.2.1", + "winston": "0.8.0" + }, + "dependencies": { + "cliff": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/cliff/-/cliff-0.1.9.tgz", + "integrity": "sha1-ohHgnGo947oa8n0EnTASUNGIErw=", + "requires": { + "colors": "0.x.x", + "eyes": "0.1.x", + "winston": "0.8.x" + } + }, + "winston": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-0.8.0.tgz", + "integrity": "sha1-YdCDD6aZcGISIGsKK1ymmpMENmg=", + "requires": { + "async": "0.2.x", + "colors": "0.6.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "pkginfo": "0.3.x", + "stack-trace": "0.0.x" + } + } + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "buffer-equals": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/buffer-equals/-/buffer-equals-1.0.4.tgz", + "integrity": "sha1-A1O1T9B/2VZBcGca5vZrnPENJ/U=" + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-json/-/buffer-json-2.0.0.tgz", + "integrity": "sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw==" + }, + "buffer-json-encoding": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-json-encoding/-/buffer-json-encoding-1.0.2.tgz", + "integrity": "sha512-zH4Q0aqJnv0xPVX+Imcp+EbiyYg9xq7//mvShmQ08E6wC1EeYg2+1OG2n9EEu0rfiuYjP+j5LsSmQVufdqflrg==", + "requires": { + "buffer-json": "^2.0.0" + } + }, + "bulk-write-stream": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bulk-write-stream/-/bulk-write-stream-1.1.4.tgz", + "integrity": "sha512-GtKwd/4etuk1hNeprXoESBO1RSeRYJMXKf+O0qHmWdUomLT8ysNEfX/4bZFXr3BK6eukpHiEnhY2uMtEHDM2ng==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.1.4" + } + }, + "byte-stream": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/byte-stream/-/byte-stream-2.1.0.tgz", + "integrity": "sha1-Mu7LpiU4IdaVELnPNLMVzj5Vsxo=", + "requires": { + "debug": "^1.0.4", + "readable-stream": "~1.1.10" + }, + "dependencies": { + "debug": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.5.tgz", + "integrity": "sha1-9yQSF0MPmd7EwrRz6rkiKOh0wqw=", + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" + }, + "caller": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/caller/-/caller-0.0.1.tgz", + "integrity": "sha1-83odbqEOgp2UchrimpC7T7Uqt2c=", + "requires": { + "tape": "~2.3.2" + } + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "^0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + }, + "dependencies": { + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "requires": { + "is-extglob": "^1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + } + } + }, + "chownr": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz", + "integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==" + }, + "chrome-dgram": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/chrome-dgram/-/chrome-dgram-3.0.2.tgz", + "integrity": "sha512-Ay741EHF/Ib18un+LUtBNK43NrabD6GOuwVaka7uUbV0gFRLEPULm2Q05YSzRNBtSrbaO4eErmDdniiy/u8Lig==", + "requires": { + "inherits": "^2.0.1", + "run-series": "^1.1.2" + } + }, + "chrome-net": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/chrome-net/-/chrome-net-3.3.2.tgz", + "integrity": "sha512-BHxWfA9MDnh0C1By5q1DnF1vRS7vfBi2PrqTHIIt1HA4hM6l2xkHzoazbDlZcrDrMfjNs6fojKG+ZD0JmlnNWg==", + "requires": { + "inherits": "^2.0.1" + } + }, + "circular-append-file": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/circular-append-file/-/circular-append-file-1.0.1.tgz", + "integrity": "sha512-BUDFvrBTCdeVhg9E05PX4XgMegk6xWB69uGwyuATEg7PMfa9lGU1mzFSK0xWNW2O0i9CAQHN0oIdXI/kI2hPkg==", + "requires": { + "multistream": "^2.1.0" + } + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliff": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/cliff/-/cliff-0.1.10.tgz", + "integrity": "sha1-U74z6p9ZvshWCe4wCsQgdgPlIBM=", + "requires": { + "colors": "~1.0.3", + "eyes": "~0.1.8", + "winston": "0.8.x" + }, + "dependencies": { + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" + }, + "winston": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-0.8.3.tgz", + "integrity": "sha1-ZLar9M0Brcrv1QCTk7HY6L7BnbA=", + "requires": { + "async": "0.2.x", + "colors": "0.6.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "pkginfo": "0.3.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + } + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "codecs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/codecs/-/codecs-2.0.0.tgz", + "integrity": "sha512-WXvpJRAgc693oqYvZte9uYEiL5YHtfrxyEq12uVny9oBJ1k37zSva5vVz7trsnt6R9Y15hEgOSC7VFZT2pfYnA==" + }, + "collect-stream": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/collect-stream/-/collect-stream-1.2.1.tgz", + "integrity": "sha1-gptBdGQxseJ+AebNPQrBY8IqHKc=", + "requires": { + "concat-stream": "^1.2.0", + "once": "^1.3.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorette": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.0.8.tgz", + "integrity": "sha512-X6Ck90ReaF+EfKdVGB7vdIQ3dr651BbIrBwY5YBKg13fjH+940sTtp7/Pkx33C6ntYfQcRumOs/aUQhaRPpbTQ==" + }, + "colornames": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", + "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" + }, + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + }, + "colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "connections": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/connections/-/connections-1.4.2.tgz", + "integrity": "sha1-eJBIK/XHGvbFyhkr4xNq7XRCiq0=" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-js": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "corestore": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/corestore/-/corestore-2.0.0.tgz", + "integrity": "sha512-KcVd385RQna+dNgcPmWPAbMw4h9g4IoITfggvcHm7XOREvraFAwKv6LdnB1pIcSSwCh+UNoaUpPRIkycYgyjlA==", + "requires": { + "dat-encoding": "^5.0.1", + "hypercore": "^7.2.2", + "hypercore-crypto": "^1.0.0", + "hypercore-protocol": "^6.11.0" + } + }, + "corestore-swarm-networking": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/corestore-swarm-networking/-/corestore-swarm-networking-1.0.4.tgz", + "integrity": "sha512-UvaMd5p/OvrX9bMrD/4Vc8u+tVrFO6w8Ilujv7fmZvfilST7L8qKEHyJzjeXI+AaZZwS8Fr3+w7/a1g3nUdlqw==", + "requires": { + "dat-encoding": "^5.0.1", + "dat-swarm-defaults": "^1.0.2", + "duplexify": "^4.0.0", + "hypercore-protocol": "^6.11.0", + "hyperswarm": "^2.0.2", + "pump": "^3.0.0" + } + }, + "count-trailing-zeros": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/count-trailing-zeros/-/count-trailing-zeros-1.0.1.tgz", + "integrity": "sha1-q6bFgzvkENRbHso+bVg4RM5oLHc=" + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" + }, + "custom-error-class": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/custom-error-class/-/custom-error-class-1.0.0.tgz", + "integrity": "sha512-bHT5BAycUbsHYexiPuoIEM/o770u48yWBrZHw/f+BRVkERn19xTgNwcHt79A/AYMxUcOfPjb9OrKoj6rVvPJuA==" + }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "dat-dns": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/dat-dns/-/dat-dns-3.2.1.tgz", + "integrity": "sha512-gCfU2FBg41Qg7RgqYBRD3bjYWAaJFO6UvKfCU9SA1LBy6vZ3EoTZH5doCYdTTQmVEsAxMef18W0lnvr1Z7rx0g==", + "requires": { + "call-me-maybe": "^1.0.1", + "concat-stream": "^1.6.0", + "debug": "^4.1.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "dat-encoding": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/dat-encoding/-/dat-encoding-5.0.1.tgz", + "integrity": "sha512-PET9PlGt6ejgqU07hbPLx3tP2siDMMFumUe+xwmm4+5W+0cOlpzreCPoMVUBzxWeR4sPdxL+AS53odQTBtzEqA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "dat-swarm-defaults": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/dat-swarm-defaults/-/dat-swarm-defaults-1.0.2.tgz", + "integrity": "sha512-gz9RuhUxq3coYBrelzuFXCNyC579aO3Bm1Wlwa12/9tJr1NP0AAGxpHJYA1HZvt8X7ZdrtMzpFyNvs2Y9PFG6w==" + }, + "datland-swarm-defaults": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/datland-swarm-defaults/-/datland-swarm-defaults-1.0.2.tgz", + "integrity": "sha1-J3uJWjnxqn+WpJWgL7NmKl7Z8uA=", + "requires": { + "xtend": "^4.0.1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decode-bmp": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/decode-bmp/-/decode-bmp-0.1.0.tgz", + "integrity": "sha512-i7ImaOawHIwQNIt3IpO8X04ZRGI4A7gqX3vPw5aMIqMwsAk5xs/pnWLKmXc97nII5rSGJB9QyauO5FwctFiYoQ==", + "requires": { + "to-data-view": "^1.0.0" + } + }, + "decode-ico": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/decode-ico/-/decode-ico-0.3.1.tgz", + "integrity": "sha512-Ejv981YSYeAVyebE+g/Z/3hhE9wLE0uOBmiglqnhRfVMbLu1mf0CCesOoFWjdDqDYBOWIYLHJ6+uQxjlID3FEg==", + "requires": { + "decode-bmp": "^0.1.0", + "to-data-view": "^1.0.0" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "deferred-leveldown": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-4.0.2.tgz", + "integrity": "sha512-5fMC8ek8alH16QiV0lTCis610D1Zt1+LA4MS4d63JgS32lrCjTFDUFz2ao09/j2I4Bqb5jL4FZYwu7Jz0XO1ww==", + "requires": { + "abstract-leveldown": "~5.0.0", + "inherits": "^2.0.3" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "defined": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz", + "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, + "dht-rpc": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/dht-rpc/-/dht-rpc-4.1.6.tgz", + "integrity": "sha512-12jlZgwv6EQw+415Q8HlRokjwkUbHMNPIgbK8V0u4HDnaZ6MfbuKUEkS0BC6wX3HFZ1jVPSKp+KinLet33WfJQ==", + "requires": { + "codecs": "^2.0.0", + "ipv4-peers": "^2.0.0", + "k-bucket": "^5.0.0", + "protocol-buffers-encodings": "^1.1.0", + "sodium-universal": "^2.0.0", + "stream-collector": "^1.0.1", + "time-ordered-set": "^1.0.1", + "xor-distance": "^2.0.0" + }, + "dependencies": { + "k-bucket": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/k-bucket/-/k-bucket-5.0.0.tgz", + "integrity": "sha512-r/q+wV/Kde62/tk+rqyttEJn6h0jR7x+incdMVSYTqK73zVxVrzJa70kJL49cIKen8XjIgUZKSvk8ktnrQbK4w==", + "requires": { + "randombytes": "^2.0.3" + } + } + } + }, + "diagnostics": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "requires": { + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" + }, + "diff-file-tree": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/diff-file-tree/-/diff-file-tree-2.2.0.tgz", + "integrity": "sha512-2vvgzQLCQGNnc6WRVHhvn2L+C5/Lam7DYgY/vPfuXno3OpNhcuhZf+B86zptQm8yEzxthzmdslIO08wodMB5Bw==", + "requires": { + "debug": "^2.6.4", + "es6-promisify": "^5.0.0", + "pump": "^1.0.2", + "stream-equal": "^1.0.0", + "tempy": "^0.1.0" + }, + "dependencies": { + "pump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "director": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/director/-/director-1.2.7.tgz", + "integrity": "sha1-v9N0EHX9f7GlsuE2WMX0vsd3NvM=" + }, + "discovery-channel": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/discovery-channel/-/discovery-channel-5.5.1.tgz", + "integrity": "sha512-EEmZQFE0PiOsJj7G3KVCwFGbYs4QchUvzA91iHtZ6HfkIqfBEDSTGLygJrUlY1Tr77WDV+qZVrZuNghHxSL/vw==", + "requires": { + "bittorrent-dht": "^7.10.0", + "buffer-from": "^1.0.0", + "debug": "^2.6.9", + "dns-discovery": "^6.0.1", + "pretty-hash": "^1.0.1", + "thunky": "^0.1.0" + } + }, + "discovery-swarm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/discovery-swarm/-/discovery-swarm-6.0.0.tgz", + "integrity": "sha512-ByfwygfLCB4umpSBVz9tGxgmng1D3YWg6A80cip8dgdpC5dRyGsL5w6KoC9srQ15xydKtYPgcxUC2YtSzPCtHA==", + "requires": { + "connections": "^1.4.2", + "debug": "^4.1.1", + "discovery-channel": "^5.5.1", + "length-prefixed-message": "^3.0.3", + "pump": "^3.0.0", + "to-buffer": "^1.0.1", + "utp-native": "^2.1.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "dns-discovery": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/dns-discovery/-/dns-discovery-6.2.3.tgz", + "integrity": "sha512-ZULG1R5J9QHZfaXo5XFGVG22LIcnZorbEa7f83FYgCGDaQrVfyVmty3Z89OvBLpCPetwW+LzjCcT60ekhbQ+9g==", + "requires": { + "circular-append-file": "^1.0.1", + "debug": "^2.6.9", + "dns-socket": "^3.0.0", + "lru": "^2.0.0", + "minimist": "^1.2.0", + "multicast-dns": "^7.1.1", + "network-address": "^1.1.2", + "pump": "^3.0.0", + "speedometer": "^1.0.0", + "unordered-set": "^1.1.0" + }, + "dependencies": { + "lru": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lru/-/lru-2.0.1.tgz", + "integrity": "sha1-+XmHHhYuP1yiVL5GhExT1MU2RUQ=", + "requires": { + "inherits": "^2.0.1" + } + } + } + }, + "dns-packet": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-4.2.0.tgz", + "integrity": "sha512-bn1AKpfkFbm0MIioOMHZ5qJzl2uypdBwI4nYNsqvhjsegBhcKJUlCrMPWLx6JEezRjxZmxhtIz/FkBEur2l8Cw==", + "requires": { + "ip": "^1.1.5", + "safe-buffer": "^5.1.1" + } + }, + "dns-socket": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/dns-socket/-/dns-socket-3.0.0.tgz", + "integrity": "sha512-M0WkByoJ/mTm+HtwBQLsRJPe5uGIC/lYVOp+s6ZzhbZ5iq4GxjFyxYPQhB85dgCLvVb43aJQXHDC9aUgyKGc/Q==", + "requires": { + "dns-packet": "^4.1.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "emit-stream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/emit-stream/-/emit-stream-0.1.2.tgz", + "integrity": "sha1-DiBVCKDQ1tM0YHhC98R2nb+/Fug=", + "requires": { + "through": "~2.3.4" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "enabled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "requires": { + "env-variable": "0.0.x" + } + }, + "encoding-down": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-5.0.4.tgz", + "integrity": "sha512-8CIZLDcSKxgzT+zX8ZVfgNbu8Md2wq/iqa1Y7zyVR18QBEAc0Nmzuvj/N5ykSKpfGzjM8qxbaFntLPwnVoUhZw==", + "requires": { + "abstract-leveldown": "^5.0.0", + "inherits": "^2.0.3", + "level-codec": "^9.0.0", + "level-errors": "^2.0.0", + "xtend": "^4.0.1" + } + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "requires": { + "once": "^1.4.0" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "env-variable": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", + "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "requires": { + "prr": "~1.0.1" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "dev": true, + "requires": { + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + } + } + }, + "eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "event-stream": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-0.5.3.tgz", + "integrity": "sha1-t3uTCfcQet3+q2PwwOr9jbC9jBw=", + "requires": { + "optimist": "0.2" + }, + "dependencies": { + "optimist": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.2.8.tgz", + "integrity": "sha1-6YGrfiaLRXlIWTtVZ0wJmoFcrDE=", + "requires": { + "wordwrap": ">=0.0.1 <0.1.0" + } + } + } + }, + "eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=" + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "requires": { + "fill-range": "^2.1.0" + }, + "dependencies": { + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dev": true, + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, + "fast-bitfield": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/fast-bitfield/-/fast-bitfield-1.2.2.tgz", + "integrity": "sha512-t8HYqkuE3YEqNcyWlAfh55479aTxO+GpYwvQvJppYqyBfSmRdNIhzY2m09FKN/MENTzq4wH6heHOIvsPyMAwvQ==", + "requires": { + "count-trailing-zeros": "^1.0.1" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-fifo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.0.0.tgz", + "integrity": "sha512-4VEXmjxLj7sbs8J//cn2qhRap50dGzF5n8fjay8mau+Jn4hxSeR3xPFwxMaQq/pDaq7+KQk0PAbC2+nWDkJrmQ==" + }, + "fast-future": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fast-future/-/fast-future-1.0.2.tgz", + "integrity": "sha1-hDWpqqAteSSNF9cE52JZMB2ZKAo=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fast-redact": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-1.5.0.tgz", + "integrity": "sha512-Afo61CgUjkzdvOKDHn08qnZ0kwck38AOGcMlvSGzvJbIab6soAP5rdoQayecGCDsD69AiF9vJBXyq31eoEO2tQ==" + }, + "fast-safe-stringify": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", + "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==" + }, + "fd-lock": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fd-lock/-/fd-lock-1.0.2.tgz", + "integrity": "sha512-8O4zSv6rlNNghVfzVkj/p7LUIeBm7Xxk6QnhfmR1WJm/W4kwS8IyShy4X1peRnFUYZUYLlcwEMKXF8QWxJCMvg==", + "optional": true, + "requires": { + "napi-macros": "^1.8.2", + "node-gyp-build": "^3.8.0" + } + }, + "fecha": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + }, + "dependencies": { + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + } + } + }, + "file-type": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz", + "integrity": "sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw==" + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" + }, + "filesystem-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/filesystem-constants/-/filesystem-constants-1.0.0.tgz", + "integrity": "sha512-/ue62eYa8Mk53dc1XXxT1nhwat3ygWMepjrFON8tBVjtjCTVUzM8JTEAQquNoZnmimM4dbxfV9tZeEav1KUccg==" + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "dependencies": { + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + } + } + }, + "fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + } + }, + "flat-tree": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/flat-tree/-/flat-tree-1.6.0.tgz", + "integrity": "sha1-/KMM3bkAb7ZW6168ea6ydOf96e0=" + }, + "flatiron": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/flatiron/-/flatiron-0.4.3.tgz", + "integrity": "sha1-JIz3mj2n19w3nioRySonGcu1QPY=", + "requires": { + "broadway": "~0.3.2", + "director": "1.2.7", + "optimist": "0.6.0", + "prompt": "0.2.14" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + }, + "optimist": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.0.tgz", + "integrity": "sha1-aUJIJvNAX3nxQub8PZrljU27kgA=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + } + } + }, + "flatstr": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz", + "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "requires": { + "for-in": "^1.0.1" + } + }, + "forever": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/forever/-/forever-0.15.3.tgz", + "integrity": "sha1-d9nX4V/S9RGtnYShEMfdj8js68I=", + "requires": { + "cliff": "~0.1.9", + "clone": "^1.0.2", + "colors": "~0.6.2", + "flatiron": "~0.4.2", + "forever-monitor": "~1.7.0", + "nconf": "~0.6.9", + "nssocket": "~0.5.1", + "object-assign": "^3.0.0", + "optimist": "~0.6.0", + "path-is-absolute": "~1.0.0", + "prettyjson": "^1.1.2", + "shush": "^1.0.0", + "timespan": "~2.3.0", + "utile": "~0.2.1", + "winston": "~0.8.1" + }, + "dependencies": { + "winston": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-0.8.3.tgz", + "integrity": "sha1-ZLar9M0Brcrv1QCTk7HY6L7BnbA=", + "requires": { + "async": "0.2.x", + "colors": "0.6.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "pkginfo": "0.3.x", + "stack-trace": "0.0.x" + } + } + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "forever-monitor": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/forever-monitor/-/forever-monitor-1.7.1.tgz", + "integrity": "sha1-XYIPSjp42y2BriZx8Vi56GoJG7g=", + "requires": { + "broadway": "~0.3.6", + "chokidar": "^1.0.1", + "minimatch": "~3.0.2", + "ps-tree": "0.0.x", + "utile": "~0.2.1" + } + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-jetpack": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/fs-jetpack/-/fs-jetpack-1.3.1.tgz", + "integrity": "sha512-oCrJI4kSredslsM3iZoZ19RKUt78XyyOSJuwzg/JGIxCBmjaoqPpvqAy5ZaUNI/QHJPL0UkKeX/yarAd39vP/Q==", + "requires": { + "minimatch": "^3.0.2" + } + }, + "fs-minipass": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz", + "integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==", + "requires": { + "minipass": "^2.2.1" + } + }, + "fs-reverse": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/fs-reverse/-/fs-reverse-0.0.3.tgz", + "integrity": "sha512-zu+5yhmaWueDBAWm7y6ejj2PipVep3EQlQYdfS6r3zsfzIfTVkcdbrsqye2UovisDqogu5dJFxae/dUAOYQqBA==", + "requires": { + "from": "~0.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "optional": true + } + } + }, + "function-queue": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/function-queue/-/function-queue-0.0.12.tgz", + "integrity": "sha1-us+7w90sMqWnY+/aGZ+wBgDQ/Zo=" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "fuse-native": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fuse-native/-/fuse-native-1.1.2.tgz", + "integrity": "sha512-+InNbU/xodg6wUQvqcZaxL070/si0TyinxlnzyHm0XsMffgy7VOz7wi6+jfgOtdhfUtJs9tvY4zHu1/UfYIRxw==", + "optional": true, + "requires": { + "fuse-shared-library": "^1.0.1", + "nan": "^2.13.2", + "napi-macros": "^1.8.2", + "node-gyp-build": "^3.2.2", + "xtend": "^4.0.1" + } + }, + "fuse-shared-library": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fuse-shared-library/-/fuse-shared-library-1.0.1.tgz", + "integrity": "sha512-B28UMu1yKCK+Cr2UnC5ykAZQhw9arcPcvwzQyoo3jjKzdy1a8OBxXHtf5UlRVjVw//JIPKFgW10AfTl0TOi6SA==", + "optional": true, + "requires": { + "fuse-shared-library-darwin": "^1.0.0", + "fuse-shared-library-linux": "^1.0.0" + } + }, + "fuse-shared-library-darwin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fuse-shared-library-darwin/-/fuse-shared-library-darwin-1.0.1.tgz", + "integrity": "sha512-thQh0BsvIK93pPV/8a25HmIzxmmGKKedw3KZTxy/4Y7D+Rix/3bT0EcCQ4Ll+U1EkDGy+1Px18B1PsHu4J+z7w==", + "optional": true + }, + "fuse-shared-library-linux": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fuse-shared-library-linux/-/fuse-shared-library-linux-1.0.1.tgz", + "integrity": "sha512-07MQRSobrBKwW4D7oKm0gM2TwgvZWb+gC08JdiYDG4KBTncxk9ssqEDiDMKll8hpseZufsY2w1yc/feOu2DPmQ==", + "optional": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "requires": { + "is-property": "^1.0.2" + } + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "requires": { + "is-property": "^1.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "getopts": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.4.tgz", + "integrity": "sha512-Rz7DGyomZjrenu9Jx4qmzdlvJgvrEFHXHvjK0FcZtcTC1U5FmES7OdZHUwMuSnEE6QvBvwse1JODKj7TgbSEjQ==" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "requires": { + "is-glob": "^2.0.0" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "google-protobuf": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.9.1.tgz", + "integrity": "sha512-tkz7SVwBktFbqFK3teXFUY/VM57+mbUgV9bSD+sZH1ocHJ7uk7BfEWMRdU24dd0ciUDokreA7ghH2fYFIczQdw==" + }, + "graceful-fs": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.1.tgz", + "integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==" + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + } + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hashlru": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hashlru/-/hashlru-2.3.0.tgz", + "integrity": "sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==" + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "hypercore": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/hypercore/-/hypercore-7.6.1.tgz", + "integrity": "sha512-ZQ1HdFXa9D5cSwXiu6vldYSE5ro6OBtyWdnFr8L/U3PFDCEpIyhyLvoRTscmP+7U2U9ZYSV3NoNHjWlNPIA8Gw==", + "requires": { + "array-lru": "^1.1.0", + "atomic-batcher": "^1.0.2", + "bitfield-rle": "^2.2.1", + "bulk-write-stream": "^1.1.3", + "codecs": "^2.0.0", + "fast-bitfield": "^1.2.2", + "fd-lock": "^1.0.2", + "flat-tree": "^1.6.0", + "from2": "^2.3.0", + "hypercore-crypto": "^1.0.0", + "hypercore-protocol": "^6.5.0", + "inherits": "^2.0.3", + "inspect-custom-symbol": "^1.1.0", + "last-one-wins": "^1.0.4", + "memory-pager": "^1.0.2", + "merkle-tree-stream": "^3.0.3", + "pretty-hash": "^1.0.1", + "random-access-file": "^2.1.0", + "sodium-universal": "^2.0.0", + "sparse-bitfield": "^3.0.0", + "thunky": "^1.0.1", + "uint64be": "^2.0.1", + "unordered-array-remove": "^1.0.2", + "unordered-set": "^2.0.0" + }, + "dependencies": { + "thunky": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", + "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==" + }, + "unordered-set": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", + "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==" + } + } + }, + "hypercore-byte-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/hypercore-byte-stream/-/hypercore-byte-stream-1.0.5.tgz", + "integrity": "sha512-zqIA+uR3ftTEYBPgKXyBnq3YR7K6opC251O1Mcg8I12KmBcamcSyQ+j7LdbPDuLMd6h6nHM9TGrvzGp5GP5LZg==", + "requires": { + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "hypercore-crypto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hypercore-crypto/-/hypercore-crypto-1.0.0.tgz", + "integrity": "sha512-xFwOnNlOt8L+SovC7dTNchKaNYJb5l8rKZZwpWQnCme1r7CU4Hlhp1RDqPES6b0OpS7DkTo9iU0GltQGkpsjMw==", + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-from": "^1.1.0", + "sodium-universal": "^2.0.0", + "uint64be": "^2.0.2" + } + }, + "hypercore-protocol": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/hypercore-protocol/-/hypercore-protocol-6.12.0.tgz", + "integrity": "sha512-T3oy9/7QFejqJX2RGcCUU1944e5/eKbLlSz9JPTNN1QbYFJgat/r7eTyOO8SMSLUimUmQx6YBMKhgYbdKzp7Bw==", + "requires": { + "buffer-alloc-unsafe": "^1.0.0", + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "protocol-buffers-encodings": "^1.1.0", + "readable-stream": "^2.2.6", + "sodium-universal": "^2.0.0", + "sorted-indexof": "^1.0.0", + "varint": "^5.0.0" + } + }, + "hyperdrive": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/hyperdrive/-/hyperdrive-10.0.2.tgz", + "integrity": "sha512-YwCIQxiwqytMhZJ/lI+yCIRjvrf9pjC0zhw7HxgcSFHapbsXSRMlqn6grdd84nJlXRwOSbgieSk3YfmxI2o70w==", + "requires": { + "byte-stream": "^2.1.0", + "corestore": "^2.0.0", + "custom-error-class": "^1.0.0", + "duplexify": "^3.7.1", + "filesystem-constants": "^1.0.0", + "hypercore-byte-stream": "^1.0.2", + "hyperdrive-schemas": "^0.9.0", + "mountable-hypertrie": "^0.10.0", + "mutexify": "^1.2.0", + "nanoiterator": "^1.2.0", + "pump": "^3.0.0", + "pumpify": "^1.5.1", + "sodium-universal": "^2.0.0", + "stream-collector": "^1.0.1", + "through2": "^3.0.0", + "thunky": "^1.0.3", + "unixify": "^1.0.0" + }, + "dependencies": { + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "requires": { + "readable-stream": "2 || 3" + } + }, + "thunky": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", + "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==" + } + } + }, + "hyperdrive-daemon": { + "version": "0.9.16", + "resolved": "https://registry.npmjs.org/hyperdrive-daemon/-/hyperdrive-daemon-0.9.16.tgz", + "integrity": "sha512-sXk/z9xwkWVQQUMcVzag2+h7evlKOWcACaY1sE9kstUeh8Ci5iemYetVJGw4Xbp9I1+KwP4faqO2PWgNP2ixSg==", + "requires": { + "@grpc/grpc-js": "^0.5.1", + "buffer-json-encoding": "^1.0.2", + "chalk": "^2.4.2", + "collect-stream": "^1.2.1", + "corestore": "^2.0.0", + "corestore-swarm-networking": "^1.0.0", + "dat-encoding": "^5.0.1", + "forever": "^0.15.3", + "forever-monitor": "^1.7.1", + "fs-extra": "^7.0.1", + "google-protobuf": "^3.8.0", + "hyperdrive": "^10.0.0-rc10", + "hyperdrive-daemon-client": "^0.10.1", + "hyperdrive-fuse": "^1.1.0", + "level": "^4.0.0", + "mkdirp": "^0.5.1", + "pino": "^5.12.6", + "prettier-bytes": "^1.0.4", + "pump": "^3.0.0", + "random-access-file": "^2.1.2", + "sodium-universal": "^2.0.0", + "stream-collector": "^1.0.1", + "subleveldown": "^4.0.0", + "through2-map": "^3.0.0", + "yargs": "^13.2.1" + } + }, + "hyperdrive-daemon-client": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/hyperdrive-daemon-client/-/hyperdrive-daemon-client-0.10.2.tgz", + "integrity": "sha512-u4DGsTmjKaGwRzvxgiDJsyA2EWEentyYOM0U/GjtOCt/sEbnKk8GGWuAKxigp09Av+WPa/BWJsCJJpZH8gMimg==", + "requires": { + "@grpc/grpc-js": "^0.5.1", + "@mafintosh/streamx": "^1.1.0", + "call-me-maybe": "^1.0.1", + "chalk": "^2.4.2", + "dat-encoding": "^5.0.1", + "fs-extra": "^8.0.1", + "google-protobuf": "^3.8.0", + "hyperdrive-schemas": "^0.9.0", + "pumpify": "^2.0.0", + "stream-collector": "^1.0.1", + "through2-map": "^3.0.0", + "thunky": "^1.0.3", + "yargs": "^13.2.4" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "pumpify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.0.tgz", + "integrity": "sha512-ieN9HmpFPt4J4U4qnjN4BxrnqpPPXJyp3qFErxfwBtFOec6ewpIHdS2eu3TkmGW6S+RzFGEOGpm5ih/X/onRPQ==", + "requires": { + "duplexify": "^4.1.1", + "inherits": "^2.0.3", + "pump": "^3.0.0" + } + }, + "thunky": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", + "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==" + } + } + }, + "hyperdrive-fuse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/hyperdrive-fuse/-/hyperdrive-fuse-1.1.2.tgz", + "integrity": "sha512-LF38svTj0tkfrEbi2IpJHa6O33Pti8awGbqujlRZhX73CIQC40g1svwHlxkGNb3ByD7sf1GHUVNOAp9qyWHx/w==", + "optional": true, + "requires": { + "dat-encoding": "^5.0.1", + "filesystem-constants": "^1.0.0", + "fuse-native": "^1.1.0" + } + }, + "hyperdrive-network-speed": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hyperdrive-network-speed/-/hyperdrive-network-speed-2.1.0.tgz", + "integrity": "sha512-JolPS374h6oS1rmz1iebFfeDDvA2nAtiHbx9VJJGMgSDSx4Q77eeY09hDgZwY7KatSKUGWnnSyydSgVUb3+8Lw==", + "requires": { + "debug": "^3.1.0", + "speedometer": "^1.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "hyperdrive-schemas": { + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/hyperdrive-schemas/-/hyperdrive-schemas-0.9.8.tgz", + "integrity": "sha512-HJzonI8rtuLSMZL4fJhErwdopJNvu4ZLj0Pzn64n2e3Ifo5HwQBRUJYzwSXvx8+NNb/8VXUgh+2i6S6VtbVLuw==" + }, + "hyperswarm": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/hyperswarm/-/hyperswarm-2.0.6.tgz", + "integrity": "sha512-TJ0ZKNRbzFUiX4qZ+2dbmcUeUlZ+Ie+8h+1rOnklI9FQidoAELT/p5YhgPTzSFwkVh4b1lgcofJku3e6/FlJNA==", + "requires": { + "@hyperswarm/discovery": "^1.1.0", + "@hyperswarm/network": "1.0.0", + "shuffled-priority-queue": "^2.1.0", + "utp-native": "^2.1.3" + } + }, + "hypertrie": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/hypertrie/-/hypertrie-3.7.1.tgz", + "integrity": "sha512-2UlKAWuBJCN9f1KQomcviTY1cbPFIhgpRouHYL9s1YICIlUcttnpUYTbIHvjJJWftASJjiLnH/raLafHHDmM7Q==", + "requires": { + "bulk-write-stream": "^1.1.4", + "codecs": "^2.0.0", + "hypercore": "^7.0.0", + "inherits": "^2.0.3", + "inspect-custom-symbol": "^1.1.0", + "is-options": "^1.0.1", + "mutexify": "^1.2.0", + "nanoiterator": "^1.2.0", + "protocol-buffers-encodings": "^1.1.0", + "sodium-universal": "^2.0.0", + "thunky": "^1.0.2", + "unordered-set": "^2.0.1", + "varint": "^5.0.0" + }, + "dependencies": { + "thunky": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", + "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==" + }, + "unordered-set": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", + "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==" + } + } + }, + "i": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz", + "integrity": "sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=" + }, + "icojs": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/icojs/-/icojs-0.12.3.tgz", + "integrity": "sha512-7c/U6GVyBW6iw7SqmO0XLh2+q+KuaDZ2SoJcG+GrBqjAtvr9e0mtiUOxkpRx7ym6XcZQDvjgc0usjskyROJ+gg==", + "requires": { + "bmp-js": "0.1.0", + "decode-ico": "^0.3.1", + "file-type": "^10.7.0", + "jpeg-js": "^0.3.3", + "pngjs": "^3.3.3", + "to-data-view": "^1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "identify-filetype": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/identify-filetype/-/identify-filetype-1.0.0.tgz", + "integrity": "sha1-zm4pqnYvAxuChSojkqOBY/rXkOs=" + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "ignore-walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "requires": { + "minimatch": "^3.0.4" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "inspect-custom-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/inspect-custom-symbol/-/inspect-custom-symbol-1.1.0.tgz", + "integrity": "sha512-vtI2YXBRZBkU6DlfHfd0GtZENfiEiTacAXUd0ZY6HA+X7aPznpFfPmzSC+tHKXAkz9KDSdI4AYfwAMXR5t+isg==" + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" + }, + "into-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "requires": { + "from2": "^2.1.1", + "p-is-promise": "^1.1.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==" + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "ipv4-peers": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ipv4-peers/-/ipv4-peers-2.0.0.tgz", + "integrity": "sha512-6ZMWB3JnCWT0gISUkzChcUEkJS6+LpGRU3h10f9Mfc0usVmyIcbcTN9+QPMg29gLOY8WtaKFbM5ME8qNySoh8g==" + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-options/-/is-options-1.0.1.tgz", + "integrity": "sha512-2Xj8sA0zDrAcaoWfBiNmc6VPWAgKDpim0T3J9Djq7vbm1UjwbUWzeuLu/FwC46g3cBbAn0E5R0xwVtOobM6Xxg==" + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jpeg-js": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.3.6.tgz", + "integrity": "sha512-MUj2XlMB8kpe+8DJUGH/3UJm4XpI8XEgZQ+CiHDeyrGoKPdW/8FJv6ku+3UiYm5Fz3CWaL+iXmD8Q4Ap6aC1Jw==" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "k-bucket": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/k-bucket/-/k-bucket-3.3.1.tgz", + "integrity": "sha512-kgwWqYT79rAahn4maIVTP8dIe+m1KulufWW+f1bB9DlZrRFiGpZ4iJOg2HUp4xJYBWONP3+rOPIWF/RXABU6mw==", + "requires": { + "buffer-equals": "^1.0.3", + "inherits": "^2.0.1", + "randombytes": "^2.0.3" + } + }, + "k-rpc": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/k-rpc/-/k-rpc-4.3.1.tgz", + "integrity": "sha512-mgAJZeFYbpP0xzJzmS0TQTYoFI0sjy3GnKFhg8wyboL+KvWg2WLaA2Oy9PthLPx2Rxz4WeBMk4y3MSOrDJ95FA==", + "requires": { + "buffer-equals": "^1.0.3", + "k-bucket": "^4.0.0", + "k-rpc-socket": "^1.7.2", + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "k-bucket": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/k-bucket/-/k-bucket-4.0.1.tgz", + "integrity": "sha512-YvDpmY3waI999h1zZoW1rJ04fZrgZ+5PAlVmvwDHT6YO/Q1AOhdel07xsKy9eAvJjQ9xZV1wz3rXKqEfaWvlcQ==", + "requires": { + "inherits": "^2.0.1", + "randombytes": "^2.0.3" + } + } + } + }, + "k-rpc-socket": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/k-rpc-socket/-/k-rpc-socket-1.10.0.tgz", + "integrity": "sha512-OLg7zaXeP2Zok/FZ9EfJX0bVFhUxQsgjKVMEGYfSl+hYP1M5+6pPsEiprDAllHLgvIjzE8qcIez44dKLETGe7Q==", + "requires": { + "bencode": "^2.0.0", + "chrome-dgram": "^3.0.2", + "chrome-net": "^3.3.2" + }, + "dependencies": { + "bencode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bencode/-/bencode-2.0.1.tgz", + "integrity": "sha512-2uhEl8FdjSBUyb69qDTgOEeeqDTa+n3yMQzLW0cOzNf1Ow5bwcg3idf+qsWisIKRH8Bk8oC7UXL8irRcPA8ZEQ==", + "requires": { + "safe-buffer": "^5.1.1" + } + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + }, + "knex": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/knex/-/knex-0.17.6.tgz", + "integrity": "sha512-4SKp8jaBxqlEoaveenmpfnHEv5Kzo6/vhIj8UhW1srGw/FKqARTr+7Fv8C1C1qeVHDjv0coQWuUzN5eermHUsw==", + "requires": { + "@babel/polyfill": "^7.4.4", + "@types/bluebird": "^3.5.27", + "bluebird": "^3.5.5", + "colorette": "1.0.8", + "commander": "^2.20.0", + "debug": "4.1.1", + "getopts": "2.2.4", + "inherits": "~2.0.3", + "interpret": "^1.2.0", + "liftoff": "3.1.0", + "lodash": "^4.17.11", + "mkdirp": "^0.5.1", + "pg-connection-string": "2.0.0", + "tarn": "^1.1.5", + "tildify": "1.2.0", + "uuid": "^3.3.2", + "v8flags": "^3.1.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "kuler": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", + "requires": { + "colornames": "^1.1.1" + } + }, + "last-one-wins": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/last-one-wins/-/last-one-wins-1.0.4.tgz", + "integrity": "sha1-wb/Qy8tGeQ7JFWuNGu6Py4bNoio=" + }, + "lazy": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", + "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=" + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "requires": { + "invert-kv": "^2.0.0" + } + }, + "length-prefixed-message": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/length-prefixed-message/-/length-prefixed-message-3.0.4.tgz", + "integrity": "sha512-Tqyx4nggb9nkLD6p4hyIz7UiVNg5u3OnCP2h0hS/HXpheH88rsoNEgNB8xTnpPMw6zWXGZ7Cpg1zhWPlsJ0/TQ==", + "requires": { + "varint": "^3.0.1" + }, + "dependencies": { + "varint": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/varint/-/varint-3.0.1.tgz", + "integrity": "sha1-nT9T4DbAqxIACnS8LSTL8JOlgdk=" + } + } + }, + "level": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-4.0.0.tgz", + "integrity": "sha512-4epzCOlEcJ529NOdlAYiuiakS/kZTDdiKSBNJmE1B8bsmA+zEVwcpxyH86qJSQTpOu7SODrlaD9WgPRHLkGutA==", + "requires": { + "level-packager": "^3.0.0", + "leveldown": "^4.0.0", + "opencollective-postinstall": "^2.0.0" + } + }, + "level-codec": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-9.0.1.tgz", + "integrity": "sha512-ajFP0kJ+nyq4i6kptSM+mAvJKLOg1X5FiFPtLG9M5gCEZyBmgDi3FkDrvlMkEzrUn1cWxtvVmrvoS4ASyO/q+Q==" + }, + "level-concat-iterator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz", + "integrity": "sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw==" + }, + "level-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-2.0.1.tgz", + "integrity": "sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw==", + "requires": { + "errno": "~0.1.1" + } + }, + "level-iterator-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-3.0.1.tgz", + "integrity": "sha512-nEIQvxEED9yRThxvOrq8Aqziy4EGzrxSZK+QzEFAVuJvQ8glfyZ96GB6BoI4sBbLfjMXm2w4vu3Tkcm9obcY0g==", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "xtend": "^4.0.0" + } + }, + "level-option-wrap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/level-option-wrap/-/level-option-wrap-1.1.0.tgz", + "integrity": "sha1-rSDmjZ88IsiJdTHMaqevWWse0Sk=", + "requires": { + "defined": "~0.0.0" + } + }, + "level-packager": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-3.1.0.tgz", + "integrity": "sha512-UxVEfK5WH0u0InR3WxTCSAroiorAGKzXWZT6i+nBjambmvINuXFUsFx2Ai3UIjUUtnyWhluv42jMlzUZCsAk9A==", + "requires": { + "encoding-down": "~5.0.0", + "levelup": "^3.0.0" + } + }, + "leveldown": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-4.0.2.tgz", + "integrity": "sha512-SUgSRTWFh3eeiTdIt2a4Fi9TZO5oWzE9uC/Iw8+fVr1sk8x1S2l151UWwSmrMFZB3GxJhZIf4bQ0n+051Cctpw==", + "requires": { + "abstract-leveldown": "~5.0.0", + "bindings": "~1.3.0", + "fast-future": "~1.0.2", + "nan": "~2.12.1", + "prebuild-install": "~5.2.4" + }, + "dependencies": { + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + } + } + }, + "levelup": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-3.1.1.tgz", + "integrity": "sha512-9N10xRkUU4dShSRRFTBdNaBxofz+PGaIZO962ckboJZiNmLuhVT6FZ6ZKAsICKfUBO76ySaYU6fJWX/jnj3Lcg==", + "requires": { + "deferred-leveldown": "~4.0.0", + "level-errors": "~2.0.0", + "level-iterator-stream": "~3.0.0", + "xtend": "~4.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "requires": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + } + }, + "limiter": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.4.tgz", + "integrity": "sha512-XCpr5bElgDI65vVgstP8TWjv6/QKWm9GU5UG0Pr5sLQ3QLo8NVKsioe+Jed5/3vFOe3IQuqE7DKwTvKQkjTHvg==" + }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "requires": { + "uc.micro": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" + }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + }, + "lodash.uniqwith": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", + "integrity": "sha1-egy/ZfQ7WShiWp1NDcVLGMrcfvM=" + }, + "logform": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", + "integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==", + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^2.3.3", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "colors": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", + "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==" + } + } + }, + "lru": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lru/-/lru-3.1.0.tgz", + "integrity": "sha1-6n+4VG2DczOWoTCR12z+tMBoN9U=", + "requires": { + "inherits": "^2.0.1" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + }, + "dependencies": { + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "markdown-it": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "requires": { + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==" + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + }, + "dependencies": { + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" + } + } + }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + }, + "merkle-tree-stream": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/merkle-tree-stream/-/merkle-tree-stream-3.0.3.tgz", + "integrity": "sha1-+KBkdg0355eK1fn208EZpJT1cIE=", + "requires": { + "flat-tree": "^1.3.0", + "readable-stream": "^2.0.5" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "requires": { + "mime-db": "1.40.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "minipass": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "requires": { + "minipass": "^2.2.1" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "mountable-hypertrie": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/mountable-hypertrie/-/mountable-hypertrie-0.10.4.tgz", + "integrity": "sha512-AXkSWSJPeZ7ar0xnrXe3mqX96dBZJxczKOK2nXUIj6JabowwcC/fbOVMaQTQ1MK6PWXKVMTwcgBdjQtDn4CJow==", + "requires": { + "hypertrie": "^3.6.0", + "is-options": "^1.0.1", + "nanoiterator": "^1.2.0", + "protocol-buffers": "^4.1.0", + "protocol-buffers-encodings": "^1.1.0", + "unixify": "^1.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.0.tgz", + "integrity": "sha512-Tu2QORGOFANB124NWQ/JTRhMf/ODouVLEuvu5Dz8YWEU55zQgRgFGnBHfIh5PbfNDAuaRl7yLB+pgWhSqVxi2Q==", + "requires": { + "dns-packet": "^4.0.0", + "thunky": "^1.0.2" + }, + "dependencies": { + "thunky": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", + "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==" + } + } + }, + "multistream": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/multistream/-/multistream-2.1.1.tgz", + "integrity": "sha512-xasv76hl6nr1dEy3lPvy7Ej7K/Lx3O/FCvwge8PeVJpciPPoNCbaANcNiBug3IpdvTveZUcAV0DJzdnUDMesNQ==", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.5" + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "mutexify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mutexify/-/mutexify-1.2.0.tgz", + "integrity": "sha512-oprzxd2zhfrJqEuB98qc1dRMMonClBQ57UPDjnbcrah4orEMTq1jq3+AcdFe5ePzdbJXI7zmdhfftIdMnhYFoQ==" + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, + "nanoassert": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-1.1.0.tgz", + "integrity": "sha1-TzFS4JVA/eKMdvRLGbvNHVpCR40=" + }, + "nanoiterator": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/nanoiterator/-/nanoiterator-1.2.0.tgz", + "integrity": "sha512-Ybp8yZQDvjgqjrER+jlvZ2m/qzhK7gakNTKFDs84OLPrzsHcSbsFczJlNkDmyBlYldxFEO3JT3gwBWCN9nj8aQ==", + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.3" + } + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "nanoresource": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/nanoresource/-/nanoresource-1.2.0.tgz", + "integrity": "sha512-6DJTce5okL9IQlVcswSsrLP4lQER52GkRMHAnkmHQNX1AqpT6VOE8y0MBartHJW3SV0ppC0wy0u4eAK3JARfpA==" + }, + "napi-build-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz", + "integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==" + }, + "napi-macros": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-1.8.2.tgz", + "integrity": "sha512-Tr0DNY4RzTaBG2W2m3l7ZtFuJChTH6VZhXVhkGGjF/4cZTt+i8GcM9ozD+30Lmr4mDoZ5Xx34t2o4GJqYWDGcg==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nconf": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/nconf/-/nconf-0.6.9.tgz", + "integrity": "sha1-lXDvFe1vmuays8jV5xtm0xk81mE=", + "requires": { + "async": "0.2.9", + "ini": "1.x.x", + "optimist": "0.6.0" + }, + "dependencies": { + "async": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.9.tgz", + "integrity": "sha1-32MGD789Myhqdqr21Vophtn/hhk=" + }, + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + }, + "optimist": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.0.tgz", + "integrity": "sha1-aUJIJvNAX3nxQub8PZrljU27kgA=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + } + } + }, + "ncp": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", + "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=" + }, + "needle": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", + "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "network-address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/network-address/-/network-address-1.1.2.tgz", + "integrity": "sha1-Sqe/1D8D8LgclwKxPWqFjdsybz4=" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "node-abi": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.10.0.tgz", + "integrity": "sha512-OT0WepUvYHXdki6DU8LWhEkuo3M44i2paWBYtH9qXtPb9YiKlYEKa5WUII20XEcOv7UJPzfB0kZfPZdW46zdkw==", + "requires": { + "semver": "^5.4.1" + } + }, + "node-gyp-build": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", + "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==" + }, + "node-pre-gyp": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", + "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" + }, + "npm-bundled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==" + }, + "npm-packlist": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.4.tgz", + "integrity": "sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==", + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "^2.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nssocket": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/nssocket/-/nssocket-0.5.3.tgz", + "integrity": "sha1-iDyi7GBfXtZKTVGQsmJUAZKPj40=", + "requires": { + "eventemitter2": "~0.4.14", + "lazy": "~1.0.11" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "dependencies": { + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "requires": { + "for-in": "^1.0.1" + } + } + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "dependencies": { + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "requires": { + "for-in": "^1.0.1" + } + } + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "one-time": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", + "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + } + } + }, + "opencollective-postinstall": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", + "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==" + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "os-shim": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-is-promise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=" + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "parse-dat-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/parse-dat-url/-/parse-dat-url-3.0.3.tgz", + "integrity": "sha512-7a/rNzaZqhOHlZ1rwxz4xmERI47PpnAkuqbnkne9IH91D/pQ2T0+g5jK9kVUCp+jKHYRA0j4kbsyaluiF9XoaA==" + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" + }, + "pauls-dat-api": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/pauls-dat-api/-/pauls-dat-api-8.1.0.tgz", + "integrity": "sha512-DTxj5BIPjKJ5dDgQJxMsUfTVUVVi6RSgR3AWz4dl6pwAmQoh4YMYz+cfwfoQRIituMUdczRJkbs/JXD9yaa8dQ==", + "requires": { + "anymatch": "^1.3.2", + "beaker-error-constants": "^1.4.0", + "call-me-maybe": "^1.0.1", + "dat-encoding": "^4.0.2", + "diff-file-tree": "^2.1.1", + "emit-stream": "^0.1.2", + "fs-extra": "^4.0.3", + "pump": "^1.0.3" + }, + "dependencies": { + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "dat-encoding": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/dat-encoding/-/dat-encoding-4.0.2.tgz", + "integrity": "sha1-sBBo/g0IDz0+SYWgxK0ht8FGdfY=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "requires": { + "is-extglob": "^1.0.0" + } + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "pump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "pg-connection-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.0.0.tgz", + "integrity": "sha1-Pu/lmX4G2Ugh5NUC5CtqHHP434I=" + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + }, + "pino": { + "version": "5.13.2", + "resolved": "https://registry.npmjs.org/pino/-/pino-5.13.2.tgz", + "integrity": "sha512-WwOSCy36/gWhinsqWqAnuwIi2WtcH+jvoyeLm3bjUALIrzWIst0AovQjK4jVvSN2l64KFPfi3gd2fjsTovjdLQ==", + "requires": { + "fast-redact": "^1.4.4", + "fast-safe-stringify": "^2.0.6", + "flatstr": "^1.0.9", + "pino-std-serializers": "^2.3.0", + "quick-format-unescaped": "^3.0.2", + "sonic-boom": "^0.7.5" + } + }, + "pino-std-serializers": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.4.2.tgz", + "integrity": "sha512-WaL504dO8eGs+vrK+j4BuQQq6GLKeCCcHaMB2ItygzVURcL1CycwNEUHTD/lHFHs/NL5qAz2UKrjYWXKSf4aMQ==" + }, + "pkginfo": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", + "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=" + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "pre-commit": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", + "integrity": "sha1-287g7p3nI15X95xW186UZBpp7sY=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "spawn-sync": "^1.0.15", + "which": "1.2.x" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "prebuild-install": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.2.5.tgz", + "integrity": "sha512-6uZgMVg7yDfqlP5CPurVhtq3hUKBFNufiar4J5hZrlHTo59DDBEtyxw01xCdFss9j0Zb9+qzFVf/s4niayba3w==", + "requires": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "os-homedir": "^1.0.1", + "pump": "^2.0.1", + "rc": "^1.2.7", + "simple-get": "^2.7.0", + "tar-fs": "^1.13.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" + }, + "prettier-bytes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prettier-bytes/-/prettier-bytes-1.0.4.tgz", + "integrity": "sha1-mUsCqkb2mcULYle1+qp/4lV+YtY=" + }, + "pretty-hash": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pretty-hash/-/pretty-hash-1.0.1.tgz", + "integrity": "sha1-FuBXkYje9WvbVliSvNBaXWUySAc=" + }, + "prettyjson": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.1.tgz", + "integrity": "sha1-/P+rQdGcq0365eV15kJGYZsS0ok=", + "requires": { + "colors": "^1.1.2", + "minimist": "^1.2.0" + }, + "dependencies": { + "colors": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", + "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==" + } + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "prompt": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/prompt/-/prompt-0.2.14.tgz", + "integrity": "sha1-V3VPZPVD/XsIRXB8gY7OYY8F/9w=", + "requires": { + "pkginfo": "0.x.x", + "read": "1.0.x", + "revalidator": "0.1.x", + "utile": "0.2.x", + "winston": "0.8.x" + }, + "dependencies": { + "winston": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-0.8.3.tgz", + "integrity": "sha1-ZLar9M0Brcrv1QCTk7HY6L7BnbA=", + "requires": { + "async": "0.2.x", + "colors": "0.6.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "pkginfo": "0.3.x", + "stack-trace": "0.0.x" + } + } + } + }, + "protocol-buffers": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/protocol-buffers/-/protocol-buffers-4.1.0.tgz", + "integrity": "sha512-9erS5oyfb5vzLCO1pJfSujA03md3MzaR6zP77lcHobH3tb6Z3S/mMDzCxpRrGnmsPb/6o5RLZ5wpVEM2UMlgvw==", + "requires": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.2.0", + "protocol-buffers-encodings": "^1.1.0", + "protocol-buffers-schema": "^3.1.1", + "signed-varint": "^2.0.0", + "varint": "^5.0.0" + } + }, + "protocol-buffers-encodings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/protocol-buffers-encodings/-/protocol-buffers-encodings-1.1.0.tgz", + "integrity": "sha512-SmjEuAf3hc3h3rWZ6V1YaaQw2MNJWK848gLJgzx/sefOJdNLujKinJVXIS0q2cBQpQn2Q32TinawZyDZPzm4kQ==", + "requires": { + "signed-varint": "^2.0.1", + "varint": "^5.0.0" + } + }, + "protocol-buffers-schema": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.3.2.tgz", + "integrity": "sha512-Xdayp8sB/mU+sUV4G7ws8xtYMGdQnxbeIfLjyO9TZZRJdztBGhlmbI5x1qcY4TG5hBkIKGnc28i7nXxaugu88w==" + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "ps-tree": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-0.0.3.tgz", + "integrity": "sha1-2/jXUqf+Ivp9WGNWiUmWEOknbdw=", + "requires": { + "event-stream": "~0.5" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.3.0.tgz", + "integrity": "sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "quick-format-unescaped": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-3.0.2.tgz", + "integrity": "sha512-FXTaCkwvpIlkdKeGDNgcq07SXWS383noQUuZjvdE1QcTt+eLuqof6/BDiEPqB59FWLie/l91+HtlJSw7iCViSA==" + }, + "random-access-file": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/random-access-file/-/random-access-file-2.1.3.tgz", + "integrity": "sha512-AE0Z1ywR5gIkzACMC1lCsR6LP8g4ynNm7oYWYdKPSSU6Y3H+mGDJxBqfcV9B9KstfHNemhfX3nYmx99ZC9f/yg==", + "requires": { + "mkdirp": "^0.5.1", + "random-access-storage": "^1.1.1" + } + }, + "random-access-indexed-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/random-access-indexed-file/-/random-access-indexed-file-2.0.0.tgz", + "integrity": "sha512-IDPRktIPbitqJ0WFQqxyjuE4OhvZ7VyWdJYGCcfi1HKVUByPa4JgS+v8r93xoLbKkMPJDKhiMfyYhGoAPNEzPA==", + "requires": { + "await-lock": "^1.1.3", + "mkdirp": "^0.5.1", + "random-access-storage": "^1.3.0", + "uint48be": "^2.0.1" + } + }, + "random-access-storage": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/random-access-storage/-/random-access-storage-1.4.0.tgz", + "integrity": "sha512-7oszloM/+PdqWp/oFGyL6SeI14liqo8AAisHAZQGkWdHISyAnngKjNPL0JYIazeLxbHPY6oed2yUffowdq/o6A==", + "requires": { + "inherits": "^2.0.3" + } + }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + } + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + } + } + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "requires": { + "mute-stream": "~0.0.4" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "requires": { + "resolve": "^1.1.6" + } + }, + "record-cache": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/record-cache/-/record-cache-1.1.0.tgz", + "integrity": "sha512-u8rbtLEJV7HRacl/ZYwSBFD8NFyB3PfTTfGLP37IW3hftQCwu6z4Q2RLyxo1YJUNRTEzJfpLpGwVuEYdaIkG9Q==" + }, + "recursive-watch": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/recursive-watch/-/recursive-watch-1.1.4.tgz", + "integrity": "sha512-fWejAmdLi7B/jipBUjTLnqId+PK+573fbGNbdaNA/AiAnQAx6OYOLCGWRs0W5+PyM1rLzZSWK2f40QpHSR49PQ==", + "requires": { + "ttl": "^1.3.0" + } + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + } + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "resumer": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", + "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", + "requires": { + "through": "~2.3.4" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "revalidator": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", + "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=" + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-series": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.8.tgz", + "integrity": "sha512-+GztYEPRpIsQoCSraWHDBs9WVy4eVME16zhOtDB4H9J4xN0XRhknnmLOl+4gRgZtu8dpp9N/utSPjKH/xmDzXg==" + }, + "rusha": { + "version": "0.8.13", + "resolved": "https://registry.npmjs.org/rusha/-/rusha-0.8.13.tgz", + "integrity": "sha1-mghOe4YLF7/zAVuSxnpqM2GRUTo=" + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "requires": { + "rx-lite": "*" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "scoped-fs": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scoped-fs/-/scoped-fs-1.3.0.tgz", + "integrity": "sha512-aH9/73pyOAuO1x5YDf7kFogD7MMLsrADRtCcKHC7fD+o7IKwzpVxgbWB6YZyCIWxfTI/+TLCw/rHMcj3B4jXdQ==", + "requires": { + "recursive-watch": "^1.1.1" + } + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "shuffled-priority-queue": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/shuffled-priority-queue/-/shuffled-priority-queue-2.1.0.tgz", + "integrity": "sha512-xhdh7fHyMsr0m/w2kDfRJuBFRS96b9l8ZPNWGaQ+PMvnUnZ/Eh+gJJ9NsHBd7P9k0399WYlCLzsy18EaMfyadA==", + "requires": { + "unordered-set": "^2.0.1" + }, + "dependencies": { + "unordered-set": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", + "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==" + } + } + }, + "shush": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shush/-/shush-1.0.0.tgz", + "integrity": "sha1-wnQVqeRY8v7TmyfPjrN8ADeCtDE=", + "requires": { + "caller": "~0.0.1", + "strip-json-comments": "~0.1.1" + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "signed-varint": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/signed-varint/-/signed-varint-2.0.1.tgz", + "integrity": "sha1-UKmYnafJjCxh2tEZvJdHDvhSgSk=", + "requires": { + "varint": "~5.0.0" + } + }, + "simple-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", + "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" + }, + "simple-get": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", + "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", + "requires": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "simple-sha1": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/simple-sha1/-/simple-sha1-2.1.2.tgz", + "integrity": "sha512-TQl9rm4rdKAVmhO++sXAb8TNN0D6JAD5iyI1mqEPNpxUzTRrtm4aOG1pDf/5W/qCFihiaoK6uuL9rvQz1x1VKw==", + "requires": { + "rusha": "^0.8.1" + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + } + }, + "siphash24": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/siphash24/-/siphash24-1.1.1.tgz", + "integrity": "sha512-dKKwjIoTOa587TARYLlBRXq2lkbu5Iz35XrEVWpelhBP1m8r2BGOy1QlaZe84GTFHG/BTucEUd2btnNc8QzIVA==", + "requires": { + "nanoassert": "^1.0.0" + } + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + } + }, + "slugify": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.4.tgz", + "integrity": "sha512-KP0ZYk5hJNBS8/eIjGkFDCzGQIoZ1mnfQRYS5WM3273z+fxGWXeN0fkwf2ebEweydv9tioZIHGZKoF21U07/nw==" + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "sodium-javascript": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/sodium-javascript/-/sodium-javascript-0.5.5.tgz", + "integrity": "sha512-UMmCHovws/sxIBZsIRhIl8uRPou/RFDD0vVop81T1hG106NLLgqajKKuHAOtAP6hflnZ0UrVA2VFwddTd/NQyA==", + "requires": { + "blake2b": "^2.1.1", + "nanoassert": "^1.0.0", + "siphash24": "^1.0.1", + "xsalsa20": "^1.0.0" + } + }, + "sodium-native": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-2.4.5.tgz", + "integrity": "sha512-G1uhd4l1OexzUC/6eHIbAvoivCs9T7ncDlEWodZglPZVUOXi6jtSe7tCi25aYB06zRoOjVfE4SL+hZ4EfkyZgw==", + "optional": true, + "requires": { + "ini": "^1.3.5", + "nan": "^2.14.0", + "node-gyp-build": "^4.1.0" + }, + "dependencies": { + "node-gyp-build": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.0.tgz", + "integrity": "sha512-rGLv++nK20BG8gc0MzzcYe1Nl3p3mtwJ74Q2QD0HTEDKZ6NvOFSelY6s2QBPWIHRR8h7hpad0LiwajfClBJfNg==", + "optional": true + } + } + }, + "sodium-signatures": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/sodium-signatures/-/sodium-signatures-2.1.1.tgz", + "integrity": "sha512-Alr0buBPROZJJdUSgg/7t027pV7YWxVg9CNy2f/SEsoh3cYgyd9iUiiNJ/W+Qf5ir6yk51cruqQVYpLYju0dbw==", + "requires": { + "buffer-alloc-unsafe": "^1.0.0", + "sodium-universal": "^2.0.0" + } + }, + "sodium-universal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sodium-universal/-/sodium-universal-2.0.0.tgz", + "integrity": "sha512-csdVyakzHJRyCevY4aZC2Eacda8paf+4nmRGF2N7KxCLKY2Ajn72JsExaQlJQ2BiXJncp44p3T+b80cU+2TTsg==", + "requires": { + "sodium-javascript": "~0.5.0", + "sodium-native": "^2.0.0" + } + }, + "sonic-boom": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-0.7.5.tgz", + "integrity": "sha512-1pKrnAV6RfvntPnarY71tpthFTM3pWZWWQdghZY8ARjtDPGzG/inxqSuRwQY/7V1woUjfyxPb437zn4p5phgnQ==", + "requires": { + "flatstr": "^1.0.12" + } + }, + "sorted-indexof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sorted-indexof/-/sorted-indexof-1.0.0.tgz", + "integrity": "sha1-F8dC/3zxh+L1mhXfm4HxemLOCJk=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "requires": { + "memory-pager": "^1.0.2" + } + }, + "spawn-sync": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", + "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "dev": true, + "requires": { + "concat-stream": "^1.4.7", + "os-shim": "^0.1.2" + } + }, + "speedometer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-1.1.0.tgz", + "integrity": "sha512-z/wAiTESw2XVPssY2XRcme4niTc4S5FkkJ4gknudtVoc33Zil8TdTxHy5torRcgqMqksJV2Yz8HQcvtbsnw0mQ==" + }, + "spellchecker": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/spellchecker/-/spellchecker-3.7.0.tgz", + "integrity": "sha512-saQT4BR9nivbK70s0YjyIlSbZzO6bfWRULcGL2JU7fi7wotOnWl70P0QoUwwLywNQJQ47osgCo6GmOlqzRTxbQ==", + "requires": { + "any-promise": "^1.3.0", + "nan": "^2.14.0" + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "split2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", + "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", + "requires": { + "through2": "^2.0.2" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sqlite3": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.0.9.tgz", + "integrity": "sha512-IkvzjmsWQl9BuBiM4xKpl5X8WCR4w0AeJHRdobCdXZ8dT/lNc1XS6WqvY35N6+YzIIgzSBeY5prdFObID9F9tA==", + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.11.0", + "request": "^2.87.0" + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stream-collector": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-collector/-/stream-collector-1.0.1.tgz", + "integrity": "sha1-TU5V8XE1YSGyxfZVn5RHBaso2xU=", + "requires": { + "once": "^1.3.1" + } + }, + "stream-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-equal/-/stream-equal-1.1.1.tgz", + "integrity": "sha512-SaZxkvxujYBR6NTumhRTg/yztw2p30fzZ/jvSgQtlZFEGI7tdSNDaPbvT47QF92hx6Tar8hAhpr7ErpTNvtuCQ==", + "requires": { + "@types/node": "*" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" + }, + "stream-throttle": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", + "integrity": "sha1-rdV8jXzHOoFjDTHNVdOWHPr7qcM=", + "requires": { + "commander": "^2.2.0", + "limiter": "^1.0.5" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + }, + "strip-json-comments": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz", + "integrity": "sha1-Fkxk43Coo8wAyeAbU55WmCPw7lQ=" + }, + "subleveldown": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/subleveldown/-/subleveldown-4.1.0.tgz", + "integrity": "sha512-1apU81Pu6FGB2eo+ewK3Vr+a+sR7WIK7YLNIamI9xdm3Mo9XPO/JHvJxx2M24OHZP7HJ8H9R+pdrzs4UQgIT6A==", + "requires": { + "abstract-leveldown": "^6.0.2", + "encoding-down": "^6.0.1", + "inherits": "^2.0.3", + "level-option-wrap": "^1.1.0", + "levelup": "^4.0.1" + }, + "dependencies": { + "abstract-leveldown": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.0.3.tgz", + "integrity": "sha512-jzewKKpZbaYUa6HTThnrl+GrJhzjEAeuc7hTVpZdzg7kupXZFoqQDFwyOwLNbmJKJlmzw8yiipMPkDiuKkT06Q==", + "requires": { + "level-concat-iterator": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "deferred-leveldown": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.1.0.tgz", + "integrity": "sha512-PvDY+BT2ONu2XVRgxHb77hYelLtMYxKSGuWuJJdVRXh9ntqx9GYTFJno/SKAz5xcd+yjQwyQeIZrUPjPvA52mg==", + "requires": { + "abstract-leveldown": "~6.0.0", + "inherits": "^2.0.3" + } + }, + "encoding-down": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-6.1.0.tgz", + "integrity": "sha512-pBW1mbuQDHQhQLBtqarX8x2oLynahiOzBY5L/BosNqcstJ8MjpSc3rx1yCUIqb6bUE2vsp3t0BaXS0ZDP1s5pg==", + "requires": { + "abstract-leveldown": "^6.0.0", + "inherits": "^2.0.3", + "level-codec": "^9.0.0", + "level-errors": "^2.0.0" + } + }, + "level-iterator-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-4.0.1.tgz", + "integrity": "sha512-pSZWqXK6/yHQkZKCHrR59nKpU5iqorKM22C/BOHTb/cwNQ2EOZG+bovmFFGcOgaBoF3KxqJEI27YwewhJQTzsw==", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^3.0.2", + "xtend": "^4.0.0" + } + }, + "levelup": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-4.1.0.tgz", + "integrity": "sha512-+Qhe2/jb5affN7BeFgWUUWVdYoGXO2nFS3QLEZKZynnQyP9xqA+7wgOz3fD8SST2UKpHQuZgjyJjTcB2nMl2dQ==", + "requires": { + "deferred-leveldown": "~5.1.0", + "level-errors": "~2.0.0", + "level-iterator-stream": "~4.0.0", + "xtend": "~4.0.0" + } + }, + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-sparse-files": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/supports-sparse-files/-/supports-sparse-files-1.0.2.tgz", + "integrity": "sha512-45nB+UT0Tv06fTGkYCHMR+WfAL/gIgbdHqICw2vIb0Gb68QEmi1LX1s+ODA5NJbk4RS4ug2VBHBVO1tFywJzUw==" + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "tape": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tape/-/tape-2.3.3.tgz", + "integrity": "sha1-Lnzgox3wn41oUWZKcYQuDKUFevc=", + "requires": { + "deep-equal": "~0.1.0", + "defined": "~0.0.0", + "inherits": "~2.0.1", + "jsonify": "~0.0.0", + "resumer": "~0.0.0", + "through": "~2.3.4" + }, + "dependencies": { + "deep-equal": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.1.2.tgz", + "integrity": "sha1-skbCuApXCkfBG+HZvRBw7IeLh84=" + } + } + }, + "tar": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz", + "integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==", + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.5", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "tar-fs": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", + "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", + "requires": { + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" + }, + "dependencies": { + "pump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "requires": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + } + }, + "tarn": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.5.tgz", + "integrity": "sha512-PMtJ3HCLAZeedWjJPgGnCvcphbCOMbtZpjKgLq3qM5Qq9aQud+XHrL0WlrlgnTyS8U+jrjGbEXprFcQrxPy52g==" + }, + "temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=" + }, + "tempy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.1.0.tgz", + "integrity": "sha1-hSdBPNBxAINPzJy7gkK+lboOH+4=", + "requires": { + "pify": "^2.3.0", + "temp-dir": "^1.0.0", + "unique-string": "^1.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "textextensions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.5.0.tgz", + "integrity": "sha512-1IkVr355eHcomgK7fgj1Xsokturx6L5S2JRT5WcRdA6v5shk9sxWuO/w/VbpQexwkXJMQIa/j1dBi3oo7+HhcA==" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "through2-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-map/-/through2-map-3.0.0.tgz", + "integrity": "sha1-psMCbOY7SJipl9VAUGtm/9lw8nE=", + "requires": { + "through2": "~2.0.0", + "xtend": "^4.0.0" + } + }, + "thunky": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz", + "integrity": "sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=" + }, + "tildify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", + "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", + "requires": { + "os-homedir": "^1.0.0" + } + }, + "time-ordered-set": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/time-ordered-set/-/time-ordered-set-1.0.2.tgz", + "integrity": "sha512-vGO99JkxvgX+u+LtOKQEpYf31Kj3i/GNwVstfnh4dyINakMgeZCpew1e3Aj+06hEslhtHEd52g7m5IV+o1K8Mw==" + }, + "timeout-refresh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-1.0.0.tgz", + "integrity": "sha512-y5ajDPPtyhumr7xRnQgOMMVR5/EXMCVHPwM7RWnMUZx9UzT8FGRBtwG4/rh2AWHkDr7JR8dBHU6NDGx7tEiEAg==" + }, + "timespan": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz", + "integrity": "sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk=" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + }, + "to-data-view": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-1.0.0.tgz", + "integrity": "sha512-pz/bdULSupr+shtVLFHRBXstHfeBByfT9oa1oVOMBR4FWJkuFuD/OFdXZkR8sWONbtfKO7m3Tin/tKM+k3Qt8Q==" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } + } + }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "ttl": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/ttl/-/ttl-1.3.1.tgz", + "integrity": "sha512-+bGy9iDAqg3WSfc2ZrprToSPJhZjqy7vUv9wupQzsiv+BVPVx1T2a6G4T0290SpQj+56Toaw9BiLO5j5Bd7QzA==" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, + "uint48be": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uint48be/-/uint48be-2.0.1.tgz", + "integrity": "sha512-LQvWofTo3RCz+XaQR3VNch+dDFwpIvWr/98imhQne++vFhpQP16YAC/a8w9N00Heqqra00ACjHT18cgvn5H+bg==" + }, + "uint64be": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uint64be/-/uint64be-2.0.2.tgz", + "integrity": "sha512-9QqdvpGQTXgxthP+lY4e/gIBy+RuqcBaC6JVwT5I3bDLgT/btL6twZMR0pI3/Fgah9G/pdwzIprE5gL6v9UvyQ==", + "requires": { + "buffer-alloc": "^1.1.0" + } + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "unixify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz", + "integrity": "sha1-OmQcjC/7zk2mg6XHDwOkYpQMIJA=", + "requires": { + "normalize-path": "^2.1.1" + } + }, + "unordered-array-remove": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz", + "integrity": "sha1-xUbo+I4xegzyZEyX7LV9umbSUO8=" + }, + "unordered-set": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-1.1.0.tgz", + "integrity": "sha1-K6fvMW7dC5WQzFR8dPdqLxZP7Mo=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utile": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/utile/-/utile-0.2.1.tgz", + "integrity": "sha1-kwyI6ZCY1iIINMNWy9mncFItkNc=", + "requires": { + "async": "~0.2.9", + "deep-equal": "*", + "i": "0.3.x", + "mkdirp": "0.x.x", + "ncp": "0.4.x", + "rimraf": "2.x.x" + } + }, + "utp-native": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/utp-native/-/utp-native-2.1.4.tgz", + "integrity": "sha512-FYjr3bHBnJpw8yD0CmFCh5USyDgr6VtuncEIun100GqCUdgqnkAx9irSY3tA4UrzRH56qmiocP2fs1QjQ7ZDZA==", + "requires": { + "napi-macros": "^1.8.1", + "node-gyp-build": "^3.5.0", + "readable-stream": "^3.0.2", + "timeout-refresh": "^1.0.0", + "unordered-set": "^2.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "unordered-set": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz", + "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==" + } + } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "v8flags": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", + "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "varint": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", + "integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "winston": { + "version": "github:winstonjs/winston#b4ced895b3e1ead8a616590189b003cfd9d7acca", + "from": "github:winstonjs/winston#b4ced895b3e1ead8a616590189b003cfd9d7acca", + "requires": { + "async": "^2.6.1", + "diagnostics": "^1.1.1", + "is-stream": "^1.1.0", + "logform": "^2.0.0", + "one-time": "0.0.4", + "readable-stream": "^3.1.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.3.0" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "requires": { + "lodash": "^4.17.14" + } + }, + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "winston-transport": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", + "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", + "requires": { + "readable-stream": "^2.3.6", + "triple-beam": "^1.2.0" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "xor-distance": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xor-distance/-/xor-distance-2.0.0.tgz", + "integrity": "sha512-AsAqZfPAuWx7qB/0kyRDUEvoU3QKsHWzHU9smFlkaiprEpGfJ/NBbLze2Uq0rdkxCxkNM9uOLvz/KoNBCbZiLQ==" + }, + "xsalsa20": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xsalsa20/-/xsalsa20-1.0.2.tgz", + "integrity": "sha512-g1DFmZ5JJ9Qzvt4dMw6m9IydqoCSP381ucU5zm46Owbk3bwmqAr8eEJirOPc7PrXRn45drzOpAyDp8jsnoyXyw==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "requires": { + "buffer-crc32": "~0.2.3" + } + } + } +} diff --git a/package.json b/package.json index ee13367a..1813cf7c 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,8 @@ "fs-jetpack": "^1.3.1", "fs-reverse": "0.0.3", "function-queue": "0.0.12", - "hyperdrive-daemon": "^0.9.13", - "hyperdrive-daemon-client": "^0.9.10", + "hyperdrive-daemon": "^0.9.16", + "hyperdrive-daemon-client": "^0.10.1", "hyperdrive-network-speed": "^2.1.0", "icojs": "^0.12.3", "identify-filetype": "^1.0.0", From e013d5bc65824c2394ed56b5725d6feec96d41b2 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 8 Aug 2019 16:19:41 -0500 Subject: [PATCH 10/74] Switch to pauls-dat-api2 --- dat/daemon.js | 7 ++++--- dat/daemon/folder-sync.js | 5 ++--- dat/daemon/index.js | 10 +++++----- dat/folder-sync.js | 5 ++--- dat/library.js | 2 +- lib/scoped-fses.js | 38 ++++++++++++++++++++++++++++++++++++++ package-lock.json | 13 ++++++------- package.json | 2 +- web-apis/bg/dat-archive.js | 2 +- 9 files changed, 60 insertions(+), 24 deletions(-) diff --git a/dat/daemon.js b/dat/daemon.js index c41e3eb7..9cc5bd01 100644 --- a/dat/daemon.js +++ b/dat/daemon.js @@ -3,7 +3,7 @@ const { createMetadata } = require('hyperdrive-daemon/lib/metadata') const constants = require('hyperdrive-daemon-client/lib/constants') const { HyperdriveClient } = require('hyperdrive-daemon-client') const datEncoding = require('dat-encoding') -const pda = require('pauls-dat-api') +const pda = require('pauls-dat-api2') // typedefs // = @@ -133,8 +133,9 @@ exports.createDatArchiveSession = async function (opts) { // access: makeArchiveProxyCbFn(key, version, 'access'), mount: (...args) => drive.mount(...args), unmount: (...args) => drive.unmount(...args), + + pda: createDatArchiveSessionPDA(drive) } - datArchive.pda = createDatArchiveSessionPDA(datArchive) return /** @type DaemonDatArchive */(datArchive) } @@ -160,7 +161,7 @@ function fixStatObject (st) { } /** - * Provides a pauls-dat-api object for the given archive + * Provides a pauls-dat-api2 object for the given archive * @param {Object} datArchive * @returns {DaemonDatArchivePDA} */ diff --git a/dat/daemon/folder-sync.js b/dat/daemon/folder-sync.js index b79e5eee..92f38a51 100644 --- a/dat/daemon/folder-sync.js +++ b/dat/daemon/folder-sync.js @@ -5,7 +5,6 @@ const anymatch = require('anymatch') const fs = require('fs') const path = require('path') const EventEmitter = require('events') -const pda = require('pauls-dat-api') const mkdirp = require('mkdirp') const {toAnymatchRules} = require('@beaker/datignore') const logger = require('./logger').child({category: 'dat', subcategory: 'folder-sync'}) @@ -329,13 +328,13 @@ exports.applyDatIgnoreFilter = function (archive, filepath) { const mergeArchiveAndFolder = exports.mergeArchiveAndFolder = async function (archive, localSyncPath) { logger.silly('Merging archive and folder', {details: {path: localSyncPath, key: archive.key.toString('hex')}}) const readManifest = async (fs) => { - try { return await pda.readManifest(fs) } catch (e) { return {} } + try { return await fs.pda.readManifest() } catch (e) { return {} } } var localFS = scopedFSes.get(localSyncPath) var localManifest = await readManifest(localFS) var archiveManifest = await readManifest(archive) var mergedManifest = Object.assign(archiveManifest || {}, localManifest || {}) - await pda.writeManifest(localFS, mergedManifest) + await localFS.pda.writeManifest(mergedManifest) await sync(archive, false, {localSyncPath, shallow: false, addOnly: true}) // archive -> folder (add-only) await sync(archive, true, {localSyncPath, shallow: false}) // folder -> archive events.emit('merge:' + archive.key.toString('hex'), archive.key) diff --git a/dat/daemon/index.js b/dat/daemon/index.js index c7ef8f9f..e471093a 100644 --- a/dat/daemon/index.js +++ b/dat/daemon/index.js @@ -14,7 +14,7 @@ const {join} = require('path') // dat modules const hyperdrive = require('hyperdrive') const hypercoreProtocol = require('hypercore-protocol') -const pda = require('pauls-dat-api') +const pda = require('pauls-dat-api2') const datEncoding = require('dat-encoding') // network modules @@ -258,7 +258,7 @@ const RPC_API = { } // watch for sync events - archive.fileActStream = pda.watch(archive) + archive.fileActStream = archive.pda.watch() archive.fileActStream.on('data', ([event, {path}]) => { if (event === 'changed') { if (!archive.localSyncSettings) return @@ -477,7 +477,7 @@ function getArchiveCheckout (key, version) { async function updateSizeTracking (archive) { archive = getArchive(archive) try { - archive.size = await pda.readSize(archive, '/') + archive.size = await archive.pda.readSize('/') } catch (e) { archive.size = 0 } @@ -504,11 +504,11 @@ function configureAutoDownload (archive, userSettings) { onUpdate: throttle(() => { // cancel ALL previous, then prioritize ALL current archive._autodownloader.undownloadAll() - pda.download(archive, '/').catch(e => { /* ignore cancels */ }) + archive.pda.download('/').catch(e => { /* ignore cancels */ }) }, 5e3) } archive.metadata.on('download', archive._autodownloader.onUpdate) - pda.download(archive, '/').catch(e => { /* ignore cancels */ }) + archive.pda.download('/').catch(e => { /* ignore cancels */ }) } else if (archive._autodownloader && !isAutoDownloading) { stopAutodownload(archive) } diff --git a/dat/folder-sync.js b/dat/folder-sync.js index 36795729..d7abda29 100644 --- a/dat/folder-sync.js +++ b/dat/folder-sync.js @@ -7,7 +7,6 @@ const jetpack = require('fs-jetpack') const path = require('path') const EventEmitter = require('events') const datEncoding = require('dat-encoding') -const pda = require('pauls-dat-api') const mkdirp = require('mkdirp') const isEqual = require('lodash.isequal') const {toAnymatchRules} = require('@beaker/datignore') @@ -423,13 +422,13 @@ exports.applyDatIgnoreFilter = function (archive, filepath) { const mergeArchiveAndFolder = exports.mergeArchiveAndFolder = async function (archive, localSyncPath) { logger.silly('Merging archive and folder', {details: {path: localSyncPath, key: archive.key.toString('hex')}}) const readManifest = async (fs) => { - try { return await pda.readManifest(fs) } catch (e) { return {} } + try { return await fs.pda.readManifest() } catch (e) { return {} } } var localFS = scopedFSes.get(localSyncPath) var localManifest = await readManifest(localFS) var archiveManifest = await readManifest(archive) var mergedManifest = Object.assign(archiveManifest || {}, localManifest || {}) - await pda.writeManifest(localFS, mergedManifest) + await localFS.pda.writeManifest(mergedManifest) await sync(archive, false, {localSyncPath, shallow: false, addOnly: true}) // archive -> folder (add-only) await sync(archive, true, {localSyncPath, shallow: false}) // folder -> archive events.emit('merge:' + archive.key.toString('hex'), archive.key) diff --git a/dat/library.js b/dat/library.js index 01660eae..7144c762 100644 --- a/dat/library.js +++ b/dat/library.js @@ -6,7 +6,7 @@ const signatures = require('sodium-signatures') const parseDatURL = require('parse-dat-url') const _debounce = require('lodash.debounce') const mkdirp = require('mkdirp') -const pda = require('pauls-dat-api') +const pda = require('pauls-dat-api2') const scopedFSes = require('../lib/scoped-fses') const baseLogger = require('../logger').get() const logger = baseLogger.child({category: 'dat', subcategory: 'library'}) diff --git a/lib/scoped-fses.js b/lib/scoped-fses.js index 873ddc2f..f7bad900 100644 --- a/lib/scoped-fses.js +++ b/lib/scoped-fses.js @@ -23,6 +23,25 @@ const ScopedFS = require('scoped-fs') * @prop {function(string, Function): void} unlink * @prop {function(string, Function): void} rmdir * @prop {function(string, Function): Object} watch + * @prop {ScopedFSPDA} pda + * + * @typedef {Object} ScopedFSPDA + * @prop {function(string): Promise} stat + * @prop {function(string, Object=): Promise} readFile + * @prop {function(string, Object=): Promise>} readdir + * @prop {function(string): Promise} readSize + * @prop {function(string, any, Object=): Promise} writeFile + * @prop {function(string): Promise} mkdir + * @prop {function(string, string): Promise} copy + * @prop {function(string, string): Promise} rename + * @prop {function(string): Promise} unlink + * @prop {function(string, Object=): Promise} rmdir + * @prop {function(string=): Promise} download + * @prop {function(string=): NodeJS.ReadableStream} watch + * @prop {function(): NodeJS.ReadableStream} createNetworkActivityStream + * @prop {function(): Promise} readManifest + * @prop {function(Object): Promise} writeManifest + * @prop {function(Object): Promise} updateManifest */ // globals @@ -40,7 +59,26 @@ var scopedFSes = {} // map of scoped filesystems, kept in memory to reduce alloc exports.get = function (path) { if (!(path in scopedFSes)) { scopedFSes[path] = new ScopedFS(path) + scopedFSes[path].pda = createScopedFSPDA(scopedFSes[path]) scopedFSes[path].isLocalFS = true } return scopedFSes[path] } + +// internal methods +// = + +/** + * Provides a pauls-dat-api2 object for the given scoped fs + * @param {Object} scopedFS + * @returns {ScopedFSPDA} + */ +function createScopedFSPDA (scopedFS) { + var obj = {} + for (let k in pda) { + if (typeof pda[k] === 'function') { + obj[k] = pda[k].bind(pda, scopedFS) + } + } + return obj +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 16c83895..ee652b1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,9 +55,9 @@ } }, "@hyperswarm/dht": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@hyperswarm/dht/-/dht-1.0.0.tgz", - "integrity": "sha512-tfg2K44ddpQZ7M25Lys3gDtXIK+5EcUA5sAGOCLtANGNjXc1T8qYLlviJIWdo0ucKnrEJK8Ag+7L3U9hbNTyFg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@hyperswarm/dht/-/dht-1.0.1.tgz", + "integrity": "sha512-bmJyX4dWy28ZiuL3+zMJug226gVvBmXcCUKXe55g1JtoXwPgXch+ENIrB03/sBrXfYffAGFUlWKNHflVe9FNzw==", "requires": { "dht-rpc": "^4.1.6", "end-of-stream": "^1.4.1", @@ -5133,10 +5133,9 @@ "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" }, - "pauls-dat-api": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/pauls-dat-api/-/pauls-dat-api-8.1.0.tgz", - "integrity": "sha512-DTxj5BIPjKJ5dDgQJxMsUfTVUVVi6RSgR3AWz4dl6pwAmQoh4YMYz+cfwfoQRIituMUdczRJkbs/JXD9yaa8dQ==", + "pauls-dat-api2": { + "version": "github:beakerbrowser/pauls-dat-api2#d3fdabd8917543e5f9142388059ec4a51cd4891c", + "from": "github:beakerbrowser/pauls-dat-api2", "requires": { "anymatch": "^1.3.2", "beaker-error-constants": "^1.4.0", diff --git a/package.json b/package.json index 1813cf7c..24029172 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "once": "^1.4.0", "os-locale": "^3.1.0", "parse-dat-url": "^3.0.3", - "pauls-dat-api": "^8.1.0", + "pauls-dat-api2": "github:beakerbrowser/pauls-dat-api2", "pify": "^3.0.0", "pump": "^3.0.0", "random-access-file": "^2.1.3", diff --git a/web-apis/bg/dat-archive.js b/web-apis/bg/dat-archive.js index f16b863d..64c7fc69 100644 --- a/web-apis/bg/dat-archive.js +++ b/web-apis/bg/dat-archive.js @@ -2,7 +2,7 @@ const globals = require('../../globals') const path = require('path') const fs = require('fs') const parseDatURL = require('parse-dat-url') -const pda = require('pauls-dat-api') +const pda = require('pauls-dat-api2') const concat = require('concat-stream') const pick = require('lodash.pick') const datDns = require('../../dat/dns') From 73241792746b30094eb7039904fd7bd502cf7ade Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 8 Aug 2019 16:19:50 -0500 Subject: [PATCH 11/74] Remove unused directory-listing-page --- dat/directory-listing-page.js | 83 ----------------------------------- dat/protocol.js | 1 - 2 files changed, 84 deletions(-) delete mode 100644 dat/directory-listing-page.js diff --git a/dat/directory-listing-page.js b/dat/directory-listing-page.js deleted file mode 100644 index 51bc4c43..00000000 --- a/dat/directory-listing-page.js +++ /dev/null @@ -1,83 +0,0 @@ -const {pluralize, makeSafe} = require('../lib/strings') -const {stat, readdir} = require('pauls-dat-api') -const {join, relative} = require('path') - -/** @typedef {import('./daemon').DaemonDatArchive} DaemonDatArchive */ - -const styles = `` - -/** - * @prop {DaemonDatArchive} archive - * @prop {string} dirPath - * @prop {string} webRoot - * @returns {Promise} - */ -module.exports = async function renderDirectoryListingPage (archive, dirPath, webRoot) { - // handle the webroot - webRoot = webRoot || '/' - const realPath = p => join(webRoot, p) - const webrootPath = p => relative(webRoot, p) - - // list files - var names = [] - try { names = await readdir(archive, realPath(dirPath)) } catch (e) {} - - // stat each file - var entries = /** @type any[] */(await Promise.all(names.map(async (name) => { - var entry - var entryPath = join(dirPath, name) - try { entry = await stat(archive, realPath(entryPath)) } catch (e) { return false } - entry.path = webrootPath(entryPath) - entry.name = name - return entry - }))) - entries = entries.filter(Boolean) - - // sort the listing - entries.sort((a, b) => { - // directories on top - if (a.isDirectory() && !b.isDirectory()) return -1 - if (!a.isDirectory() && b.isDirectory()) return 1 - // alphabetical after that - return a.name.localeCompare(b.name) - }) - - // show the updog if path is not top - var updog = '' - if (['/', '', '..'].includes(webrootPath(dirPath)) === false) { - updog = `
..
` - } - - // render entries - var totalFiles = 0 - var entriesStr = entries.map(entry => { - totalFiles++ - var url = makeSafe(entry.path) - if (!url.startsWith('/')) url = '/' + url // all urls should have a leading slash - if (entry.isDirectory() && !url.endsWith('/')) url += '/' // all dirs should have a trailing slash - var type = entry.isDirectory() ? 'directory' : 'file' - return `
${makeSafe(entry.name)}
` - }).join('') - - // render summary - var summary = `
${totalFiles} ${pluralize(totalFiles, 'file')}
` - - // render final - return '' + styles + updog + entriesStr + summary -} diff --git a/dat/protocol.js b/dat/protocol.js index 9d372761..9b050475 100644 --- a/dat/protocol.js +++ b/dat/protocol.js @@ -12,7 +12,6 @@ const datDns = require('./dns') const datLibrary = require('./library') const datServeResolvePath = require('@beaker/dat-serve-resolve-path') -const directoryListingPage = require('./directory-listing-page') const errorPage = require('../lib/error-page') const mime = require('../lib/mime') const {makeSafe} = require('../lib/strings') From 86b8c710cf6fc8899adc132547ba9a2da391eff0 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 8 Aug 2019 20:22:14 -0500 Subject: [PATCH 12/74] Implement DatArchive mount/unmount --- dat/daemon.js | 52 +--------------------- package-lock.json | 2 +- web-apis/bg/dat-archive.js | 35 +++++++++++++++ web-apis/fg/dat-archive.js | 18 ++++++++ web-apis/manifests/external/dat-archive.js | 3 ++ 5 files changed, 58 insertions(+), 52 deletions(-) diff --git a/dat/daemon.js b/dat/daemon.js index 9cc5bd01..cf3b39f0 100644 --- a/dat/daemon.js +++ b/dat/daemon.js @@ -20,11 +20,8 @@ const pda = require('pauls-dat-api2') * @prop {function(): Promise} session.publish * @prop {function(): Promise} session.unpublish * @prop {function(): Promise} getInfo -* @prop {function(string, Object=, Function=): any} readFile -* @prop {function(string, any, Object=, Function=): void} writeFile -* @prop {function(string, Object=, Function=): void} readdir * @prop {DaemonDatArchivePDA} pda - +* * @typedef {Object} DaemonDatArchivePDA * @prop {function(string): Promise} stat * @prop {function(string, Object=): Promise} readFile @@ -104,35 +101,6 @@ exports.createDatArchiveSession = async function (opts) { networkStats: {} } }, - stat: (...args) => { - // wrap the callback with a method which fixes the stat object output - var cb = args.pop() - args.push((err, st) => { - if (st) fixStatObject(st) - cb(err, st) - }) - drive.stat(...args) - }, - lstat (path, opts = {}) { - opts.lstat = true - return this.stat(path, opts) - }, - // readFile: (...args) => client.drive.readFile(sessionId, ...args), TODO opts not accepted by daemon yet - readFile: (path, opts, cb) => drive.readFile(path, cb ? cb : opts), - // writeFile: (...args) => client.drive.writeFile(sessionId, ...args), TODO encoding/opts not accepted by daemon yet - writeFile: (path, content, opts, cb) => drive.writeFile(path, content, cb ? cb : opts), - // download: makeArchiveProxyCbFn(key, version, 'download'), - // history: makeArchiveProxyReadStreamFn(key, version, 'history'), - createReadStream: (...args) => drive.createReadStream(...args), - // createDiffStream: makeArchiveProxyReadStreamFn(key, version, 'createDiffStream'), - createWriteStream: (...args) => drive.createWriteStream(...args), - unlink: (...args) => drive.unlink(...args), - readdir: (...args) => drive.readdir(...args), - mkdir: (...args) => drive.mkdir(...args), - rmdir: (...args) => drive.rmdir(...args), - // access: makeArchiveProxyCbFn(key, version, 'access'), - mount: (...args) => drive.mount(...args), - unmount: (...args) => drive.unmount(...args), pda: createDatArchiveSessionPDA(drive) } @@ -142,24 +110,6 @@ exports.createDatArchiveSession = async function (opts) { // internal methods // = -/** - * Converts the stat object to the expected form - * @param {Object} st - * @returns {void} - */ -function fixStatObject (st) { - st.atime = (new Date(st.atime)).getTime() - st.mtime = (new Date(st.mtime)).getTime() - st.ctime = (new Date(st.ctime)).getTime() - st.isSocket = () => false - st.isSymbolicLink = () => false - st.isFile = () => (st.mode & 32768) === 32768 - st.isBlockDevice = () => false - st.isDirectory = () => (st.mode & 16384) === 16384 - st.isCharacterDevice = () => false - st.isFIFO = () => false -} - /** * Provides a pauls-dat-api2 object for the given archive * @param {Object} datArchive diff --git a/package-lock.json b/package-lock.json index ee652b1e..9bdaa922 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5134,7 +5134,7 @@ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" }, "pauls-dat-api2": { - "version": "github:beakerbrowser/pauls-dat-api2#d3fdabd8917543e5f9142388059ec4a51cd4891c", + "version": "github:beakerbrowser/pauls-dat-api2#73fceee2e34dca40d0ad7c6be4de713178fd16ae", "from": "github:beakerbrowser/pauls-dat-api2", "requires": { "anymatch": "^1.3.2", diff --git a/web-apis/bg/dat-archive.js b/web-apis/bg/dat-archive.js index 64c7fc69..812d1b82 100644 --- a/web-apis/bg/dat-archive.js +++ b/web-apis/bg/dat-archive.js @@ -431,6 +431,41 @@ module.exports = { }) }, + async mount (url, filepath, opts) { + filepath = normalizeFilepath(filepath || '') + return timer(to(opts), async (checkin, pause, resume) => { + checkin('searching for archive') + const {archive, checkoutFS, isHistoric} = await lookupArchive(this.sender, url) + if (isHistoric) throw new ArchiveNotWritableError('Cannot modify a historic version') + + pause() // dont count against timeout, there may be user prompts + await assertWritePermission(archive, this.sender) + await assertValidPath(filepath) + assertUnprotectedFilePath(filepath, this.sender) + resume() + + checkin('mounting archive') + return checkoutFS.pda.mount(filepath, opts) + }) + }, + + async unmount (url, filepath, opts = {}) { + filepath = normalizeFilepath(filepath || '') + return timer(to(opts), async (checkin, pause, resume) => { + checkin('searching for archive') + const {archive, checkoutFS, isHistoric} = await lookupArchive(this.sender, url, opts) + if (isHistoric) throw new ArchiveNotWritableError('Cannot modify a historic version') + + pause() // dont count against timeout, there may be user prompts + await assertWritePermission(archive, this.sender) + assertUnprotectedFilePath(filepath, this.sender) + resume() + + checkin('unmounting archive') + return checkoutFS.pda.unmount(filepath) + }) + }, + async watch (url, pathPattern) { var {archive, checkoutFS, version} = await lookupArchive(this.sender, url) if (version === 'preview') { diff --git a/web-apis/fg/dat-archive.js b/web-apis/fg/dat-archive.js index 6a553bd7..c9dd11f0 100644 --- a/web-apis/fg/dat-archive.js +++ b/web-apis/fg/dat-archive.js @@ -232,6 +232,24 @@ exports.setup = function (rpc) { } } + async mount (path, opts = {}) { + var errStack = (new Error()).stack + try { + return await datRPC.mount(this.url, path, opts) + } catch (e) { + throwWithFixedStack(e, errStack) + } + } + + async unmount (path, opts = {}) { + var errStack = (new Error()).stack + try { + return await datRPC.unmount(this.url, path, opts) + } catch (e) { + throwWithFixedStack(e, errStack) + } + } + createFileActivityStream (pathSpec = null) { console.warn('The DatArchive createFileActivityStream() API has been deprecated, use watch() instead.') return this.watch(pathSpec) diff --git a/web-apis/manifests/external/dat-archive.js b/web-apis/manifests/external/dat-archive.js index e20e3926..dbe58da7 100644 --- a/web-apis/manifests/external/dat-archive.js +++ b/web-apis/manifests/external/dat-archive.js @@ -20,6 +20,9 @@ module.exports = { mkdir: 'promise', rmdir: 'promise', + mount: 'promise', + unmount: 'promise', + watch: 'readable', createNetworkActivityStream: 'readable', From e33fe9b264da8cf72d38438060cf40c75131ff59 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 9 Aug 2019 14:38:52 -0500 Subject: [PATCH 13/74] Implement DatArchive symlink --- package-lock.json | 2 +- web-apis/bg/dat-archive.js | 19 +++++++++++++++++++ web-apis/fg/dat-archive.js | 9 +++++++++ web-apis/manifests/external/dat-archive.js | 2 ++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 9bdaa922..09fc19d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5134,7 +5134,7 @@ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" }, "pauls-dat-api2": { - "version": "github:beakerbrowser/pauls-dat-api2#73fceee2e34dca40d0ad7c6be4de713178fd16ae", + "version": "github:beakerbrowser/pauls-dat-api2#cba9eac145a96e7927dec97160c3e3e14d55240d", "from": "github:beakerbrowser/pauls-dat-api2", "requires": { "anymatch": "^1.3.2", diff --git a/web-apis/bg/dat-archive.js b/web-apis/bg/dat-archive.js index 812d1b82..9ea8dd79 100644 --- a/web-apis/bg/dat-archive.js +++ b/web-apis/bg/dat-archive.js @@ -431,6 +431,25 @@ module.exports = { }) }, + async symlink (url, target, linkname, opts) { + target = normalizeFilepath(target || '') + linkname = normalizeFilepath(linkname || '') + return timer(to(opts), async (checkin, pause, resume) => { + checkin('searching for archive') + const {archive, checkoutFS, isHistoric} = await lookupArchive(this.sender, url) + if (isHistoric) throw new ArchiveNotWritableError('Cannot modify a historic version') + + pause() // dont count against timeout, there may be user prompts + await assertWritePermission(archive, this.sender) + await assertValidPath(linkname) + assertUnprotectedFilePath(linkname, this.sender) + resume() + + checkin('symlinking') + return checkoutFS.pda.symlink(target, linkname) + }) + }, + async mount (url, filepath, opts) { filepath = normalizeFilepath(filepath || '') return timer(to(opts), async (checkin, pause, resume) => { diff --git a/web-apis/fg/dat-archive.js b/web-apis/fg/dat-archive.js index c9dd11f0..226b7574 100644 --- a/web-apis/fg/dat-archive.js +++ b/web-apis/fg/dat-archive.js @@ -232,6 +232,15 @@ exports.setup = function (rpc) { } } + async symlink (target, linkname, opts = {}) { + var errStack = (new Error()).stack + try { + return await datRPC.symlink(this.url, target, linkname, opts) + } catch (e) { + throwWithFixedStack(e, errStack) + } + } + async mount (path, opts = {}) { var errStack = (new Error()).stack try { diff --git a/web-apis/manifests/external/dat-archive.js b/web-apis/manifests/external/dat-archive.js index dbe58da7..a89dfb3d 100644 --- a/web-apis/manifests/external/dat-archive.js +++ b/web-apis/manifests/external/dat-archive.js @@ -20,6 +20,8 @@ module.exports = { mkdir: 'promise', rmdir: 'promise', + symlink: 'promise', + mount: 'promise', unmount: 'promise', From 58402b4bc42872b4d7d07595c93364c4d896cf92 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 9 Aug 2019 20:05:06 -0500 Subject: [PATCH 14/74] Remove old dat 1.0 daemon --- dat/daemon/extensions.js | 189 ---------- dat/daemon/folder-sync.js | 462 ------------------------ dat/daemon/index.js | 691 ------------------------------------ dat/daemon/logger.js | 32 -- dat/daemon/logging-utils.js | 232 ------------ dat/daemon/manifest.js | 153 -------- dat/daemon/storage.js | 53 --- 7 files changed, 1812 deletions(-) delete mode 100644 dat/daemon/extensions.js delete mode 100644 dat/daemon/folder-sync.js delete mode 100644 dat/daemon/index.js delete mode 100644 dat/daemon/logger.js delete mode 100644 dat/daemon/logging-utils.js delete mode 100644 dat/daemon/manifest.js delete mode 100644 dat/daemon/storage.js diff --git a/dat/daemon/extensions.js b/dat/daemon/extensions.js deleted file mode 100644 index 32e77ef2..00000000 --- a/dat/daemon/extensions.js +++ /dev/null @@ -1,189 +0,0 @@ -const EventEmitter = require('events') -const emitStream = require('emit-stream') -const {DatSessionDataExtMsg} = require('@beaker/dat-session-data-ext-msg') -const {DatEphemeralExtMsg} = require('@beaker/dat-ephemeral-ext-msg') - -// globals -// = - -var datSessionDataExtMsg = new DatSessionDataExtMsg() -var datEphemeralExtMsg = new DatEphemeralExtMsg() - -// exported api -// = - -function setup () { - datEphemeralExtMsg.on('message', onEphemeralMsg) - datSessionDataExtMsg.on('session-data', onSessionDataMsg) -} -exports.setup = setup - -// call this on every archive created in the library -function attach (archive) { - datEphemeralExtMsg.watchDat(archive) - datSessionDataExtMsg.watchDat(archive) - archive._datPeersEvents = new EventEmitter() - archive._datPeersOnPeerAdd = (peer) => onPeerAdd(archive, peer) - archive._datPeersOnPeerRemove = (peer) => onPeerRemove(archive, peer) - archive.metadata.on('peer-add', archive._datPeersOnPeerAdd) - archive.metadata.on('peer-remove', archive._datPeersOnPeerRemove) -} -exports.attach = attach - -// call this on every archive destroyed in the library -function detach (archive) { - datEphemeralExtMsg.unwatchDat(archive) - datSessionDataExtMsg.unwatchDat(archive) - delete archive._datPeersEvents - archive.metadata.removeListener('peer-add', archive._datPeersOnPeerAdd) - archive.metadata.removeListener('peer-remove', archive._datPeersOnPeerRemove) -} -exports.detach = detach - -// impl for datPeers.list() -function listPeers (archive) { - return archive.metadata.peers.map(internalPeerObj => createWebAPIPeerObj(archive, internalPeerObj)) -} -exports.listPeers = listPeers - -// impl for datPeers.getPeer(peerId) -function getPeer (archive, peerId) { - var internalPeerObj = archive.metadata.peers.find(internalPeerObj => getPeerId(internalPeerObj) === peerId) - return createWebAPIPeerObj(archive, internalPeerObj) -} -exports.getPeer = getPeer - -// impl for datPeers.broadcast(msg) -function broadcastEphemeralMessage (archive, payload) { - datEphemeralExtMsg.broadcast(archive, encodeEphemeralMsg(payload)) -} -exports.broadcastEphemeralMessage =broadcastEphemeralMessage - -// impl for datPeers.send(peerId, msg) -function sendEphemeralMessage (archive, peerId, payload) { - datEphemeralExtMsg.send(archive, peerId, encodeEphemeralMsg(payload)) -} -exports.sendEphemeralMessage = sendEphemeralMessage - -// impl for datPeers.getSessionData() -function getSessionData (archive) { - return decodeSessionData(datSessionDataExtMsg.getLocalSessionData(archive)) -} -exports.getSessionData = getSessionData - -// impl for datPeers.getSessionData(data) -function setSessionData (archive, sessionData) { - datSessionDataExtMsg.setLocalSessionData(archive, encodeSessionData(sessionData)) -} -exports.setSessionData = setSessionData - -function createDatPeersStream (archive) { - return emitStream(archive._datPeersEvents) -} -exports.createDatPeersStream = createDatPeersStream - -// events -// = - -function onPeerAdd (archive, internalPeerObj) { - if (getPeerId(internalPeerObj)) onHandshook() - else internalPeerObj.stream.stream.on('handshake', onHandshook) - - function onHandshook () { - var peerId = getPeerId(internalPeerObj) - - // send session data - if (datSessionDataExtMsg.getLocalSessionData(archive)) { - datSessionDataExtMsg.sendLocalSessionData(archive, peerId) - } - - // emit event - archive._datPeersEvents.emit('connect', { - peerId, - sessionData: getPeerSessionData(archive, peerId) - }) - } -} - -function onPeerRemove (archive, internalPeerObj) { - var peerId = getPeerId(internalPeerObj) - if (peerId) { - archive._datPeersEvents.emit('disconnect', { - peerId, - sessionData: getPeerSessionData(archive, peerId) - }) - } -} - -function onEphemeralMsg (archive, internalPeerObj, msg) { - var peerId = getPeerId(internalPeerObj) - archive._datPeersEvents.emit('message', { - peerId, - sessionData: getPeerSessionData(archive, peerId), - message: decodeEphemeralMsg(msg) - }) -} - -function onSessionDataMsg (archive, internalPeerObj, sessionData) { - archive._datPeersEvents.emit('session-data', { - peerId: getPeerId(internalPeerObj), - sessionData: decodeSessionData(sessionData) - }) -} - -// internal methods -// = - -function getPeerId (internalPeerObj) { - var feedStream = internalPeerObj.stream - var protocolStream = feedStream.stream - return protocolStream.remoteId ? protocolStream.remoteId.toString('hex') : null -} - -function getPeerSessionData (archive, peerId) { - return decodeSessionData(datSessionDataExtMsg.getSessionData(archive, peerId)) -} - -function createWebAPIPeerObj (archive, internalPeerObj) { - var id = getPeerId(internalPeerObj) - var sessionData = getPeerSessionData(archive, id) - return {id, sessionData} -} - -function encodeEphemeralMsg (payload) { - var contentType - if (Buffer.isBuffer(payload)) { - contentType = 'application/octet-stream' - } else { - contentType = 'application/json' - payload = Buffer.from(JSON.stringify(payload), 'utf8') - } - return {contentType, payload} -} - -function decodeEphemeralMsg (msg) { - var payload - if (msg.contentType === 'application/json') { - try { - payload = JSON.parse(msg.payload.toString('utf8')) - } catch (e) { - console.error('Failed to parse ephemeral message', e, msg) - payload = null - } - } - return payload -} - -function encodeSessionData (obj) { - return Buffer.from(JSON.stringify(obj), 'utf8') -} - -function decodeSessionData (sessionData) { - if (!sessionData || sessionData.length === 0) return null - try { - return JSON.parse(sessionData.toString('utf8')) - } catch (e) { - console.error('Failed to parse local session data', e, sessionData) - return null - } -} \ No newline at end of file diff --git a/dat/daemon/folder-sync.js b/dat/daemon/folder-sync.js deleted file mode 100644 index 92f38a51..00000000 --- a/dat/daemon/folder-sync.js +++ /dev/null @@ -1,462 +0,0 @@ -const bytes = require('bytes') -const dft = require('diff-file-tree') -const diff = require('diff') -const anymatch = require('anymatch') -const fs = require('fs') -const path = require('path') -const EventEmitter = require('events') -const mkdirp = require('mkdirp') -const {toAnymatchRules} = require('@beaker/datignore') -const logger = require('./logger').child({category: 'dat', subcategory: 'folder-sync'}) -const {isFileNameBinary, isFileContentBinary} = require('../../lib/mime') -const lock = require('../../lib/lock') -const scopedFSes = require('../../lib/scoped-fses') -const { - NotFoundError, - NotAFolderError, - ProtectedFileNotWritableError, - ArchiveNotWritableError, - InvalidEncodingError, - SourceTooLargeError -} = require('beaker-error-constants') - -const MAX_DIFF_SIZE = bytes('100kb') - -// globals -// = - -var disallowedSavePaths = [] - -// exported api -// = - -const events = exports.events = new EventEmitter() - -exports.setup = function (opts) { - disallowedSavePaths = opts.disallowedSavePaths -} - -// sync dat to the folder -// - opts -// - shallow: bool, dont descend into changed folders (default true) -// - compareContent: bool, compare the actual content (default true) -// - paths: Array, a whitelist of files to compare -// - localSyncPath: string, override the archive localSyncPath -// - addOnly: bool, dont modify or remove any files (default false) -const syncArchiveToFolder = exports.syncArchiveToFolder = function (archive, opts = {}) { - opts = opts || {} - return sync(archive, false, opts) -} - -// sync folder to the dat -// - opts -// - shallow: bool, dont descend into changed folders (default true) -// - compareContent: bool, compare the actual content (default true) -// - paths: Array, a whitelist of files to compare -// - localSyncPath: string, override the archive localSyncPath -// - addOnly: bool, dont modify or remove any files (default false) -const syncFolderToArchive = exports.syncFolderToArchive = function (archive, opts = {}) { - opts = opts || {} - if (!archive.writable) throw new ArchiveNotWritableError() - return sync(archive, true, opts) -} - -// helper to wait for sync on an archive to be finished -const ensureSyncFinished = exports.ensureSyncFinished = async function (archive) { - var isFinished - var release = await getArchiveSyncLock(archive) - try { isFinished = (archive._activeSyncs == 0) } - finally { release() } - if (!isFinished) { - return ensureSyncFinished(archive) // check again - } -} - -// queue a sync event from folder->archive or archive->folder -// - debounces the sync event with a 500ms timeout -// - call with toFolder: true to sync from archive->folder -// - call with toArchive: true to sync from folder->archive -// - if both toFolder && toArchive are queued, toArchive wins (local folder wins) -// - this *will* result in lost changes in the archive if simultaneous changes happen in the local folder, -// but it creates very deterministic results -const queueSyncEvent = exports.queueSyncEvent = function (archive, {toFolder, toArchive}) { - if (!archive.syncEventQueue) { - archive.syncEventQueue = newQueueObj() - } - - // ignore if currently syncing - if (archive.syncEventQueue.isSyncing) return logger.silly('Already syncing, ignored') - - // debounce the handler - if (archive.syncEventQueue.timeout) { - clearTimeout(archive.syncEventQueue.timeout) - } - - // queue - if (toFolder) archive.syncEventQueue.toFolder = true - if (toArchive) archive.syncEventQueue.toArchive = true - archive.syncEventQueue.timeout = setTimeout(async () => { - const localSyncPath = archive.localSyncSettings.path - const {toArchive, toFolder} = archive.syncEventQueue - - // lock - archive.syncEventQueue.isSyncing = true - logger.silly('Ok timed out, beginning sync', {details: {toArchive, toFolder}}) - - try { - let st = await stat(fs, localSyncPath) - if (!st) { - // folder has been removed - archive.stopWatchingLocalFolder() - archive.stopWatchingLocalFolder = null - logger.warn('Local sync folder not found, aborting watch', {details: {path: localSyncPath}}) - return - } - // sync with priority given to the local folder - if (toArchive) await syncFolderToArchive(archive, {localSyncPath, shallow: false}) - else if (toFolder) await syncArchiveToFolder(archive, {localSyncPath, shallow: false}) - } catch (e) { - logger.error('Error syncing folder', {details: {path: localSyncPath, error: e.toString()}}) - if (e.name === 'CycleError') { - events.emit('error', archive.key, e) - } - } finally { - // reset the queue - archive.syncEventQueue = newQueueObj() - } - }, 500) -} -function newQueueObj () { - return {timeout: null, toFolder: false, toArchive: false, isSyncing: false} -} - -// attach/detach a watcher on the local folder and sync it to the dat -exports.configureFolderToArchiveWatcher = async function (archive) { - // HACKish - // it's possible that configureFolderToArchiveWatcher() could be called multiple times in sequence - // (for instance because of multiple settings changes) - // this is problematic because the method is async, and a previous call may still be in progress - // shouldAbort() tracks whether such an event has occurred and lets you drop out - // put this after every await: - // - // if (shouldAbort()) return - // - // -prf - var callCount = archive.folderSyncConfig_CallCount = (archive.folderSyncConfig_CallCount || 0) + 1 - const shouldAbort = () => callCount !== archive.folderSyncConfig_CallCount - - // teardown the existing watch (his watch has ended) - // = - - if (archive.stopWatchingLocalFolder) { - // stop watching - archive.stopWatchingLocalFolder() - archive.stopWatchingLocalFolder = null - if (archive.syncEventQueue && archive.syncEventQueue.timeout) { - clearTimeout(archive.syncEventQueue.timeout) - archive.syncEventQueue = null - } - } - if (archive.stopWatchingDatIgnore) { - archive.stopWatchingDatIgnore() - archive.stopWatchingDatIgnore = null - } - - // start a new watch - // = - - if (archive.localSyncSettings) { - logger.silly('Configuring archive sync', {details: {key: archive.key.toString('hex'), settings: archive.localSyncSettings}}) - - // create diff cache - archive._compareContentCache = {} - - // create internal folder if needed - if (archive.localSyncSettings.isUsingInternal) { - mkdirp.sync(archive.localSyncSettings.path) - } - - // make sure the folder exists - let st = await stat(fs, archive.localSyncSettings.path) - if (shouldAbort()) return - if (!st) { - logger.warn('Local sync folder not found, aborting watch', {details: {path: archive.localSyncSettings.path}}) - } - var scopedFS = scopedFSes.get(archive.localSyncSettings.path) - - // track datignore rules - readDatIgnore(scopedFS).then(rules => { archive.datIgnoreRules = rules }) - archive.stopWatchingDatIgnore = scopedFS.watch('/.datignore', async () => { - archive.datIgnoreRules = await readDatIgnore(scopedFS) - }) - - if (!archive.localSyncSettings.autoPublish) { - // no need to setup watcher - // just do an add-only sync from archive->folder - await sync(archive, false, {shallow: false, addOnly: true}) - if (shouldAbort()) return - } else { - // sync up - try { - await mergeArchiveAndFolder(archive, archive.localSyncSettings.path) - } catch (err) { - logger.error('Failed to merge local sync folder', {details: {err}}) - } - if (shouldAbort()) return - - // start watching - archive.stopWatchingLocalFolder = scopedFS.watch('/', path => { - // TODO - // it would be possible to make this more efficient by ignoring changes that match .datignore - // but you need to make sure you have the latest .datignore and reading that on every change-event isnt efficient - // so you either need to: - // A. queue up all the changed paths, then read the datignore inside the timeout and filter, if filteredList.length === 0 then abort - // B. maintain an in-memory copy of the datignore and keep it up-to-date, and then check at time of the event - // -prf - - logger.silly('Change detected', {details: {path}}) - queueSyncEvent(archive, {toArchive: true}) - }) - } - } else { - // clear diff cache - archive._compareContentCache = {} - } -} - -// list the files that differ -// - opts -// - shallow: bool, dont descend into changed folders (default true) -// - compareContent: bool, compare the actual content (default true) -// - paths: Array, a whitelist of files to compare -// - localSyncPath: string, override the archive localSyncPath -exports.diffListing = async function (archive, opts = {}) { - opts = opts || {} - var localSyncPath = opts.localSyncPath || (archive.localSyncSettings && archive.localSyncSettings.path) - if (!localSyncPath) return logger.warn('Sanity check failed - diffListing() aborting, no localSyncPath') - var scopedFS = scopedFSes.get(localSyncPath) - opts = massageDiffOpts(opts) - - // build ignore rules - if (opts.paths) { - opts.filter = makeDiffFilterByPaths(opts.paths) - } else { - const ignoreRules = await readDatIgnore(scopedFS) - opts.filter = (filepath) => anymatch(ignoreRules, filepath) - } - - // run diff - opts.compareContentCache = archive._compareContentCache - return dft.diff({fs: scopedFS}, {fs: archive}, opts) -} - -// diff an individual file -// - filepath: string, the path of the file in the archive/folder -exports.diffFile = async function (archive, filepath) { - if (!archive.localSyncSettings.path) return logger.warn('Sanity check failed - diffFile() aborting, no localSyncPath') - var scopedFS = scopedFSes.get(archive.localSyncSettings.path) - filepath = path.normalize(filepath) - - // check the filename to see if it's binary - var isBinary = isFileNameBinary(filepath) - if (isBinary === true) { - throw new InvalidEncodingError('Cannot diff a binary file') - } - - // make sure we can handle the buffers involved - let st - st = await stat(scopedFS, filepath) - if (isBinary !== false && st && st.isFile() && await isFileContentBinary(scopedFS, filepath)) { - throw new InvalidEncodingError('Cannot diff a binary file') - } - if (st && st.isFile() && st.size > MAX_DIFF_SIZE) { - throw new SourceTooLargeError() - } - st = await stat(archive, filepath) - if (isBinary !== false && st && st.isFile() && await isFileContentBinary(archive, filepath)) { - throw new InvalidEncodingError('Cannot diff a binary file') - } - if (st && st.isFile() && st.size > MAX_DIFF_SIZE) { - throw new SourceTooLargeError() - } - - // read the file in both sources - const [newFile, oldFile] = await Promise.all([readFile(scopedFS, filepath), readFile(archive, filepath)]) - - // return the diff - return diff.diffLines(oldFile, newFile) -} - -// validate a path to be used for sync -exports.assertSafePath = async function (p) { - // check whether this is an OS path - for (let disallowedSavePath of disallowedSavePaths) { - if (path.normalize(p) === path.normalize(disallowedSavePath)) { - throw new ProtectedFileNotWritableError(`This is a protected folder. Please pick another folder or subfolder.`) - } - } - - // stat the folder - const stat = await new Promise(resolve => { - fs.stat(p, (_, st) => resolve(st)) - }) - - if (!stat) { - throw new NotFoundError() - } - - if (!stat.isDirectory()) { - throw new NotAFolderError('Invalid target folder: not a folder') - } -} - -// read a datignore from a fs space and turn it into anymatch rules -const readDatIgnore = exports.readDatIgnore = async function (fs) { - var rulesRaw = await readFile(fs, '.datignore') - return toAnymatchRules(rulesRaw) -} - -// filter function used by scoped-fs to hide files in the datignore -exports.applyDatIgnoreFilter = function (archive, filepath) { - const datIgnoreRules = archive.datIgnoreRules || toAnymatchRules('') - var filepaths = explodeFilePaths(filepath) // we need to check parent paths in addition to the target path - var res = filepaths.filter(p => anymatch(datIgnoreRules, p)).length === 0 - return res -} - -// merge the dat.json in the folder and then merge files, with preference to folder files -const mergeArchiveAndFolder = exports.mergeArchiveAndFolder = async function (archive, localSyncPath) { - logger.silly('Merging archive and folder', {details: {path: localSyncPath, key: archive.key.toString('hex')}}) - const readManifest = async (fs) => { - try { return await fs.pda.readManifest() } catch (e) { return {} } - } - var localFS = scopedFSes.get(localSyncPath) - var localManifest = await readManifest(localFS) - var archiveManifest = await readManifest(archive) - var mergedManifest = Object.assign(archiveManifest || {}, localManifest || {}) - await localFS.pda.writeManifest(mergedManifest) - await sync(archive, false, {localSyncPath, shallow: false, addOnly: true}) // archive -> folder (add-only) - await sync(archive, true, {localSyncPath, shallow: false}) // folder -> archive - events.emit('merge:' + archive.key.toString('hex'), archive.key) - logger.silly('Done merging archive and folder', {details: {path: localSyncPath, key: archive.key.toString('hex')}}) -} - -// internal methods -// = - -// sync the dat & folder content -// - toArchive: true to sync folder to archive, false to sync archive to folder -// - opts -// - shallow: bool, dont descend into changed folders (default true) -// - compareContent: bool, compare the actual content (default true) -// - paths: Array, a whitelist of files to compare -// - localSyncPath: string, override the archive localSyncPath -// - addOnly: bool, dont modify or remove any files (default false) -async function sync (archive, toArchive, opts = {}) { - opts = opts || {} - var localSyncPath = opts.localSyncPath || (archive.localSyncSettings && archive.localSyncSettings.path) - if (!localSyncPath) return logger.warn('Sanity check failed - sync() aborting, no localSyncPath') - - archive._activeSyncs = (archive._activeSyncs || 0) + 1 - var release = await getArchiveSyncLock(archive) - try { - var scopedFS = scopedFSes.get(localSyncPath) - opts = massageDiffOpts(opts) - - // build ignore rules - if (opts.paths) { - opts.filter = makeDiffFilterByPaths(opts.paths) - } else { - let ignoreRules = await readDatIgnore(scopedFS) - opts.filter = (filepath) => anymatch(ignoreRules, filepath) - } - - // choose direction - var left = toArchive ? {fs: scopedFS} : {fs: archive} - var right = toArchive ? {fs: archive} : {fs: scopedFS} - - // run diff - opts.compareContentCache = archive._compareContentCache - var diff = await dft.diff(left, right, opts) - if (opts.addOnly) { - diff = diff.filter(d => d.change === 'add') - } - logger.silly(`Syncing to ${toArchive ? 'archive' : 'folder'}`, {details: {key: archive.key.toString('hex'), path: localSyncPath}}) - - // sync data - await dft.applyRight(left, right, diff) - events.emit('sync', archive.key, toArchive ? 'archive' : 'folder') - events.emit('sync:' + archive.key.toString('hex'), archive.key, toArchive ? 'archive' : 'folder') - - // decrement active syncs - archive._activeSyncs-- - } catch (err) { - logger.error('Failed to sync archive to local path', {details: {key: archive.key.toString('hex'), path: localSyncPath, err: err.toString()}}) - } finally { - release() - } -} - -function getArchiveSyncLock (archive) { - return lock('sync:' + archive.key.toString('hex')) -} - -function makeDiffFilterByPaths (targetPaths) { - targetPaths = targetPaths.map(path.normalize) - return (filepath) => { - for (let i = 0; i < targetPaths.length; i++) { - let targetPath = targetPaths[i] - - if (targetPath.endsWith(path.sep)) { - // a directory - if (filepath === targetPath.slice(0, -1)) return false // the directory itself - if (filepath.startsWith(targetPath)) return false // a file within the directory - } else { - // a file - if (filepath === targetPath) return false - } - if (targetPath.startsWith(filepath) && targetPath.charAt(filepath.length) === path.sep) { - return false // a parent folder - } - } - return true - } -} - -function massageDiffOpts (opts) { - return { - compareContent: typeof opts.compareContent === 'boolean' ? opts.compareContent : true, - shallow: typeof opts.shallow === 'boolean' ? opts.shallow : true, - paths: Array.isArray(opts.paths) ? opts.paths.filter(v => typeof v === 'string') : false, - addOnly: typeof opts.addOnly === 'boolean' ? opts.addOnly : false - } -} - -// helper to read a file via promise and return a null on fail -async function stat (fs, filepath) { - return new Promise(resolve => { - fs.stat(filepath, (_, data) => { - resolve(data || null) - }) - }) -} - -// helper to read a file via promise and return an empty string on fail -async function readFile (fs, filepath) { - return new Promise(resolve => { - fs.readFile(filepath, {encoding: 'utf8'}, (_, data) => { - resolve(data || '') - }) - }) -} - -// helper to go from '/foo/bar/baz' to ['/', '/foo', '/foo/bar', '/foo/bar/baz'] -function explodeFilePaths (str) { - str = str.replace(/^\/|\/$/g, '') // strip leading and trailing slashes - var paths = str.split('/') - let lastPath = '' - for (let i = 0; i < paths.length; i++) { - lastPath = paths[i] = `${lastPath}/${paths[i]}` - } - return paths -} diff --git a/dat/daemon/index.js b/dat/daemon/index.js deleted file mode 100644 index e471093a..00000000 --- a/dat/daemon/index.js +++ /dev/null @@ -1,691 +0,0 @@ -const crypto = require('crypto') -const EventEmitter = require('events') -const emitStream = require('emit-stream') -const CircularAppendFile = require('circular-append-file') -const through = require('through2') -const split = require('split2') -const concat = require('concat-stream') -const throttle = require('lodash.throttle') -const isEqual = require('lodash.isequal') -const pump = require('pump') -const jetpack = require('fs-jetpack') -const {join} = require('path') - -// dat modules -const hyperdrive = require('hyperdrive') -const hypercoreProtocol = require('hypercore-protocol') -const pda = require('pauls-dat-api2') -const datEncoding = require('dat-encoding') - -// network modules -const swarmDefaults = require('datland-swarm-defaults') -const discoverySwarm = require('discovery-swarm') -const networkSpeed = require('hyperdrive-network-speed') -const {ThrottleGroup} = require('stream-throttle') - -const baseLogger = require('./logger') -const logger = baseLogger.child({category: 'dat', subcategory: 'daemon'}) -const datStorage = require('./storage') -const folderSync = require('./folder-sync') -const {addArchiveSwarmLogging} = require('./logging-utils') -const datExtensions = require('./extensions') -const scopedFSes = require('../../lib/scoped-fses') -const {DAT_SWARM_PORT} = require('../../lib/const') -const RPC_MANIFEST = require('./manifest') - -// globals -// = - -var datPath -var networkId = crypto.randomBytes(32) -var archives = {} // in-memory cache of archive objects. key -> archive -var archivesByDKey = {} // same, but discoveryKey -> archive -var daemonEvents = new EventEmitter() -var debugEvents = new EventEmitter() -var debugLogFile -var archiveSwarm - -var upThrottleGroup -var downThrottleGroup - -// exported api -// = - -exports.setup = async function ({rpcAPI, logfilePath}) { - // export API - rpcAPI.exportAPI('dat-daemon', RPC_MANIFEST, RPC_API) - - // setup storage - await datStorage.setup() - debugLogFile = CircularAppendFile(logfilePath, {maxSize: 1024 /* 1kb */ * 1024 /* 1mb */ * 50 /* 50mb */ }) - - // setup extension messages - datExtensions.setup() - - // re-export events - folderSync.events.on('sync', (key, direction) => { - daemonEvents.emit('folder-synced', { - details: { - url: `dat://${datEncoding.toStr(key)}`, - direction - } - }) - }) - folderSync.events.on('error', (key, err) => { - daemonEvents.emit('folder-sync-error', { - details: { - url: `dat://${datEncoding.toStr(key)}`, - name: err.name, - message: err.message - } - }) - }) - - // setup the archive swarm - archiveSwarm = discoverySwarm(swarmDefaults({ - id: networkId, - hash: false, - utp: true, - tcp: true, - dht: false, - connect: connectReplicationStream, - stream: createReplicationStream - })) - addArchiveSwarmLogging({archivesByDKey, log, archiveSwarm}) - archiveSwarm.once('error', () => archiveSwarm.listen(0)) - archiveSwarm.listen(DAT_SWARM_PORT) - archiveSwarm.on('error', error => log(null, {event: 'swarm-error', message: error.toString()}, 'warn')) - - logger.info('Initialized dat daemon') -} - -// rpc api -// = - -const RPC_API = { - // setup & config - // = - - /** - * @method - * @param {*} opts - */ - async setup (opts) { - datPath = opts.datPath - folderSync.setup(opts) - }, - - // up/down are in MB/s - async setBandwidthThrottle ({up, down}) { - logger.info('Setting bandwidth throttle', {details: {up, down}}) - if (typeof up !== 'undefined') { - upThrottleGroup = up ? new ThrottleGroup({rate: up * 1e6}) : null - } - if (typeof down !== 'undefined') { - downThrottleGroup = down ? new ThrottleGroup({rate: down * 1e6}) : null - } - }, - - // event streams & debug - // = - - createLogStream () { - return emitStream(baseLogger.events) - }, - - createEventStream () { - return emitStream(daemonEvents) - }, - - createDebugStream () { - return emitStream(debugEvents) - }, - - async getDebugLog (key) { - return new Promise((resolve, reject) => { - let rs = debugLogFile.createReadStream() - rs - .pipe(split()) - .pipe(through({encoding: 'utf8', decodeStrings: false}, (data, _, cb) => { - if (data && (!key || data.startsWith(key))) { - return cb(null, data.slice(64) + '\n') - } - cb() - })) - .pipe(concat({encoding: 'string'}, resolve)) - rs.on('error', reject) - }) - }, - - // archive management - // = - - async configureArchive (key, userSettings) { - var archive = getArchive(key) - if (archive) { - configureNetwork(archive, userSettings) - configureAutoDownload(archive, userSettings) - configureLocalSync(archive, userSettings) - } - }, - - async getArchiveInfo (key) { - var archive = getArchive(key) - if (!archive) return {} - return { - version: archive.version, - size: archive.size, - peers: archive.metadata.peers.length, - peerInfo: getArchivePeerInfos(archive), - peerHistory: archive.peerHistory, - networkStats: archive.networkStats - } - }, - - async getArchiveNetworkStats (key) { - var archive = getArchive(key) - if (!archive) return {} - return archive.networkStats - }, - - updateSizeTracking, - - async loadArchive (opts) { - var { - key, - secretKey, - metaPath, - userSettings - } = opts - var logDetails = {key: key.toString('hex')} - - // create the archive instance - logger.verbose('Loading archive', {details: logDetails}) - var archive = hyperdrive(datStorage.create(metaPath), key, { - sparse: true, - secretKey - // metadataStorageCacheSize: 0, - // contentStorageCacheSize: 0, - // treeCacheSize: 2048 - }) - archive.on('error', err => { - let k = key.toString('hex') - log(k, {event: 'archive-error', message: err.toString()}, 'warn') - console.error('Error in archive', k, err) - }) - archive.metadata.on('peer-add', () => onNetworkChanged(archive)) - archive.metadata.on('peer-remove', () => onNetworkChanged(archive)) - archive.networkStats = networkSpeed(archive) - archive.replicationStreams = [] // list of all active replication streams - archive.peerHistory = [] // samples of the peer count - - // wait for ready - await new Promise((resolve, reject) => { - archive.ready(err => { - if (err) reject(err) - else resolve() - }) - }) - logger.silly('Archive ready', {details: {key: logDetails}}) - await updateSizeTracking(archive) - - // attach extensions - datExtensions.attach(archive) - - // store in the discovery listing, so the swarmer can find it - // but not yet in the regular archives listing, because it's not fully loaded - var discoveryKey = datEncoding.toStr(archive.discoveryKey) - archivesByDKey[discoveryKey] = archive - - // setup the archive based on current settings - configureNetwork(archive, userSettings) - configureAutoDownload(archive, userSettings) - configureLocalSync(archive, userSettings) - - // await initial metadata sync if not the owner - if (!archive.writable && !archive.metadata.length) { - // wait to receive a first update - await new Promise((resolve, reject) => { - archive.metadata.update(err => { - if (err) reject(err) - else resolve() - }) - }) - } - if (!archive.writable) { - // always download all metadata - archive.metadata.download({start: 0, end: -1}) - } - - // watch for sync events - archive.fileActStream = archive.pda.watch() - archive.fileActStream.on('data', ([event, {path}]) => { - if (event === 'changed') { - if (!archive.localSyncSettings) return - // need to sync this change to the local folder - if (archive.localSyncSettings.autoPublish) { - // bidirectional sync: use the sync queue - folderSync.queueSyncEvent(archive, {toFolder: true}) - } else { - // preview mode: just write this update to disk - folderSync.syncArchiveToFolder(archive, {paths: [path], shallow: false}) - } - } - }) - - // store in the archives list - archives[datEncoding.toStr(archive.key)] = archive - - // return some archive info - return {discoveryKey, writable: archive.writable} - }, - - async unloadArchive (key) { - const archive = archives[key] - if (!archive) { - return - } - logger.verbose('Unloading archive', {details: {key}}) - - // shutdown archive - leaveSwarm(key) - stopAutodownload(archive) - if (archive.fileActStream) { - archive.fileActStream.end() - archive.fileActStream = null - } - datExtensions.detach(archive) - await new Promise((resolve, reject) => { - archive.close(err => { - if (err) reject(err) - else resolve() - }) - }) - delete archivesByDKey[datEncoding.toStr(archive.discoveryKey)] - delete archives[key] - }, - - // archive methods - // = - - callArchiveAsyncMethod (key, version, method, ...args) { - var checkout = getArchiveCheckout(key, version) - checkout[method](...args) - }, - - callArchiveReadStreamMethod (key, version, method, ...args) { - var checkout = getArchiveCheckout(key, version) - return checkout[method](...args) - }, - - callArchiveWriteStreamMethod (key, version, method, ...args) { - var checkout = getArchiveCheckout(key, version) - return checkout[method](...args) - }, - - callArchivePDAPromiseMethod (key, version, method, ...args) { - var checkout = getArchiveCheckout(key, version) - return pda[method](checkout, ...args) - }, - - callArchivePDAReadStreamMethod (key, version, method, ...args) { - var checkout = getArchiveCheckout(key, version) - return pda[method](checkout, ...args) - }, - - async clearFileCache (key, userSettings) { - var archive = await getArchive(key) - if (!archive || archive.writable) { - return // abort, only clear the content cache of downloaded archives - } - logger.info('Clearing archive file cache', {details: {key: key.toString('hex')}}) - - // clear the cache - await new Promise((resolve, reject) => { - archive.content.clear(0, archive.content.length, err => { - if (err) reject(err) - else resolve() - }) - }) - - // force a reconfig of the autodownloader - stopAutodownload(archive) - configureAutoDownload(archive, userSettings) - }, - - async exportFilesystemToArchive (opts) { - opts.dstArchive = getArchive(opts.dstArchive) - return pda.exportFilesystemToArchive(opts) - }, - - async exportArchiveToFilesystem (opts) { - opts.srcArchive = getArchive(opts.srcArchive) - return pda.exportFilesystemToArchive(opts) - }, - - async exportArchiveToArchive (opts) { - opts.srcArchive = getArchive(opts.srcArchive) - opts.dstArchive = getArchive(opts.dstArchive) - return pda.exportArchiveToArchive(opts) - }, - - // folder sync - // = - - fs_assertSafePath: folderSync.assertSafePath, - fs_ensureSyncFinished: key => folderSync.ensureSyncFinished(getArchive(key)), - fs_diffListing: (key, ...args) => folderSync.diffListing(getArchive(key), ...args), - fs_diffFile: (key, ...args) => folderSync.diffFile(getArchive(key), ...args), - fe_queueSyncEvent: (key, ...args) => folderSync.queueSyncEvent(getArchive(key), ...args), - fs_syncFolderToArchive: (key, ...args) => folderSync.syncFolderToArchive(getArchive(key), ...args), - fs_syncArchiveToFolder: (key, ...args) => folderSync.syncArchiveToFolder(getArchive(key), ...args), - - // dat extensions - // = - - ext_listPeers: async (key, ...args) => datExtensions.listPeers(getArchive(key), ...args), - ext_getPeer: async (key, ...args) => datExtensions.getPeer(getArchive(key), ...args), - ext_getOwnPeerId: () => datEncoding.toStr(networkId), - ext_broadcastEphemeralMessage: async (key, ...args) => datExtensions.broadcastEphemeralMessage(getArchive(key), ...args), - ext_sendEphemeralMessage: async (key, ...args) => datExtensions.sendEphemeralMessage(getArchive(key), ...args), - ext_getSessionData: async (key, ...args) => datExtensions.getSessionData(getArchive(key), ...args), - ext_setSessionData: async (key, ...args) => datExtensions.setSessionData(getArchive(key), ...args), - ext_createDatPeersStream: async (key, ...args) => datExtensions.createDatPeersStream(getArchive(key), ...args) -} - -// archive networking -// = - -// set the networking of an archive based on settings -function configureNetwork (archive, settings) { - if (!settings || settings.networked) { - joinSwarm(archive) - } else { - leaveSwarm(archive) - } -} - -// put the archive into the network, for upload and download -const joinSwarm = exports.joinSwarm = function joinSwarm (key, opts) { - var archive = (typeof key === 'object' && key.key) ? key : getArchive(key) - if (!archive || archive.isSwarming) return - archiveSwarm.join(archive.discoveryKey) - var keyStr = datEncoding.toStr(archive.key) - log(keyStr, { - event: 'swarming', - discoveryKey: datEncoding.toStr(archive.discoveryKey) - }) - archive.isSwarming = true -} - -// take the archive out of the network -const leaveSwarm = exports.leaveSwarm = function leaveSwarm (key) { - var archive = (typeof key === 'object' && key.discoveryKey) ? key : getArchive(key) - if (!archive || !archive.isSwarming) return - - var keyStr = datEncoding.toStr(archive.key) - log(keyStr, { - event: 'unswarming', - message: `Disconnected ${archive.metadata.peers.length} peers` - }) - - archive.replicationStreams.forEach(stream => stream.destroy()) // stop all active replications - archive.replicationStreams.length = 0 - archiveSwarm.leave(archive.discoveryKey) - archive.isSwarming = false -} - -// internal methods -// = - -function getArchive (key) { - if (key instanceof hyperdrive) return key - if (key.key) key = key.key - return archives[datEncoding.toStr(key)] -} - -function getArchiveCheckout (key, version) { - var archive = getArchive(key) - var checkoutFS = archive - if (version) { - let seq = parseInt(version) - if (Number.isNaN(seq)) { - if (version === 'latest') { - // ignore, we use latest by default - } else if (version === 'preview') { - if (archive.localSyncSettings) { - // checkout local sync path - checkoutFS = scopedFSes.get(archive.localSyncSettings.path) - checkoutFS.setFilter(p => folderSync.applyDatIgnoreFilter(archive, p)) - } else { - let err = new Error('Preview mode is not enabled for this dat') - err.noPreviewMode = true - throw err - } - } else { - throw new Error('Invalid version identifier:' + version) - } - } else { - if (seq <= 0) throw new Error('Version too low') - if (seq > archive.version) throw new Error('Version too high') - checkoutFS = archive.checkout(seq, {metadataStorageCacheSize: 0, contentStorageCacheSize: 0, treeCacheSize: 0}) - } - } - return checkoutFS -} - -async function updateSizeTracking (archive) { - archive = getArchive(archive) - try { - archive.size = await archive.pda.readSize('/') - } catch (e) { - archive.size = 0 - } - return archive.size -} - -function configureAutoDownload (archive, userSettings) { - if (archive.writable) { - return // abort, only used for unwritable - } - // HACK - // mafintosh is planning to put APIs for this inside of hyperdrive - // till then, we'll do our own inefficient downloader - // -prf - const isAutoDownloading = userSettings.isSaved && userSettings.autoDownload - if (!archive._autodownloader && isAutoDownloading) { - // setup the autodownload - archive._autodownloader = { - undownloadAll: () => { - if (archive.content) { - archive.content._selections.forEach(range => archive.content.undownload(range)) - } - }, - onUpdate: throttle(() => { - // cancel ALL previous, then prioritize ALL current - archive._autodownloader.undownloadAll() - archive.pda.download('/').catch(e => { /* ignore cancels */ }) - }, 5e3) - } - archive.metadata.on('download', archive._autodownloader.onUpdate) - archive.pda.download('/').catch(e => { /* ignore cancels */ }) - } else if (archive._autodownloader && !isAutoDownloading) { - stopAutodownload(archive) - } -} - -function configureLocalSync (archive, userSettings) { - var oldLocalSyncSettings = archive.localSyncSettings - archive.localSyncSettings = getLocalSyncSettings(archive, userSettings) - - if (!isEqual(archive.localSyncSettings, oldLocalSyncSettings)) { - // configure the local folder watcher if a change occurred - folderSync.configureFolderToArchiveWatcher(archive) - } - - if (!archive.localSyncSettings || !archive.localSyncSettings.isUsingInternal) { - // clear the internal directory if it's not in use - jetpack.removeAsync(getInternalLocalSyncPath(archive)) - } -} - -function getLocalSyncSettings (archive, userSettings) { - if (!archive.writable || !userSettings.isSaved) { - return false - } - if (userSettings.localSyncPath) { - return { - path: userSettings.localSyncPath, - autoPublish: !userSettings.previewMode - } - } - if (userSettings.previewMode) { - return { - path: getInternalLocalSyncPath(archive), - autoPublish: false, - isUsingInternal: true - } - } - return false -} - -function stopAutodownload (archive) { - if (archive._autodownloader) { - archive._autodownloader.undownloadAll() - archive.metadata.removeListener('download', archive._autodownloader.onUpdate) - archive._autodownloader = null - } -} - -function connectReplicationStream (local, remote) { - var streams = [local, remote, local] - if (upThrottleGroup) streams.splice(1, 0, upThrottleGroup.throttle()) - if (downThrottleGroup) streams.splice(-1, 0, downThrottleGroup.throttle()) - pump(streams) -} - -function createReplicationStream (info) { - // create the protocol stream - var streamKeys = [] // list of keys replicated over the streamd - var stream = hypercoreProtocol({ - id: networkId, - live: true, - encrypt: true, - extensions: ['ephemeral', 'session-data'] - }) - stream.peerInfo = info - - // add the archive if the discovery network gave us any info - if (info.channel) { - add(info.channel) - } - - // add any requested archives - stream.on('feed', add) - - function add (dkey) { - // lookup the archive - var dkeyStr = datEncoding.toStr(dkey) - var archive = archivesByDKey[dkeyStr] - if (!archive || !archive.isSwarming) { - return - } - if (archive.replicationStreams.indexOf(stream) !== -1) { - return // already replicating - } - - // create the replication stream - archive.replicate({stream, live: true}) - if (stream.destroyed) return // in case the stream was destroyed during setup - - // track the stream - var keyStr = datEncoding.toStr(archive.key) - streamKeys.push(keyStr) - archive.replicationStreams.push(stream) - function onend () { - archive.replicationStreams = archive.replicationStreams.filter(s => (s !== stream)) - } - stream.once('error', onend) - stream.once('end', onend) - stream.once('finish', onend) - stream.once('close', onend) - } - - // debugging - stream.on('error', err => { - log(streamKeys, { - event: 'connection-error', - peer: `${info.host}:${info.port}`, - connectionType: info.type, - message: err.toString() - }, 'warn') - }) - - return stream -} - -function onNetworkChanged (archive) { - var now = Date.now() - var lastHistory = archive.peerHistory.slice(-1)[0] - if (lastHistory && (now - lastHistory.ts) < 10e3) { - // if the last datapoint was < 10s ago, just update it - lastHistory.peers = archive.metadata.peers.length - } else { - archive.peerHistory.push({ - ts: Date.now(), - peers: archive.metadata.peers.length - }) - } - - // keep peerHistory from getting too long - if (archive.peerHistory.length >= 500) { - // downsize to 360 points, which at 10s intervals covers one hour - archive.peerHistory = archive.peerHistory.slice(archive.peerHistory.length - 360) - } - - // count # of peers - var totalPeerCount = 0 - for (var k in archives) { - totalPeerCount += archives[k].metadata.peers.length - } - - daemonEvents.emit('network-changed', { - details: { - url: `dat://${datEncoding.toStr(archive.key)}`, - peers: getArchivePeerInfos(archive), - connections: archive.metadata.peers.length, - totalPeerCount - } - }) -} - -function getArchivePeerInfos (archive) { - // old way, more accurate? - // archive.replicationStreams.map(s => ({host: s.peerInfo.host, port: s.peerInfo.port})) - - return archive.metadata.peers.map(peer => peer.stream.stream.peerInfo).filter(Boolean) -} - -function getInternalLocalSyncPath (archiveOrKey) { - var key = datEncoding.toStr(archiveOrKey.key || archiveOrKey) - return join(datPath, 'Archives', 'LocalCopy', key.slice(0, 2), key.slice(2)) -} - -// helpers -// = - -function log (key, data, logLevel = false) { - var keys = Array.isArray(key) ? key : [key] - keys.forEach(k => { - let data2 = Object.assign(data, {archiveKey: k}) - debugEvents.emit(k, data2) - debugEvents.emit('all', data2) - }) - if (keys[0]) { - debugLogFile.append(keys[0] + JSON.stringify(data) + '\n') - } - if (logLevel) { - let message = data.event + (data.message ? `: ${data.message}` : '') - logger.log(logLevel, message, {details: {key, peer: data.peer}}) - } -} \ No newline at end of file diff --git a/dat/daemon/logger.js b/dat/daemon/logger.js deleted file mode 100644 index e5b07c5e..00000000 --- a/dat/daemon/logger.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * This logger is just an event-emitter wrapper which streams to the main process. - * The main process then folds the events into the main logger. - */ - -const Emitter = require('events') - -// globals -// = - -const events = new Emitter() - -// exported api -// = - -exports.events = events - -exports.child = (meta = {}) => { - const log = (level, message, etc = {}) => { - Object.assign(etc, meta) - events.emit('log', {level, message, etc}) - } - return { - log, - error: (...args) => log('error', ...args), - warn: (...args) => log('warn', ...args), - info: (...args) => log('info', ...args), - verbose: (...args) => log('verbose', ...args), - debug: (...args) => log('debug', ...args), - silly: (...args) => log('silly', ...args) - } -} \ No newline at end of file diff --git a/dat/daemon/logging-utils.js b/dat/daemon/logging-utils.js deleted file mode 100644 index df028362..00000000 --- a/dat/daemon/logging-utils.js +++ /dev/null @@ -1,232 +0,0 @@ -const datEncoding = require('dat-encoding') - -const findFullDiscoveryKey = exports.findFullDiscoveryKey = function (archivesByDKey, key) { - key = Buffer.isBuffer(key) ? key.toString('hex') : key - // HACK - // if the key is short, try to find the full thing in our list - // (this shouldnt be needed once discovery stops truncating keys) - // -prf - if (key && key.length === 40) { - let dKeys = Object.keys(archivesByDKey) - for (let i = 0; i < dKeys.length; i++) { - if (dKeys[i].startsWith(key)) { - return dKeys[i] - } - } - } - return key -} - -const getDNSMessageDiscoveryKey = exports.getDNSMessageDiscoveryKey = function (archivesByDKey, msg) { - var key - function check (obj) { - if (!key && obj.name.endsWith('.dat.local')) { - key = findFullDiscoveryKey(archivesByDKey, obj.name.slice(0, -10)) - } - } - if (msg.questions) msg.questions.forEach(check) - if (msg.answers) msg.answers.forEach(check) - if (msg.additionals) msg.additionals.forEach(check) - return key || '' -} - -function has (str, v) { - return str.indexOf(v) !== -1 -} - -const addArchiveSwarmLogging = exports.addArchiveSwarmLogging = function ({archivesByDKey, log, archiveSwarm}) { - archiveSwarm.on('listening', () => { - archiveSwarm._discovery.dns.on('traffic', (type, details) => { - let archive = archivesByDKey[getDNSMessageDiscoveryKey(archivesByDKey, details.message)] - if (!archive) return - log(datEncoding.toStr(archive.key), { - event: 'traffic', - trafficType: type, - messageId: details.message.id, - message: renderDNSTraffic(details.message), - peer: details.peer ? `${details.peer.address || details.peer.host}:${details.peer.port}` : undefined - }) - }) - }) - archiveSwarm.on('peer', (peer) => { - let archive = archivesByDKey[findFullDiscoveryKey(archivesByDKey, peer.channel)] - if (!archive) return - log(datEncoding.toStr(archive.key), { - event: 'peer-found', - peer: `${peer.address || peer.host}:${peer.port}` - }, 'silly') - }) - archiveSwarm.on('peer-banned', (peer, details) => { - let archive = archivesByDKey[findFullDiscoveryKey(archivesByDKey, peer.channel)] - if (!archive) return - log(datEncoding.toStr(archive.key), { - event: 'peer-banned', - peer: `${peer.address || peer.host}:${peer.port}`, - message: peerBannedReason(details.reason) - }, 'info') - }) - archiveSwarm.on('peer-rejected', (peer, details) => { - let archive = archivesByDKey[findFullDiscoveryKey(archivesByDKey, peer.channel)] - if (!archive) return - log(datEncoding.toStr(archive.key), { - event: 'peer-rejected', - peer: `${peer.address || peer.host}:${peer.port}`, - message: peerRejectedReason(details.reason) - }, 'silly') - }) - archiveSwarm.on('drop', (peer) => { - let archive = archivesByDKey[findFullDiscoveryKey(archivesByDKey, peer.channel)] - if (!archive) return - log(datEncoding.toStr(archive.key), { - event: 'peer-dropped', - peer: `${peer.address || peer.host}:${peer.port}`, - message: 'Too many failed connection attempts' - }, 'silly') - }) - archiveSwarm.on('connecting', (peer) => { - let archive = archivesByDKey[findFullDiscoveryKey(archivesByDKey, peer.channel)] - if (!archive) return - log(datEncoding.toStr(archive.key), { - event: 'connecting', - peer: `${peer.address || peer.host}:${peer.port}` - }, 'debug') - }) - archiveSwarm.on('connect-failed', (peer, details) => { - let archive = archivesByDKey[findFullDiscoveryKey(archivesByDKey, peer.channel)] - if (!archive) return - log(datEncoding.toStr(archive.key), { - event: 'connect-failed', - peer: `${peer.address || peer.host}:${peer.port}`, - message: connectFailedMessage(details) - }, 'debug') - }) - archiveSwarm.on('handshaking', (conn, peer) => { - let archive = archivesByDKey[findFullDiscoveryKey(archivesByDKey, peer.channel)] - if (!archive) return - log(datEncoding.toStr(archive.key), { - event: 'handshaking', - peer: `${peer.address || peer.host}:${peer.port}`, - connectionId: conn._debugId, - connectionType: peer.type, - ts: 0 - }, 'silly') - }) - archiveSwarm.on('handshake-timeout', (conn, peer) => { - let archive = archivesByDKey[findFullDiscoveryKey(archivesByDKey, peer.channel)] - if (!archive) return - log(datEncoding.toStr(archive.key), { - event: 'handshake-timeout', - peer: `${peer.address || peer.host}:${peer.port}`, - connectionId: conn._debugId, - connectionType: peer.type, - ts: Date.now() - conn._debugStartTime - }, 'silly') - }) - archiveSwarm.on('connection', (conn, peer) => { - let archive = archivesByDKey[findFullDiscoveryKey(archivesByDKey, peer.channel)] - if (!archive) return - log(datEncoding.toStr(archive.key), { - event: 'connection-established', - peer: `${peer.address || peer.host}:${peer.port}`, - connectionId: conn._debugId, - connectionType: peer.type, - ts: Date.now() - conn._debugStartTime, - message: 'Starting replication' - }, 'debug') - }) - archiveSwarm.on('redundant-connection', (conn, peer) => { - let archive = archivesByDKey[findFullDiscoveryKey(archivesByDKey, peer.channel)] - if (!archive) return - log(datEncoding.toStr(archive.key), { - event: 'redundant-connection', - peer: `${peer.address || peer.host}:${peer.port}`, - connectionId: conn._debugId, - connectionType: peer.type, - ts: Date.now() - conn._debugStartTime - }, 'silly') - }) - archiveSwarm.on('connection-closed', (conn, peer) => { - let archive = archivesByDKey[findFullDiscoveryKey(archivesByDKey, peer.channel)] - if (!archive) return - log(datEncoding.toStr(archive.key), { - event: 'connection-closed', - peer: `${peer.address || peer.host}:${peer.port}`, - connectionId: conn._debugId, - connectionType: peer.type, - ts: Date.now() - conn._debugStartTime - }, 'debug') - }) -} - -const renderDNSTraffic = exports.renderDNSTraffic = function ({questions, answers, additionals}) { - var messageParts = [] - if (questions && (!answers || !answers.length) && (!additionals || !additionals.length)) { - questions.forEach(q => { - if (q.type === 'TXT') { - messageParts.push('TXT Question (requesting peers list)') - } else { - messageParts.push(q.type + ' Question') - } - }) - } - if (answers) { - answers.forEach(a => { - if (a.type === 'TXT' && a.data) { - let data = a.data.toString() - if (has(data, 'host') && has(data, 'token')) { - messageParts.push('TXT Answer (heres a session token)') - } else if (has(data, 'peers')) { - messageParts.push('TXT Answer (heres a peers list)') - } else if (has(data, 'token')) { - messageParts.push('TXT Answer (no peers found)') - } else { - messageParts.push('TXT Answer') - } - } else { - messageParts.push(a.type + ' Answer') - } - }) - } - if (additionals) { - additionals.forEach(a => { - if (a.type === 'TXT' && a.data) { - let data = a.data.toString() - if (has(data, 'announce')) { - messageParts.push('TXT Additional (announcing self)') - } else if (has(data, 'unannounce')) { - messageParts.push('TXT Additional (unannouncing self)') - } else if (has(data, 'subscribe')) { - messageParts.push('TXT Additional (subscribing)') - } else { - messageParts.push('TXT Additional') - } - } else if (a.type === 'SRV' && a.data) { - messageParts.push('SRV Additional (pushed announcement)') - } else { - messageParts.push(a.type + ' Additional') - } - }) - } - return messageParts.join(', ') -} - -function connectFailedMessage (details) { - if (details.timedout) return 'Timed out' -} - -function peerBannedReason (reason) { - switch (reason) { - case 'detected-self': return 'Detected that the peer is this process' - case 'application': return 'Peer was removed by the application' - } - return '' -} - -function peerRejectedReason (reason) { - switch (reason) { - case 'whitelist': return 'Peer was not on the whitelist' - case 'banned': return 'Peer is on the ban list' - case 'duplicate': return 'Peer was a duplicate (already being handled)' - } - return '' -} diff --git a/dat/daemon/manifest.js b/dat/daemon/manifest.js deleted file mode 100644 index 09a78f27..00000000 --- a/dat/daemon/manifest.js +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @typedef {import('../../dbs/archives').LibraryArchiveUserSettings} LibraryArchiveUserSettings - * - * @typedef {Object} DatDaemon - * @prop {function(DatDaemonSetupOpts): Promise} setup - * @prop {function(DatDaemonThrottleOpts): Promise} setBandwidthThrottle - * @prop {function(): NodeJS.ReadableStream} createLogStream - * @prop {function(): NodeJS.ReadableStream} createEventStream - * @prop {function(): NodeJS.ReadableStream} createDebugStream - * @prop {function(string): Promise} getDebugLog - * @prop {function(string | Buffer, LibraryArchiveUserSettings): Promise} configureArchive - * @prop {function(string | Buffer): Promise} getArchiveInfo - * @prop {function(string | Buffer): Promise} getArchiveNetworkStats - * @prop {function(string | Buffer): Promise} updateSizeTracking - * @prop {function(DatDaemonLoadArchiveOpts): Promise} loadArchive - * @prop {function(string): Promise} unloadArchive - * @prop {function(any=, ...any=): void} callArchiveAsyncMethod - * @prop {function(any=, ...any=): NodeJS.ReadableStream} callArchiveReadStreamMethod - * @prop {function(any=, ...any=): NodeJS.WritableStream} callArchiveWriteStreamMethod - * @prop {function(any=, ...any=): Promise} callArchivePDAPromiseMethod - * @prop {function(any=, ...any=): NodeJS.ReadableStream} callArchivePDAReadStreamMethod - * @prop {function(string | Buffer, LibraryArchiveUserSettings): Promise} clearFileCache - * @prop {function(Object): Promise} exportFilesystemToArchive - * @prop {function(Object): Promise} exportArchiveToFilesystem - * @prop {function(Object): Promise} exportArchiveToArchive - * @prop {function(string): Promise} fs_assertSafePath - * @prop {function(string | Buffer): Promise} fs_ensureSyncFinished - * @prop {function(string | Buffer, [DatDaemonFSDiffListingOpts]): Promise} fs_diffListing - * @prop {function(string | Buffer, string): Promise} fs_diffFile - * @prop {function(string | Buffer, DatDaemonFSQueueSyncEventOpts): Promise} fe_queueSyncEvent - * @prop {function(string | Buffer, [DatDaemonFSDiffListingOpts]): Promise} fs_syncFolderToArchive - * @prop {function(string | Buffer, [DatDaemonFSDiffListingOpts]): Promise} fs_syncArchiveToFolder - * @prop {function(any=, ...any=): Promise} ext_listPeers - * @prop {function(any=, ...any=): Promise} ext_getPeer - * @prop {function(any=, ...any=): Promise} ext_broadcastEphemeralMessage - * @prop {function(any=, ...any=): Promise} ext_sendEphemeralMessage - * @prop {function(any=, ...any=): Promise} ext_getSessionData - * @prop {function(any=, ...any=): Promise} ext_setSessionData - * @prop {function(any=, ...any=): NodeJS.ReadableStream} ext_createDatPeersStream - * NOTE: the ext_* methods are temporary so Im not going to bother documenting their types - * - * @typedef {Object} DatDaemonSetupOpts - * @prop {string} datPath - * @prop {string[]} disallowedSavePaths - * - * @typedef {Object} DatDaemonThrottleOpts - * @prop {number} [up] - * @prop {number} [down] - * - * @typedef {Object} DatDaemonLoadArchiveOpts - * @prop {string | Buffer} key - * @prop {Buffer} [secretKey] - * @prop {string} metaPath - * @prop {LibraryArchiveUserSettings} userSettings - * - * @typedef {Object} DatDaemonFSDiffListingOpts - * @prop {boolean} [shallow] - Dont descend into changed folders (default true) - * @prop {boolean} [compareContent] - Compare the actual content (default true) - * @prop {string[]} [paths] - A whitelist of files to compare - * @prop {string} [localSyncPath] - Override the archive localSyncPath - * @prop {boolean} [addOnly] - Dont modify or remove any files (default false) - * - * @typedef {Object} DatDaemonFSQueueSyncEventOpts - * @prop {boolean} toFolder - * @prop {boolean} toArchive - * - * @typedef {Object} DatDaemonLoadedArchiveInfo - * @prop {Buffer} discoveryKey - * @prop {boolean} writable - * - * @typedef {never} DatDaemonPeerInfo - * TODO- what's in here? - * - * @typedef {Object} DatDaemonPeerHistory - * @prop {number} ts - * @prop {number} peers - * - * @typedef {Object} DatDaemonNetworkStats - * @prop {number} downloadSpeed - * @prop {number} uploadSpeed - * @prop {number} downloadTotal - * @prop {number} uploadTotal - * - * @typedef {Object} DatDaemonArchiveInfo - * @prop {number} version - * @prop {number} size - * @prop {number} peers - * @prop {DatDaemonPeerInfo[]} peerInfo - * @prop {DatDaemonPeerHistory[]} peerHistory - * @prop {DatDaemonNetworkStats} networkStats - * - * @typedef {never} DatDaemonFSListingDiff - * TODO - what's in here? - * - * @typedef {never} DatDaemonFSFileDiff - * TODO - what's in here? - */ - -module.exports = { - // setup & config - - setup: 'promise', - setBandwidthThrottle: 'promise', - - // event streams & debug - - createLogStream: 'readable', - createEventStream: 'readable', - createDebugStream: 'readable', - getDebugLog: 'promise', - - // archive management - - configureArchive: 'promise', - getArchiveInfo: 'promise', - getArchiveNetworkStats: 'promise', - updateSizeTracking: 'promise', - loadArchive: 'promise', - unloadArchive: 'promise', - - // archive methods - - callArchiveAsyncMethod: 'async', - callArchiveReadStreamMethod: 'readable', - callArchiveWriteStreamMethod: 'writable', - callArchivePDAPromiseMethod: 'promise', - callArchivePDAReadStreamMethod: 'readable', - clearFileCache: 'promise', - exportFilesystemToArchive: 'async', - exportArchiveToFilesystem: 'async', - exportArchiveToArchive: 'async', - - // folder sync - - fs_assertSafePath: 'promise', - fs_ensureSyncFinished: 'promise', - fs_diffListing: 'promise', - fs_diffFile: 'promise', - fe_queueSyncEvent: 'promise', - fs_syncFolderToArchive: 'promise', - fs_syncArchiveToFolder: 'promise', - - // dat extensions - - ext_listPeers: 'promise', - ext_getPeer: 'promise', - ext_getOwnPeerId: 'promise', - ext_broadcastEphemeralMessage: 'promise', - ext_sendEphemeralMessage: 'promise', - ext_getSessionData: 'promise', - ext_setSessionData: 'promise', - ext_createDatPeersStream: 'readable' -} diff --git a/dat/daemon/storage.js b/dat/daemon/storage.js deleted file mode 100644 index a2215846..00000000 --- a/dat/daemon/storage.js +++ /dev/null @@ -1,53 +0,0 @@ -const path = require('path') -const fs = require('fs') -const detectSparseFiles = require('supports-sparse-files') -const raf = require('random-access-file') -const raif = require('random-access-indexed-file') -const logger = require('./logger').child({category: 'dat', subcategory: 'storage'}) - -// globals -// = - -const LARGE_FILES = ['data', 'signatures'] -const INDEX_BLOCK_SIZE = { - data: 1024 * 1024, // 1mb - signatures: 1024 // 1kb -} -var supportsSparseFiles = false - -// exported api -// = - -exports.setup = async function () { - await new Promise((resolve) => { - detectSparseFiles(function (err, yes) { - supportsSparseFiles = yes - if (!yes) { - logger.info('Sparse-file support not detected. Falling back to indexed data files.') - } - resolve() - }) - }) -} - -function createStorage (folder, subfolder) { - return function (name) { - var filepath = path.join(folder, subfolder, name) - if (fs.existsSync(filepath + '.index')) { - // use random-access-indexed-file because that's what has been used - return raif(filepath, {blockSize: INDEX_BLOCK_SIZE[name]}) - } - if (!supportsSparseFiles && LARGE_FILES.includes(name)) { - // use random-access-indexed-file because sparse-files are not supported and this file tends to get big - return raif(filepath, {blockSize: INDEX_BLOCK_SIZE[name]}) - } - return raf(filepath) - } -} - -exports.create = function (folder) { - return { - metadata: createStorage(folder, 'metadata'), - content: createStorage(folder, 'content') - } -} \ No newline at end of file From 8495aca9cb97bf55971dfd74476bc91055638ee7 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 9 Aug 2019 20:05:45 -0500 Subject: [PATCH 15/74] Reimplement archive size tracking --- dat/daemon.js | 1 - dat/library.js | 49 ++++++++++++++------------------------ package-lock.json | 2 +- web-apis/bg/dat-archive.js | 12 +++++----- 4 files changed, 25 insertions(+), 39 deletions(-) diff --git a/dat/daemon.js b/dat/daemon.js index cf3b39f0..7ceef4bb 100644 --- a/dat/daemon.js +++ b/dat/daemon.js @@ -57,7 +57,6 @@ exports.setup = async function () { await daemon.start() process.on('exit', () => daemon.stop()) - // TODO client = new HyperdriveClient() await client.ready() } diff --git a/dat/library.js b/dat/library.js index 7144c762..caa96570 100644 --- a/dat/library.js +++ b/dat/library.js @@ -193,7 +193,7 @@ const pullLatestArchiveMeta = exports.pullLatestArchiveMeta = async function pul var [manifest, oldMeta, size] = await Promise.all([ archive.pda.readManifest().catch(_ => {}), archivesDb.getMeta(key), - 0 // TODO daemon.updateSizeTracking(key) + archive.pda.readSize('/') ]) var {title, description, type} = (manifest || {}) var isOwner = archive.writable @@ -379,29 +379,23 @@ async function loadArchiveInner (key, userSettings = null) { // wire up events archive.pullLatestArchiveMeta = _debounce(opts => pullLatestArchiveMeta(archive, opts), 1e3) - // TODO - // archive.fileActStream = archive.pda.watch() - // archive.fileActStream.on('data', ([event, {path}]) => { - // if (event === 'changed') { - // archive.pullLatestArchiveMeta({updateMTime: true}) - // datAssets.update(archive, [path]) - // } - // }) - // TODO - // archive.fileActStream = pda.watch(archive) - // archive.fileActStream.on('data', ([event, {path}]) => { - // if (event === 'changed') { - // if (!archive.localSyncSettings) return - // // need to sync this change to the local folder - // if (archive.localSyncSettings.autoPublish) { - // // bidirectional sync: use the sync queue - // folderSync.queueSyncEvent(archive, {toFolder: true}) - // } else { - // // preview mode: just write this update to disk - // folderSync.syncArchiveToFolder(archive, {paths: [path], shallow: false}) - // } - // } - // }) + archive.fileActStream = archive.pda.watch('/') + archive.fileActStream.on('data', ([event, {path}]) => { + if (event !== 'changed') return + archive.pullLatestArchiveMeta({updateMTime: true}) + datAssets.update(archive, [path]) + + if (archive.localSyncSettings) { + // need to sync this change to the local folder + if (archive.localSyncSettings.autoPublish) { + // bidirectional sync: use the sync queue + folderSync.queueSyncEvent(archive, {toFolder: true}) + } else { + // preview mode: just write this update to disk + folderSync.syncArchiveToFolder(archive, {paths: [path], shallow: false}) + } + } + }) // now store in main archives listing, as loaded archives[datEncoding.toStr(archive.key)] = archive @@ -477,11 +471,6 @@ const isArchiveLoaded = exports.isArchiveLoaded = function isArchiveLoaded (key) return key in archives } -exports.updateSizeTracking = function updateSizeTracking (archive) { - return 0 // TODO - // return daemon.updateSizeTracking(datEncoding.toStr(archive.key)) -} - // archive fetch/query // = @@ -502,7 +491,6 @@ exports.queryArchives = async function queryArchives (query) { if (archive) { var info = await archive.getInfo() archiveInfo.isSwarmed = archiveInfo.userSettings.networked - archiveInfo.size = info.size archiveInfo.peers = info.peers } else { archiveInfo.isSwarmed = false @@ -531,7 +519,6 @@ exports.getArchiveInfo = async function getArchiveInfo (key) { meta.links = manifest.links || {} meta.manifest = manifest meta.version = archiveInfo.version - meta.size = archiveInfo.size meta.userSettings = { isSaved: userSettings.isSaved, hidden: userSettings.hidden, diff --git a/package-lock.json b/package-lock.json index 09fc19d4..2125553a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5134,7 +5134,7 @@ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" }, "pauls-dat-api2": { - "version": "github:beakerbrowser/pauls-dat-api2#cba9eac145a96e7927dec97160c3e3e14d55240d", + "version": "github:beakerbrowser/pauls-dat-api2#656345bf9d6652d25592364a3d10186a8bd31ee8", "from": "github:beakerbrowser/pauls-dat-api2", "requires": { "anymatch": "^1.3.2", diff --git a/web-apis/bg/dat-archive.js b/web-apis/bg/dat-archive.js index 9ea8dd79..398bf8f7 100644 --- a/web-apis/bg/dat-archive.js +++ b/web-apis/bg/dat-archive.js @@ -694,17 +694,17 @@ async function assertQuotaPermission (archive, senderOrigin, byteLength) { return } - // fetch the archive settings - const userSettings = archivesDb.getUserSettings(0, archive.key) + // fetch the archive meta and settings + const [meta, userSettings] = await Promise.all([ + archivesDb.getMeta(archive.key), + archivesDb.getUserSettings(0, archive.key) + ]) // fallback to default quota var bytesAllowed = userSettings.bytesAllowed || DAT_QUOTA_DEFAULT_BYTES_ALLOWED - // update the archive size - var size = await datLibrary.updateSizeTracking(archive) - // check the new size - var newSize = (size + byteLength) + var newSize = (meta.size + byteLength) if (newSize > bytesAllowed) { throw new QuotaExceededError() } From b9938634e09a30ee4c9c2f9aad9994896a051617 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 9 Aug 2019 20:05:57 -0500 Subject: [PATCH 16/74] Add network stats to archive getInfo --- dat/daemon.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dat/daemon.js b/dat/daemon.js index 7ceef4bb..09dc3bb7 100644 --- a/dat/daemon.js +++ b/dat/daemon.js @@ -92,12 +92,14 @@ exports.createDatArchiveSession = async function (opts) { }, async getInfo () { - // TODO pull from daemon + var stats = (await drive.stats())[0] return { version: 0, - size: 0, - peers: 0, - networkStats: {} + peers: stats.metadata.peers, + networkStats: { + uploadTotal: stats.metadata.uploadedBytes + stats.content.uploadedBytes, + downloadTotal: stats.metadata.downloadedBytes + stats.content.downloadedBytes, + } } }, From 33c0091f3d6449feed976c98f06498c941065ad3 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 16 Aug 2019 11:11:20 -0500 Subject: [PATCH 17/74] Bump hyperdrive-daemon@0.10 -client@0.11 --- package-lock.json | 476 ++++++++++++++++------------------------------ package.json | 4 +- 2 files changed, 165 insertions(+), 315 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2125553a..21845fbd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,9 +22,9 @@ } }, "@beaker/dat-serve-resolve-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@beaker/dat-serve-resolve-path/-/dat-serve-resolve-path-1.0.0.tgz", - "integrity": "sha512-ohW9nPTY9gft09Hss8V78Y4rzgYOkbESDjeIDm2KcJIIEEQzdvNFgbGWiPYyPRguYW5ppF7ZorM6huWRbo3bGA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@beaker/dat-serve-resolve-path/-/dat-serve-resolve-path-1.0.1.tgz", + "integrity": "sha512-75hhrzvmD9S98Rdr+EQ4nordixZDSEubG3ycijWs/PocLO8P0yXmaSgqegOGnAXZHHtef/cs1JqGDTebnUGmoA==", "requires": { "parse-dat-url": "^3.0.2" } @@ -109,9 +109,9 @@ "integrity": "sha512-6BmYWSBea18+tSjjSC3QIyV93ZKAeNWGM7R6aYt1ryTZXrlHF+QLV0G2yV0viEGVyRkyQsWfMoJ0k/YghBX5sQ==" }, "@types/node": { - "version": "12.7.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.1.tgz", - "integrity": "sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==", + "version": "12.7.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz", + "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==", "optional": true }, "abbrev": { @@ -120,10 +120,11 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "abstract-leveldown": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-5.0.0.tgz", - "integrity": "sha512-5mU5P1gXtsMIXg65/rsYGsi93+MlogXZ9FA8JnwKurHQg64bfXwGYVdVdijNTVNOlAsuIiOwHdvFFD5JqCJQ7A==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.0.3.tgz", + "integrity": "sha512-jzewKKpZbaYUa6HTThnrl+GrJhzjEAeuc7hTVpZdzg7kupXZFoqQDFwyOwLNbmJKJlmzw8yiipMPkDiuKkT06Q==", "requires": { + "level-concat-iterator": "~2.0.0", "xtend": "~4.0.0" } }, @@ -449,11 +450,6 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" }, - "bindings": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.1.tgz", - "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==" - }, "bitfield-rle": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/bitfield-rle/-/bitfield-rle-2.2.1.tgz", @@ -497,15 +493,6 @@ } } }, - "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, "blake2b": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.3.tgz", @@ -891,10 +878,18 @@ "run-series": "^1.1.2" } }, + "chrome-dns": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/chrome-dns/-/chrome-dns-1.0.1.tgz", + "integrity": "sha512-HqsYJgIc8ljJJOqOzLphjAs79EUuWSX3nzZi2LNkzlw3GIzAeZbaSektC8iT/tKvLqZq8yl1GJu5o6doA4TRbg==", + "requires": { + "chrome-net": "^3.3.2" + } + }, "chrome-net": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/chrome-net/-/chrome-net-3.3.2.tgz", - "integrity": "sha512-BHxWfA9MDnh0C1By5q1DnF1vRS7vfBi2PrqTHIIt1HA4hM6l2xkHzoazbDlZcrDrMfjNs6fojKG+ZD0JmlnNWg==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/chrome-net/-/chrome-net-3.3.3.tgz", + "integrity": "sha512-11jL8+Ogna8M5TEdyalE8IG6cpaFEU3YcaxAj3YjZKjRM/PeT70pZbrUY+xoGwqiEJZwJE4Td2CvGxUvS9ytKQ==", "requires": { "inherits": "^2.0.1" } @@ -1297,14 +1292,6 @@ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "requires": { - "mimic-response": "^1.0.0" - } - }, "deep-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", @@ -1322,11 +1309,11 @@ "dev": true }, "deferred-leveldown": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-4.0.2.tgz", - "integrity": "sha512-5fMC8ek8alH16QiV0lTCis610D1Zt1+LA4MS4d63JgS32lrCjTFDUFz2ao09/j2I4Bqb5jL4FZYwu7Jz0XO1ww==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.1.0.tgz", + "integrity": "sha512-PvDY+BT2ONu2XVRgxHb77hYelLtMYxKSGuWuJJdVRXh9ntqx9GYTFJno/SKAz5xcd+yjQwyQeIZrUPjPvA52mg==", "requires": { - "abstract-leveldown": "~5.0.0", + "abstract-leveldown": "~6.0.0", "inherits": "^2.0.3" } }, @@ -1604,15 +1591,14 @@ } }, "encoding-down": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-5.0.4.tgz", - "integrity": "sha512-8CIZLDcSKxgzT+zX8ZVfgNbu8Md2wq/iqa1Y7zyVR18QBEAc0Nmzuvj/N5ykSKpfGzjM8qxbaFntLPwnVoUhZw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-6.1.0.tgz", + "integrity": "sha512-pBW1mbuQDHQhQLBtqarX8x2oLynahiOzBY5L/BosNqcstJ8MjpSc3rx1yCUIqb6bUE2vsp3t0BaXS0ZDP1s5pg==", "requires": { - "abstract-leveldown": "^5.0.0", + "abstract-leveldown": "^6.0.0", "inherits": "^2.0.3", "level-codec": "^9.0.0", - "level-errors": "^2.0.0", - "xtend": "^4.0.1" + "level-errors": "^2.0.0" } }, "end-of-stream": { @@ -1783,9 +1769,9 @@ } }, "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, "espree": { @@ -1823,9 +1809,9 @@ } }, "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { @@ -1949,11 +1935,6 @@ } } }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" - }, "expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -2084,11 +2065,6 @@ "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.0.0.tgz", "integrity": "sha512-4VEXmjxLj7sbs8J//cn2qhRap50dGzF5n8fjay8mau+Jn4hxSeR3xPFwxMaQq/pDaq7+KQk0PAbC2+nWDkJrmQ==" }, - "fast-future": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fast-future/-/fast-future-1.0.2.tgz", - "integrity": "sha1-hDWpqqAteSSNF9cE52JZMB2ZKAo=" - }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -2249,6 +2225,17 @@ "graceful-fs": "^4.1.2", "rimraf": "~2.6.2", "write": "^0.2.1" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "flat-tree": { @@ -2388,11 +2375,6 @@ "readable-stream": "^2.0.0" } }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, "fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", @@ -3059,11 +3041,6 @@ "assert-plus": "^1.0.0" } }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" - }, "glob": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", @@ -3128,9 +3105,9 @@ "integrity": "sha512-tkz7SVwBktFbqFK3teXFUY/VM57+mbUgV9bSD+sZH1ocHJ7uk7BfEWMRdU24dd0ciUDokreA7ghH2fYFIczQdw==" }, "graceful-fs": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.1.tgz", - "integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==" + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==" }, "har-schema": { "version": "2.0.0", @@ -3315,9 +3292,9 @@ } }, "hyperdrive": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/hyperdrive/-/hyperdrive-10.0.2.tgz", - "integrity": "sha512-YwCIQxiwqytMhZJ/lI+yCIRjvrf9pjC0zhw7HxgcSFHapbsXSRMlqn6grdd84nJlXRwOSbgieSk3YfmxI2o70w==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/hyperdrive/-/hyperdrive-10.2.0.tgz", + "integrity": "sha512-BYma+omvGncNrmoMd9cL+lVykkQDKK4a1JWdb6mqLmPDYcms6UOIxvXKOntcy3bDeIvA4cBI269HTPQxFaSl0A==", "requires": { "byte-stream": "^2.1.0", "corestore": "^2.0.0", @@ -3326,7 +3303,7 @@ "filesystem-constants": "^1.0.0", "hypercore-byte-stream": "^1.0.2", "hyperdrive-schemas": "^0.9.0", - "mountable-hypertrie": "^0.10.0", + "mountable-hypertrie": "^0.11.0", "mutexify": "^1.2.0", "nanoiterator": "^1.2.0", "pump": "^3.0.0", @@ -3365,9 +3342,9 @@ } }, "hyperdrive-daemon": { - "version": "0.9.16", - "resolved": "https://registry.npmjs.org/hyperdrive-daemon/-/hyperdrive-daemon-0.9.16.tgz", - "integrity": "sha512-sXk/z9xwkWVQQUMcVzag2+h7evlKOWcACaY1sE9kstUeh8Ci5iemYetVJGw4Xbp9I1+KwP4faqO2PWgNP2ixSg==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/hyperdrive-daemon/-/hyperdrive-daemon-0.10.0.tgz", + "integrity": "sha512-KxMQk1w+a0zDJo3ho0eetSO1SqHBWtCrBebSUR3eYKzyv2AwTCbW3JNBdU4xThFIWwRqf3v59E60NzQF6WZHWg==", "requires": { "@grpc/grpc-js": "^0.5.1", "buffer-json-encoding": "^1.0.2", @@ -3380,10 +3357,10 @@ "forever-monitor": "^1.7.1", "fs-extra": "^7.0.1", "google-protobuf": "^3.8.0", - "hyperdrive": "^10.0.0-rc10", - "hyperdrive-daemon-client": "^0.10.1", + "hyperdrive": "^10.2.0", + "hyperdrive-daemon-client": "^0.11.0", "hyperdrive-fuse": "^1.1.0", - "level": "^4.0.0", + "level": "^5.0.0", "mkdirp": "^0.5.1", "pino": "^5.12.6", "prettier-bytes": "^1.0.4", @@ -3397,18 +3374,19 @@ } }, "hyperdrive-daemon-client": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/hyperdrive-daemon-client/-/hyperdrive-daemon-client-0.10.2.tgz", - "integrity": "sha512-u4DGsTmjKaGwRzvxgiDJsyA2EWEentyYOM0U/GjtOCt/sEbnKk8GGWuAKxigp09Av+WPa/BWJsCJJpZH8gMimg==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/hyperdrive-daemon-client/-/hyperdrive-daemon-client-0.11.0.tgz", + "integrity": "sha512-1eclEdPGN0a5JU9YpKWBIYf24nbnXJF/aYadxk/g3Eir/WVZTuak3WUqtFZlVyVK/VY2ps3TMkboxYkQa8tNdQ==", "requires": { "@grpc/grpc-js": "^0.5.1", "@mafintosh/streamx": "^1.1.0", "call-me-maybe": "^1.0.1", "chalk": "^2.4.2", + "codecs": "^2.0.0", "dat-encoding": "^5.0.1", "fs-extra": "^8.0.1", "google-protobuf": "^3.8.0", - "hyperdrive-schemas": "^0.9.0", + "hyperdrive-schemas": "^0.11.0", "pumpify": "^2.0.0", "stream-collector": "^1.0.1", "through2-map": "^3.0.0", @@ -3426,6 +3404,11 @@ "universalify": "^0.1.0" } }, + "hyperdrive-schemas": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/hyperdrive-schemas/-/hyperdrive-schemas-0.11.0.tgz", + "integrity": "sha512-7wmFXFl2gDc2PvgGlFacOTymiN4mjSbQHdKZUTIa4IrJJj6e0zma73Z4YBNPomR7xsgkjIsgnHsptWoGgq8TlA==" + }, "pumpify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.0.tgz", @@ -3566,6 +3549,11 @@ "minimatch": "^3.0.4" } }, + "immediate": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.2.3.tgz", + "integrity": "sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw=" + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -4010,12 +3998,13 @@ } }, "k-rpc-socket": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/k-rpc-socket/-/k-rpc-socket-1.10.0.tgz", - "integrity": "sha512-OLg7zaXeP2Zok/FZ9EfJX0bVFhUxQsgjKVMEGYfSl+hYP1M5+6pPsEiprDAllHLgvIjzE8qcIez44dKLETGe7Q==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/k-rpc-socket/-/k-rpc-socket-1.11.1.tgz", + "integrity": "sha512-8xtA8oqbZ6v1Niryp2/g4GxW16EQh5MvrUylQoOG+zcrDff5CKttON2XUXvMwlIHq4/2zfPVFiinAccJ+WhxoA==", "requires": { "bencode": "^2.0.0", "chrome-dgram": "^3.0.2", + "chrome-dns": "^1.0.0", "chrome-net": "^3.3.2" }, "dependencies": { @@ -4110,12 +4099,13 @@ } }, "level": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/level/-/level-4.0.0.tgz", - "integrity": "sha512-4epzCOlEcJ529NOdlAYiuiakS/kZTDdiKSBNJmE1B8bsmA+zEVwcpxyH86qJSQTpOu7SODrlaD9WgPRHLkGutA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/level/-/level-5.0.1.tgz", + "integrity": "sha512-wcak5OQeA4rURGacqS62R/xNHjCYnJSQDBOlm4KNUGJVE9bWv2B04TclqReYejN+oD65PzD4FsqeWoI5wNC5Lg==", "requires": { - "level-packager": "^3.0.0", - "leveldown": "^4.0.0", + "level-js": "^4.0.0", + "level-packager": "^5.0.0", + "leveldown": "^5.0.0", "opencollective-postinstall": "^2.0.0" } }, @@ -4138,13 +4128,37 @@ } }, "level-iterator-stream": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-3.0.1.tgz", - "integrity": "sha512-nEIQvxEED9yRThxvOrq8Aqziy4EGzrxSZK+QzEFAVuJvQ8glfyZ96GB6BoI4sBbLfjMXm2w4vu3Tkcm9obcY0g==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-4.0.1.tgz", + "integrity": "sha512-pSZWqXK6/yHQkZKCHrR59nKpU5iqorKM22C/BOHTb/cwNQ2EOZG+bovmFFGcOgaBoF3KxqJEI27YwewhJQTzsw==", "requires": { "inherits": "^2.0.1", - "readable-stream": "^2.3.6", + "readable-stream": "^3.0.2", "xtend": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "level-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-js/-/level-js-4.0.1.tgz", + "integrity": "sha512-m5JRIyHZn5VnCCFeRegJkn5bQd3MJK5qZX12zg3Oivc8+BUIS2yFS6ANMMeHX2ieGxucNvEn6/ZnyjmZQLLUWw==", + "requires": { + "abstract-leveldown": "~6.0.1", + "immediate": "~3.2.3", + "inherits": "^2.0.3", + "ltgt": "^2.1.2", + "typedarray-to-buffer": "~3.1.5" } }, "level-option-wrap": { @@ -4156,41 +4170,39 @@ } }, "level-packager": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-3.1.0.tgz", - "integrity": "sha512-UxVEfK5WH0u0InR3WxTCSAroiorAGKzXWZT6i+nBjambmvINuXFUsFx2Ai3UIjUUtnyWhluv42jMlzUZCsAk9A==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-5.0.2.tgz", + "integrity": "sha512-sJWdeW5tObvTvgP4Xf2psL5CEUsZjDjiTtlcimHp3Ifd4qbmkEGquN82C5ZtC7VpWEiISeUIBtIcCskVzEpvFw==", "requires": { - "encoding-down": "~5.0.0", - "levelup": "^3.0.0" + "encoding-down": "^6.0.0", + "levelup": "^4.0.0" } }, "leveldown": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-4.0.2.tgz", - "integrity": "sha512-SUgSRTWFh3eeiTdIt2a4Fi9TZO5oWzE9uC/Iw8+fVr1sk8x1S2l151UWwSmrMFZB3GxJhZIf4bQ0n+051Cctpw==", - "requires": { - "abstract-leveldown": "~5.0.0", - "bindings": "~1.3.0", - "fast-future": "~1.0.2", - "nan": "~2.12.1", - "prebuild-install": "~5.2.4" + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-5.1.1.tgz", + "integrity": "sha512-4n2R/vEA/sssh5TKtFwM9gshW2tirNoURLqekLRUUzuF+eUBLFAufO8UW7bz8lBbG2jw8tQDF3LC+LcUCc12kg==", + "requires": { + "abstract-leveldown": "~6.0.3", + "napi-macros": "~1.8.1", + "node-gyp-build": "~4.1.0" }, "dependencies": { - "nan": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", - "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + "node-gyp-build": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.0.tgz", + "integrity": "sha512-rGLv++nK20BG8gc0MzzcYe1Nl3p3mtwJ74Q2QD0HTEDKZ6NvOFSelY6s2QBPWIHRR8h7hpad0LiwajfClBJfNg==" } } }, "levelup": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-3.1.1.tgz", - "integrity": "sha512-9N10xRkUU4dShSRRFTBdNaBxofz+PGaIZO962ckboJZiNmLuhVT6FZ6ZKAsICKfUBO76ySaYU6fJWX/jnj3Lcg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-4.1.0.tgz", + "integrity": "sha512-+Qhe2/jb5affN7BeFgWUUWVdYoGXO2nFS3QLEZKZynnQyP9xqA+7wgOz3fD8SST2UKpHQuZgjyJjTcB2nMl2dQ==", "requires": { - "deferred-leveldown": "~4.0.0", + "deferred-leveldown": "~5.1.0", "level-errors": "~2.0.0", - "level-iterator-stream": "~3.0.0", + "level-iterator-stream": "~4.0.0", "xtend": "~4.0.0" } }, @@ -4331,6 +4343,11 @@ } } }, + "ltgt": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", + "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=" + }, "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", @@ -4456,11 +4473,6 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -4531,9 +4543,9 @@ "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" }, "mountable-hypertrie": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/mountable-hypertrie/-/mountable-hypertrie-0.10.4.tgz", - "integrity": "sha512-AXkSWSJPeZ7ar0xnrXe3mqX96dBZJxczKOK2nXUIj6JabowwcC/fbOVMaQTQ1MK6PWXKVMTwcgBdjQtDn4CJow==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/mountable-hypertrie/-/mountable-hypertrie-0.11.0.tgz", + "integrity": "sha512-3J4TrX+uxkMbeGnxIGhSBisSdi28LNqDLEVRH5g+1N4lqr79Vx627woq63NMoXWBEd+F9H1ItMWQqU80bmVtmg==", "requires": { "hypertrie": "^3.6.0", "is-options": "^1.0.1", @@ -4625,11 +4637,6 @@ "resolved": "https://registry.npmjs.org/nanoresource/-/nanoresource-1.2.0.tgz", "integrity": "sha512-6DJTce5okL9IQlVcswSsrLP4lQER52GkRMHAnkmHQNX1AqpT6VOE8y0MBartHJW3SV0ppC0wy0u4eAK3JARfpA==" }, - "napi-build-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz", - "integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==" - }, "napi-macros": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-1.8.2.tgz", @@ -4707,14 +4714,6 @@ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, - "node-abi": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.10.0.tgz", - "integrity": "sha512-OT0WepUvYHXdki6DU8LWhEkuo3M44i2paWBYtH9qXtPb9YiKlYEKa5WUII20XEcOv7UJPzfB0kZfPZdW46zdkw==", - "requires": { - "semver": "^5.4.1" - } - }, "node-gyp-build": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", @@ -4737,11 +4736,6 @@ "tar": "^4" } }, - "noop-logger": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" - }, "nopt": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", @@ -5134,7 +5128,7 @@ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" }, "pauls-dat-api2": { - "version": "github:beakerbrowser/pauls-dat-api2#656345bf9d6652d25592364a3d10186a8bd31ee8", + "version": "github:beakerbrowser/pauls-dat-api2#78fba10bf05abddca1270214a3e4827a9033452d", "from": "github:beakerbrowser/pauls-dat-api2", "requires": { "anymatch": "^1.3.2", @@ -5339,40 +5333,6 @@ } } }, - "prebuild-install": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.2.5.tgz", - "integrity": "sha512-6uZgMVg7yDfqlP5CPurVhtq3hUKBFNufiar4J5hZrlHTo59DDBEtyxw01xCdFss9j0Zb9+qzFVf/s4niayba3w==", - "requires": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.7.0", - "noop-logger": "^0.1.1", - "npmlog": "^4.0.1", - "os-homedir": "^1.0.1", - "pump": "^2.0.1", - "rc": "^1.2.7", - "simple-get": "^2.7.0", - "tar-fs": "^1.13.0", - "tunnel-agent": "^0.6.0", - "which-pm-runs": "^1.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -5832,9 +5792,9 @@ "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=" }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { "glob": "^7.1.3" } @@ -5897,17 +5857,17 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "scoped-fs": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/scoped-fs/-/scoped-fs-1.3.0.tgz", - "integrity": "sha512-aH9/73pyOAuO1x5YDf7kFogD7MMLsrADRtCcKHC7fD+o7IKwzpVxgbWB6YZyCIWxfTI/+TLCw/rHMcj3B4jXdQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/scoped-fs/-/scoped-fs-1.4.1.tgz", + "integrity": "sha512-7I9UC2eECQg1myIaDyL18j+05FjX11IkuEhkUZ0XzgJGYrkfQ1xxm6dKW0MGomGkaHMamf14uNTbNc+kvuqEFA==", "requires": { "recursive-watch": "^1.1.1" } }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "set-blocking": { "version": "2.0.0", @@ -5985,21 +5945,6 @@ "varint": "~5.0.0" } }, - "simple-concat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", - "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" - }, - "simple-get": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", - "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", - "requires": { - "decompress-response": "^3.3.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "simple-sha1": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/simple-sha1/-/simple-sha1-2.1.2.tgz", @@ -6147,9 +6092,9 @@ } }, "sodium-native": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-2.4.5.tgz", - "integrity": "sha512-G1uhd4l1OexzUC/6eHIbAvoivCs9T7ncDlEWodZglPZVUOXi6jtSe7tCi25aYB06zRoOjVfE4SL+hZ4EfkyZgw==", + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-2.4.6.tgz", + "integrity": "sha512-Ro9lhTjot8M01nwKLXiqLSmjR7B8o+Wg4HmJUjEShw/q6XPlNMzjPkA1VJKaMH8SO8fJ/sggAKVwreTaFszS2Q==", "optional": true, "requires": { "ini": "^1.3.5", @@ -6404,68 +6349,6 @@ "inherits": "^2.0.3", "level-option-wrap": "^1.1.0", "levelup": "^4.0.1" - }, - "dependencies": { - "abstract-leveldown": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.0.3.tgz", - "integrity": "sha512-jzewKKpZbaYUa6HTThnrl+GrJhzjEAeuc7hTVpZdzg7kupXZFoqQDFwyOwLNbmJKJlmzw8yiipMPkDiuKkT06Q==", - "requires": { - "level-concat-iterator": "~2.0.0", - "xtend": "~4.0.0" - } - }, - "deferred-leveldown": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.1.0.tgz", - "integrity": "sha512-PvDY+BT2ONu2XVRgxHb77hYelLtMYxKSGuWuJJdVRXh9ntqx9GYTFJno/SKAz5xcd+yjQwyQeIZrUPjPvA52mg==", - "requires": { - "abstract-leveldown": "~6.0.0", - "inherits": "^2.0.3" - } - }, - "encoding-down": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-6.1.0.tgz", - "integrity": "sha512-pBW1mbuQDHQhQLBtqarX8x2oLynahiOzBY5L/BosNqcstJ8MjpSc3rx1yCUIqb6bUE2vsp3t0BaXS0ZDP1s5pg==", - "requires": { - "abstract-leveldown": "^6.0.0", - "inherits": "^2.0.3", - "level-codec": "^9.0.0", - "level-errors": "^2.0.0" - } - }, - "level-iterator-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-4.0.1.tgz", - "integrity": "sha512-pSZWqXK6/yHQkZKCHrR59nKpU5iqorKM22C/BOHTb/cwNQ2EOZG+bovmFFGcOgaBoF3KxqJEI27YwewhJQTzsw==", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^3.0.2", - "xtend": "^4.0.0" - } - }, - "levelup": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-4.1.0.tgz", - "integrity": "sha512-+Qhe2/jb5affN7BeFgWUUWVdYoGXO2nFS3QLEZKZynnQyP9xqA+7wgOz3fD8SST2UKpHQuZgjyJjTcB2nMl2dQ==", - "requires": { - "deferred-leveldown": "~5.1.0", - "level-errors": "~2.0.0", - "level-iterator-stream": "~4.0.0", - "xtend": "~4.0.0" - } - }, - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } } }, "supports-color": { @@ -6580,42 +6463,6 @@ "yallist": "^3.0.3" } }, - "tar-fs": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", - "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", - "requires": { - "chownr": "^1.0.1", - "mkdirp": "^0.5.1", - "pump": "^1.0.0", - "tar-stream": "^1.1.2" - }, - "dependencies": { - "pump": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", - "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, - "tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" - } - }, "tarn": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.5.tgz", @@ -6820,6 +6667,14 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -7027,11 +6882,6 @@ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, - "which-pm-runs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", - "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=" - }, "wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", diff --git a/package.json b/package.json index 24029172..4aa71f72 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,8 @@ "fs-jetpack": "^1.3.1", "fs-reverse": "0.0.3", "function-queue": "0.0.12", - "hyperdrive-daemon": "^0.9.16", - "hyperdrive-daemon-client": "^0.10.1", + "hyperdrive-daemon": "^0.10.0", + "hyperdrive-daemon-client": "^0.11.0", "hyperdrive-network-speed": "^2.1.0", "icojs": "^0.12.3", "identify-filetype": "^1.0.0", From d27545722d78179436865b5f12bf9775a9a3bec0 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 16 Aug 2019 11:11:31 -0500 Subject: [PATCH 18/74] Add version to archive getInfo() --- dat/daemon.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dat/daemon.js b/dat/daemon.js index 09dc3bb7..8fed0d8e 100644 --- a/dat/daemon.js +++ b/dat/daemon.js @@ -92,13 +92,16 @@ exports.createDatArchiveSession = async function (opts) { }, async getInfo () { - var stats = (await drive.stats())[0] + var [version, stats] = await Promise.all([ + drive.version(), + drive.stats() + ]) return { - version: 0, - peers: stats.metadata.peers, + version, + peers: stats[0].metadata.peers, networkStats: { - uploadTotal: stats.metadata.uploadedBytes + stats.content.uploadedBytes, - downloadTotal: stats.metadata.downloadedBytes + stats.content.downloadedBytes, + uploadTotal: stats[0].metadata.uploadedBytes + stats[0].content.uploadedBytes, + downloadTotal: stats[0].metadata.downloadedBytes + stats[0].content.downloadedBytes, } } }, From 68766f2e31b4c314f46ce3be25a2766db9b90038 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 16 Aug 2019 11:48:51 -0500 Subject: [PATCH 19/74] Update crawler to use createDiffStream() --- crawler/util.js | 16 +++++++++------- dat/daemon.js | 3 +++ dat/library.js | 7 ++++--- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/crawler/util.js b/crawler/util.js index 182cf845..8c893057 100644 --- a/crawler/util.js +++ b/crawler/util.js @@ -57,15 +57,17 @@ exports.doCrawl = async function (archive, crawlSource, crawlDataset, crawlDatas var version = archiveInfo ? archiveInfo.version : 0 // fetch change log + var changes var start = state.crawlSourceVersion + 1 var end = version + 1 - var changes = await new Promise((resolve, reject) => { - pump( - archive.history({start, end, timeout: READ_TIMEOUT}), - concat({encoding: 'object'}, resolve), - reject - ) - }) + if (start === end) { + changes = [] + } else { + let stream = await archive.session.drive.createDiffStream(start, '/') + changes = await new Promise((resolve, reject) => { + pump(stream, concat({encoding: 'object'}, resolve), reject) + }) + } crawlerEvents.emit('crawl-dataset-start', {sourceUrl: archive.url, crawlDataset, crawlRange: {start, end}}) diff --git a/dat/daemon.js b/dat/daemon.js index 8fed0d8e..a343dde5 100644 --- a/dat/daemon.js +++ b/dat/daemon.js @@ -16,6 +16,7 @@ const pda = require('pauls-dat-api2') * @prop {string} domain * @prop {boolean} writable * @prop {Object} session +* @prop {Object} session.drive * @prop {function(): Promise} session.close * @prop {function(): Promise} session.publish * @prop {function(): Promise} session.unpublish @@ -68,6 +69,7 @@ exports.setup = async function () { * @param {Buffer} opts.key * @param {number} [opts.version] * @param {Buffer} [opts.hash] + * @param {boolean} [opts.writable] * @returns {Promise} */ exports.createDatArchiveSession = async function (opts) { @@ -80,6 +82,7 @@ exports.createDatArchiveSession = async function (opts) { domain: undefined, session: { + drive, async close () { return drive.close() }, diff --git a/dat/library.js b/dat/library.js index caa96570..c1cc5dbc 100644 --- a/dat/library.js +++ b/dat/library.js @@ -411,7 +411,7 @@ exports.getArchiveCheckout = async function getArchiveCheckout (archive, version var isHistoric = false var isPreview = false var checkoutFS = archive - if (version) { + if (typeof version !== 'undefined') { let seq = parseInt(version) if (Number.isNaN(seq)) { if (version === 'latest') { @@ -427,9 +427,10 @@ exports.getArchiveCheckout = async function getArchiveCheckout (archive, version } else { let checkoutKey = `${archive.key}+${version}` if (!(checkoutKey in archiveSessionCheckouts)) { - archiveSessionCheckouts[checkoutKey] = daemon.createDatArchiveSession({ + archiveSessionCheckouts[checkoutKey] = await daemon.createDatArchiveSession({ key: archive.key, - version + version, + writable: false }) } checkoutFS = archiveSessionCheckouts[checkoutKey] From a3fa6378277f29d0b476b9655f23c4d732892e65 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 16 Aug 2019 12:31:47 -0500 Subject: [PATCH 20/74] Disable media and discussions crawl --- crawler/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crawler/index.js b/crawler/index.js index dc697119..1b714082 100644 --- a/crawler/index.js +++ b/crawler/index.js @@ -118,9 +118,9 @@ exports.crawlSite = async function (archive) { await Promise.all([ bookmarks.crawlSite(archive, crawlSource), comments.crawlSite(archive, crawlSource), - discussions.crawlSite(archive, crawlSource), + // discussions.crawlSite(archive, crawlSource), follows.crawlSite(archive, crawlSource), - media.crawlSite(archive, crawlSource), + // media.crawlSite(archive, crawlSource), posts.crawlSite(archive, crawlSource), reactions.crawlSite(archive, crawlSource), siteDescriptions.crawlSite(archive, crawlSource), From 76a9f1d978b5752d65ddf63a0f213406b9e61ffc Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 16 Aug 2019 12:32:12 -0500 Subject: [PATCH 21/74] Temporary workaround for missing .version on createDiffStream --- crawler/util.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/crawler/util.js b/crawler/util.js index 8c893057..d25265b4 100644 --- a/crawler/util.js +++ b/crawler/util.js @@ -69,6 +69,13 @@ exports.doCrawl = async function (archive, crawlSource, crawlDataset, crawlDatas }) } + // TEMPORARY + // createDiffStream() doesnt include a .version + // we need an accurate version to checkpoint progress + // for now, use the earliest version + // -prf + changes.forEach(c => { c.version = version }) + crawlerEvents.emit('crawl-dataset-start', {sourceUrl: archive.url, crawlDataset, crawlRange: {start, end}}) // handle changes @@ -115,14 +122,9 @@ exports.emitProgressEvent = function (sourceUrl, crawlDataset, progress, numUpda * @returns {Array} */ exports.getMatchingChangesInOrder = function (changes, regex) { - var list = [] // order matters, must be oldest to newest - changes.forEach(c => { - if (regex.test(c.name)) { - let i = list.findIndex(c2 => c2.name === c.name) - if (i !== -1) list.splice(i, 1) // remove from old position - list.push(c) - } - }) + var list = [] + list = changes.filter(c => regex.test(c.name)) + list.sort((a, b) => a.version - b.version) // order matters, must be oldest to newest return list } From 7248d02ef960c616dd212abbd321e067901e3b9f Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 16 Aug 2019 12:32:30 -0500 Subject: [PATCH 22/74] Fix getArchiveCheckout with no version --- dat/library.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dat/library.js b/dat/library.js index c1cc5dbc..50aba850 100644 --- a/dat/library.js +++ b/dat/library.js @@ -411,7 +411,7 @@ exports.getArchiveCheckout = async function getArchiveCheckout (archive, version var isHistoric = false var isPreview = false var checkoutFS = archive - if (typeof version !== 'undefined') { + if (typeof version !== 'undefined' && version !== null) { let seq = parseInt(version) if (Number.isNaN(seq)) { if (version === 'latest') { From 2a69121f5066d8d581e79d7d3120f0306c744c02 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 16 Aug 2019 12:32:39 -0500 Subject: [PATCH 23/74] Avoid noisy log output --- users/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/users/index.js b/users/index.js index 49606951..4606d0b1 100644 --- a/users/index.js +++ b/users/index.js @@ -64,7 +64,7 @@ exports.setup = async function () { // old temporary? if (user.isTemporary) { // delete old temporary user - logger.info('Deleting temporary user', {details: user}) + logger.info('Deleting temporary user', {details: user.url}) user.isInvalid = true // let invalid-user-deletion clean up the record let key = dat.library.fromURLToKey(user.url) await archivesDb.setUserSettings(0, key, {isSaved: false}) @@ -77,7 +77,7 @@ exports.setup = async function () { user.archive = null user.isDefault = Boolean(user.isDefault) user.createdAt = new Date(user.createdAt) - logger.info('Loading user', {details: user}) + logger.info('Loading user', {details: user.url}) // validate try { @@ -237,7 +237,7 @@ exports.add = async function (label, url, setDefault = false, isTemporary = fals isTemporary, createdAt: new Date() } - logger.verbose('Adding user', {details: user}) + logger.verbose('Adding user', {details: user.url}) await db.run( `INSERT INTO users (label, url, isDefault, isTemporary, createdAt) VALUES (?, ?, ?, ?, ?)`, [user.label, user.url, Number(user.isDefault), Number(user.isTemporary), Number(user.createdAt)] @@ -286,7 +286,7 @@ exports.edit = async function (url, opts) { user.label = opts.label await db.run(`UPDATE users SET label = ? WHERE url = ?`, [opts.label, user.url]) } - logger.verbose('Updating user', {details: user}) + logger.verbose('Updating user', {details: user.url}) // fetch the user archive user.archive = await dat.library.getOrLoadArchive(user.url) @@ -305,7 +305,7 @@ exports.remove = async function (url) { if (!user) return // remove the user - logger.verbose('Removing user', {details: user}) + logger.verbose('Removing user', {details: user.url}) users.splice(users.indexOf(user), 1) await db.run(`DELETE FROM users WHERE url = ?`, [user.url]) /* dont await */crawler.unwatchSite(user.archive) From 3a8165415af7f2c76d4cff72da62c3032dcf8c3e Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 16 Aug 2019 12:48:09 -0500 Subject: [PATCH 24/74] Crawler fixes --- crawler/util.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crawler/util.js b/crawler/util.js index d25265b4..4d0a4b12 100644 --- a/crawler/util.js +++ b/crawler/util.js @@ -58,8 +58,8 @@ exports.doCrawl = async function (archive, crawlSource, crawlDataset, crawlDatas // fetch change log var changes - var start = state.crawlSourceVersion + 1 - var end = version + 1 + var start = state.crawlSourceVersion + var end = version if (start === end) { changes = [] } else { @@ -68,13 +68,19 @@ exports.doCrawl = async function (archive, crawlSource, crawlDataset, crawlDatas pump(stream, concat({encoding: 'object'}, resolve), reject) }) } + + changes.forEach(c => { + if (!c.name.startsWith('/')) { + c.name = '/' + c.name + } - // TEMPORARY - // createDiffStream() doesnt include a .version - // we need an accurate version to checkpoint progress - // for now, use the earliest version - // -prf - changes.forEach(c => { c.version = version }) + // TEMPORARY + // createDiffStream() doesnt include a .version + // we need an accurate version to checkpoint progress + // for now, use the earliest version + // -prf + c.version = version + }) crawlerEvents.emit('crawl-dataset-start', {sourceUrl: archive.url, crawlDataset, crawlRange: {start, end}}) From 22c5b4832183f0c89aa80766762930a6dd9c0654 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 16 Aug 2019 17:49:40 -0500 Subject: [PATCH 25/74] Gracefully handle timeouts when connecting to the daemon --- dat/daemon.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dat/daemon.js b/dat/daemon.js index a343dde5..057e8afb 100644 --- a/dat/daemon.js +++ b/dat/daemon.js @@ -5,6 +5,8 @@ const { HyperdriveClient } = require('hyperdrive-daemon-client') const datEncoding = require('dat-encoding') const pda = require('pauls-dat-api2') +const SETUP_RETRIES = 10 + // typedefs // = @@ -58,8 +60,14 @@ exports.setup = async function () { await daemon.start() process.on('exit', () => daemon.stop()) - client = new HyperdriveClient() - await client.ready() + for (let i = 0; i < SETUP_RETRIES; i++) { + try { + client = new HyperdriveClient() + await client.ready() + } catch (e) { + console.log('Failed to connect to daemon, retrying', e) + } + } } /** From f42f18e142cec10389192a2c595e7b73c6384309 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 16 Aug 2019 17:50:24 -0500 Subject: [PATCH 26/74] Fixes and updates to preview-mode and folder-sync --- dat/folder-sync.js | 74 ++++++++++++++++++++++++---------------------- dat/library.js | 21 ++++++++----- lib/scoped-fses.js | 1 + package-lock.json | 41 +++++++++++++++++++++---- package.json | 2 +- 5 files changed, 90 insertions(+), 49 deletions(-) diff --git a/dat/folder-sync.js b/dat/folder-sync.js index d7abda29..b5e60a56 100644 --- a/dat/folder-sync.js +++ b/dat/folder-sync.js @@ -39,8 +39,8 @@ var datPath = '' var disallowedSavePaths = [] var localSyncSettings = {} // key -> settings object var syncEventQueues = {} // key -> queue object -var stopWatchingLocalFolderFns = {} // key -> function -var stopWatchingDatIgnoreFns = {} // key -> function +var watchingLocalFolderStreams = {} // key -> function +var watchingDatIgnoreFnsStreams = {} // key -> function var compareContentCaches = {} // key -> object var datIgnoreRules = {} // key -> object var syncCallCounts = {} // key -> number @@ -58,7 +58,7 @@ exports.setup = function (opts) { exports.reconfigureArchive = function (archive, userSettings) { var oldLocalSyncSettings = localSyncSettings[archive.key] - localSyncSettings[archive.key] = getLocalSyncSettings(archive, userSettings) + localSyncSettings[archive.key] = createLocalSyncSettings(archive, userSettings) if (!isEqual(localSyncSettings[archive.key], oldLocalSyncSettings)) { // configure the local folder watcher if a change occurred @@ -71,6 +71,10 @@ exports.reconfigureArchive = function (archive, userSettings) { } } +exports.getLocalSyncSettings = function (archive) { + return localSyncSettings[archive.key] +} + /** * @desc Sync dat to the folder * @param {DaemonDatArchive} archive @@ -162,11 +166,11 @@ const queueSyncEvent = exports.queueSyncEvent = function (archive, {toFolder, to logger.silly('Ok timed out, beginning sync', {details: {toArchive, toFolder}}) try { - let st = await stat(fs, localSyncPath) + let st = await jetpack.existsAsync(localSyncPath) if (!st) { // folder has been removed - stopWatchingLocalFolderFns[archive.key]() - stopWatchingLocalFolderFns[archive.key] = null + watchingLocalFolderStreams[archive.key].destroy() + watchingLocalFolderStreams[archive.key] = null logger.warn('Local sync folder not found, aborting watch', {details: {path: localSyncPath}}) return } @@ -210,18 +214,18 @@ const configureFolderToArchiveWatcher = exports.configureFolderToArchiveWatcher // teardown the existing watch (his watch has ended) // = - if (stopWatchingLocalFolderFns[archive.key]) { + if (watchingLocalFolderStreams[archive.key]) { // stop watching - stopWatchingLocalFolderFns[archive.key]() - stopWatchingLocalFolderFns[archive.key] = null + watchingLocalFolderStreams[archive.key].destroy() + watchingLocalFolderStreams[archive.key] = null if (syncEventQueues[archive.key] && syncEventQueues[archive.key].timeout) { clearTimeout(syncEventQueues[archive.key].timeout) syncEventQueues[archive.key] = null } } - if (stopWatchingDatIgnoreFns[archive.key]) { - stopWatchingDatIgnoreFns[archive.key]() - stopWatchingDatIgnoreFns[archive.key] = null + if (watchingDatIgnoreFnsStreams[archive.key]) { + watchingDatIgnoreFnsStreams[archive.key].destroy() + watchingDatIgnoreFnsStreams[archive.key] = null } // start a new watch @@ -239,16 +243,16 @@ const configureFolderToArchiveWatcher = exports.configureFolderToArchiveWatcher } // make sure the folder exists - let st = await stat(fs, localSyncSettings[archive.key].path) + let exists = await jetpack.exists(localSyncSettings[archive.key].path) if (shouldAbort()) return - if (!st) { + if (!exists) { logger.warn('Local sync folder not found, aborting watch', {details: {path: localSyncSettings[archive.key].path}}) } var scopedFS = scopedFSes.get(localSyncSettings[archive.key].path) // track datignore rules readDatIgnore(scopedFS).then(rules => { datIgnoreRules[archive.key] = rules }) - stopWatchingDatIgnoreFns[archive.key] = scopedFS.watch('/.datignore', async () => { + watchingDatIgnoreFnsStreams[archive.key] = scopedFS.pda.watch('/.datignore', async () => { datIgnoreRules[archive.key] = await readDatIgnore(scopedFS) }) @@ -267,7 +271,7 @@ const configureFolderToArchiveWatcher = exports.configureFolderToArchiveWatcher if (shouldAbort()) return // start watching - stopWatchingLocalFolderFns[archive.key] = scopedFS.watch('/', path => { + watchingLocalFolderStreams[archive.key] = scopedFS.pda.watch('/', path => { // TODO // it would be possible to make this more efficient by ignoring changes that match .datignore // but you need to make sure you have the latest .datignore and reading that on every change-event isnt efficient @@ -317,7 +321,7 @@ exports.diffListing = async function (archive, opts = {}) { // run diff newOpts.compareContentCache = compareContentCaches[archive.key] - return dft.diff({fs: scopedFS}, {fs: archive}, newOpts) + return dft.diff({fs: scopedFS.pda}, {fs: archive.pda}, newOpts) } /** @@ -377,15 +381,13 @@ exports.assertSafePath = async function (p) { } // stat the folder - const stat = await new Promise(resolve => { - fs.stat(p, (_, st) => resolve(st)) - }) + const info = await jetpack.inspect(p) - if (!stat) { + if (!info) { throw new NotFoundError() } - if (!stat.isDirectory()) { + if (info.type !== 'dir') { throw new NotAFolderError('Invalid target folder: not a folder') } } @@ -474,8 +476,8 @@ async function sync (archive, toArchive, opts = {}) { } // choose direction - var left = toArchive ? {fs: scopedFS} : {fs: archive} - var right = toArchive ? {fs: archive} : {fs: scopedFS} + var left = toArchive ? {fs: scopedFS.pda} : {fs: archive.pda} + var right = toArchive ? {fs: archive.pda} : {fs: scopedFS.pda} // run diff diffOpts.compareContentCache = compareContentCaches[archive.key] @@ -560,7 +562,7 @@ function getInternalLocalSyncPath (archiveOrKey) { * @param {Object} userSettings * @returns {Object} */ -function getLocalSyncSettings (archive, userSettings) { +function createLocalSyncSettings (archive, userSettings) { if (!archive.writable || !userSettings.isSaved) { return false } @@ -582,20 +584,22 @@ function getLocalSyncSettings (archive, userSettings) { // helper to read a file via promise and return a null on fail async function stat (fs, filepath) { - return new Promise(resolve => { - fs.stat(filepath, (_, data) => { - resolve(data || null) - }) - }) + try { + return await fs.pda.stat(filepath) + } catch (e) { + return null + } } // helper to read a file via promise and return an empty string on fail async function readFile (fs, filepath) { - return new Promise(resolve => { - fs.readFile(filepath, {encoding: 'utf8'}, (_, data) => { - resolve(data || '') - }) - }) + var data + try { + data = await fs.pda.readFile(filepath, {encoding: 'utf8'}) + } catch (e) { + // ignore + } + return data || '' } // helper to go from '/foo/bar/baz' to ['/', '/foo', '/foo/bar', '/foo/bar/baz'] diff --git a/dat/library.js b/dat/library.js index 50aba850..9bab8a8e 100644 --- a/dat/library.js +++ b/dat/library.js @@ -46,7 +46,6 @@ const {InvalidURLError, TimeoutError} = require('beaker-error-constants') var archives = {} // in-memory cache of archive objects. key -> archive var archiveLoadPromises = {} // key -> promise var archiveSessionCheckouts = {} // key+version -> DaemonDatArchive -var localSyncSettings = {} // key -> object var archivesEvents = new EventEmitter() // var daemonEvents TODO @@ -385,9 +384,10 @@ async function loadArchiveInner (key, userSettings = null) { archive.pullLatestArchiveMeta({updateMTime: true}) datAssets.update(archive, [path]) - if (archive.localSyncSettings) { + let localSyncSettings = folderSync.getLocalSyncSettings(archive) + if (localSyncSettings) { // need to sync this change to the local folder - if (archive.localSyncSettings.autoPublish) { + if (localSyncSettings.autoPublish) { // bidirectional sync: use the sync queue folderSync.queueSyncEvent(archive, {toFolder: true}) } else { @@ -417,10 +417,17 @@ exports.getArchiveCheckout = async function getArchiveCheckout (archive, version if (version === 'latest') { // ignore, we use latest by default } else if (version === 'preview') { - isPreview = true - checkoutFS = scopedFSes.get(localSyncSettings[archive.key].path) - checkoutFS.setFilter(p => folderSync.applyDatIgnoreFilter(archive, p)) - checkoutFS.domain = archive.domain + let localSyncSettings = folderSync.getLocalSyncSettings(archive) + if (localSyncSettings) { + isPreview = true + checkoutFS = scopedFSes.get(localSyncSettings.path) + checkoutFS.setFilter(p => folderSync.applyDatIgnoreFilter(archive, p)) + checkoutFS.domain = archive.domain + } else { + var err = new Error('Preview mode is not active') + err.noPreviewMode = true + throw err + } } else { throw new Error('Invalid version identifier:' + version) } diff --git a/lib/scoped-fses.js b/lib/scoped-fses.js index f7bad900..fbe0ba94 100644 --- a/lib/scoped-fses.js +++ b/lib/scoped-fses.js @@ -1,4 +1,5 @@ const ScopedFS = require('scoped-fs') +const pda = require('pauls-dat-api2') // typedefs // = diff --git a/package-lock.json b/package-lock.json index 21845fbd..91832493 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1420,9 +1420,9 @@ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, "diff-file-tree": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/diff-file-tree/-/diff-file-tree-2.2.0.tgz", - "integrity": "sha512-2vvgzQLCQGNnc6WRVHhvn2L+C5/Lam7DYgY/vPfuXno3OpNhcuhZf+B86zptQm8yEzxthzmdslIO08wodMB5Bw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/diff-file-tree/-/diff-file-tree-2.3.2.tgz", + "integrity": "sha512-tyyLkFV2AvADPey2kP0FoqLKja9rv6cR2ywzxqfAoFf3n9i7zbuxUzvG2lYO0K6x8NGkV2VtxoU+FQGWNGwCtw==", "requires": { "debug": "^2.6.4", "es6-promisify": "^5.0.0", @@ -5128,17 +5128,18 @@ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" }, "pauls-dat-api2": { - "version": "github:beakerbrowser/pauls-dat-api2#78fba10bf05abddca1270214a3e4827a9033452d", + "version": "github:beakerbrowser/pauls-dat-api2#08d7cf19b80b93c482b0d66acd30c308b192bab8", "from": "github:beakerbrowser/pauls-dat-api2", "requires": { "anymatch": "^1.3.2", "beaker-error-constants": "^1.4.0", "call-me-maybe": "^1.0.1", "dat-encoding": "^4.0.2", - "diff-file-tree": "^2.1.1", + "diff-file-tree": "^2.3.0", "emit-stream": "^0.1.2", "fs-extra": "^4.0.3", - "pump": "^1.0.3" + "pump": "^1.0.3", + "streamx": "^2.0.1" }, "dependencies": { "anymatch": { @@ -5181,6 +5182,18 @@ "safe-buffer": "^5.0.1" } }, + "diff-file-tree": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/diff-file-tree/-/diff-file-tree-2.3.0.tgz", + "integrity": "sha512-eYXf5lqzlqE5pX3kZ1Kz4Z4li0d1VUOmspP0ufi9X++ibcj7TqJRPDL0P7sQXSxlZXKM1/raItbQOKGSzxbaCw==", + "requires": { + "debug": "^2.6.4", + "es6-promisify": "^5.0.0", + "pump": "^1.0.2", + "stream-equal": "^1.0.0", + "tempy": "^0.1.0" + } + }, "expand-brackets": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", @@ -6296,6 +6309,22 @@ "limiter": "^1.0.5" } }, + "streamx": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.0.1.tgz", + "integrity": "sha512-Uk9zwYbJogP6o6wNHIvXRoHWGEmOhSMNz3b8HruZh2SkjRKP75UVOZu0/SjEeYIqWE5WHj6ns3jc7Ao457+Iug==", + "requires": { + "fast-fifo": "^1.0.0", + "nanoassert": "^2.0.0" + }, + "dependencies": { + "nanoassert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz", + "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==" + } + } + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", diff --git a/package.json b/package.json index 4aa71f72..8c09bde4 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "dat-encoding": "^5.0.1", "datland-swarm-defaults": "^1.0.2", "diff": "^3.5.0", - "diff-file-tree": "^2.2.0", + "diff-file-tree": "^2.3.2", "discovery-swarm": "^6.0.0", "emit-stream": "^0.1.2", "emoji-regex": "^8.0.0", From f2cb9286038f95d77a89c198490f4f4c040b515c Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Mon, 19 Aug 2019 10:46:21 -0500 Subject: [PATCH 27/74] Fix usage of PDA2 methods that are not attached to the archive object --- dat/library.js | 4 ++-- web-apis/bg/dat-archive.js | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dat/library.js b/dat/library.js index 9bab8a8e..88409498 100644 --- a/dat/library.js +++ b/dat/library.js @@ -285,8 +285,8 @@ exports.forkArchive = async function forkArchive (srcArchiveUrl, manifest = {}, // copy files var ignore = ['/.dat', '/.git', '/dat.json'] await pda.exportArchiveToArchive({ - srcArchive, - dstArchive, + srcArchive: srcArchive.session.drive, + dstArchive: dstArchive.session.drive, skipUndownloadedFiles: true, ignore }) diff --git a/web-apis/bg/dat-archive.js b/web-apis/bg/dat-archive.js index 398bf8f7..1b2bb6ce 100644 --- a/web-apis/bg/dat-archive.js +++ b/web-apis/bg/dat-archive.js @@ -77,7 +77,7 @@ module.exports = { let templatePath = path.join(globals.templatesPath, template) await pda.exportFilesystemToArchive({ srcPath: templatePath, - dstArchive: archive, + dstArchive: archive.session.drive, dstPath: '/', inplaceImport: true }) @@ -550,7 +550,7 @@ module.exports = { if (isHistoric) throw new ArchiveNotWritableError('Cannot modify a historic version') return pda.exportFilesystemToArchive({ srcPath: opts.src, - dstArchive: checkoutFS, + dstArchive: checkoutFS.session ? checkoutFS.session.drive : checkoutFS, dstPath: filepath, ignore: opts.ignore, inplaceImport: opts.inplaceImport !== false, @@ -568,7 +568,7 @@ module.exports = { var {checkoutFS, filepath} = await lookupArchive(this.sender, opts.src, opts) return pda.exportArchiveToFilesystem({ - srcArchive: checkoutFS, + srcArchive: checkoutFS.session ? checkoutFS.session.drive : checkoutFS, srcPath: filepath, dstPath: opts.dst, ignore: opts.ignore, @@ -583,9 +583,9 @@ module.exports = { var dst = await lookupArchive(this.sender, opts.dst, opts) if (dst.isHistoric) throw new ArchiveNotWritableError('Cannot modify a historic version') return pda.exportArchiveToArchive({ - srcArchive: src.checkoutFS, + srcArchive: src.checkoutFS.session ? src.checkoutFS.session.drive : src.checkoutFS, srcPath: src.filepath, - dstArchive: dst.checkoutFS, + dstArchive: dst.checkoutFS.session ? dst.checkoutFS.session.drive : dst.checkoutFS, dstPath: dst.filepath, ignore: opts.ignore, skipUndownloadedFiles: opts.skipUndownloadedFiles !== false From c2153bb50a5cedbfb46c99853190a38c61743624 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Mon, 19 Aug 2019 10:55:09 -0500 Subject: [PATCH 28/74] Switch back to using createReadStream() to serve dat:// assets --- dat/protocol.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/dat/protocol.js b/dat/protocol.js index 9b050475..196d96d0 100644 --- a/dat/protocol.js +++ b/dat/protocol.js @@ -320,18 +320,8 @@ ${html}` }) } - // TODO - // replace this with createReadStream when that method is available - var content = await checkoutFS.pda.readFile(entry.path) - Object.assign(headers, { - 'Content-Type': mime.identify(entry.path) - }) - respond({statusCode, headers, data: intoStream(content)}) - cleanup() - return - // fetch the entry and stream the response - fileReadStream = checkoutFS.createReadStream(entry.path, range) + fileReadStream = await checkoutFS.pda.createReadStream(entry.path, range) var dataStream = fileReadStream .pipe(mime.identifyStream(entry.path, mimeType => { // cleanup the timeout now, as bytes have begun to stream From 990f955d3d5a540859f560be8873b9bb5e62dad1 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Mon, 19 Aug 2019 14:46:05 -0500 Subject: [PATCH 29/74] Add users/filesystem.js and root-archive management --- dat/library.js | 8 ++- users/filesystem.js | 152 ++++++++++++++++++++++++++++++++++++++++++++ users/index.js | 29 ++++++--- 3 files changed, 180 insertions(+), 9 deletions(-) create mode 100644 users/filesystem.js diff --git a/dat/library.js b/dat/library.js index 88409498..aefede84 100644 --- a/dat/library.js +++ b/dat/library.js @@ -214,6 +214,10 @@ const pullLatestArchiveMeta = exports.pullLatestArchiveMeta = async function pul // archive creation // = +/** + * @param {Object} [manifest] + * @param {Object|boolean} [settings] + */ const createNewArchive = exports.createNewArchive = async function createNewArchive (manifest = {}, settings = false) { var userSettings = { isSaved: !(settings && settings.isSaved === false), @@ -363,7 +367,9 @@ async function loadArchiveInner (key, userSettings = null) { key = archive.key // put the archive on the network - archive.session.publish() + if (userSettings.networked) { + archive.session.publish() + } // fetch dns name if known let dnsRecord = await datDnsDb.getCurrentByKey(datEncoding.toStr(key)) diff --git a/users/filesystem.js b/users/filesystem.js new file mode 100644 index 00000000..df9c6d37 --- /dev/null +++ b/users/filesystem.js @@ -0,0 +1,152 @@ +const logger = require('../logger').category('filesystem') +const dat = require('../dat') +const db = require('../dbs/profile-data-db') + +// typedefs +// = + +/** + * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive + * @typedef {import('./index').User} User + */ + +// globals +// = + +var rootArchive + +// exported api +// = + +/** + * @returns {DaemonDatArchive} + */ +exports.get = () => rootArchive + +/** + * @param {User[]} users + * @returns {Promise} + */ +exports.setup = async function (users) { + // create the root archive as needed + var browsingProfile = await db.get(`SELECT * FROM profiles WHERE id = 0`) + if (!browsingProfile.url) { + let url = await dat.library.createNewArchive({}, { + hidden: true, + networked: false + }) + logger.info('Root archive created', {url}) + await db.run(`UPDATE profiles SET url = ? WHERE id = 0`, [url]) + browsingProfile.url = url + } + + // load root archive + rootArchive = await dat.library.getOrLoadArchive(browsingProfile.url) + + // enforce root files structure + logger.info('Loading root archive', {url: browsingProfile.url}) + try { + await ensureDir('/users') + + // ensure all user mounts are set + for (let user of users) { + if (user.isDefault) await ensureMount('/public', user.url) + if (!user.isTemporary) { + await ensureMount(`/users/${user.label}`, user.url) + } + } + + // clear out any old mounts + let usersFilenames = await rootArchive.pda.readdir('/users', {stat: true}) + for (let filename of usersFilenames) { + if (!users.find(u => u.label === filename)) { + let path = `/users/${filename}` + let st = await stat(path) + if (st && st.mount) { + logger.info('Removing old /users mount', {path}) + await rootArchive.pda.unmount(path) + } + } + } + + // TODO remove /users mounts under old labels + } catch (e) { + console.error('Error while constructing the root archive', e) + logger.error('Error while constructing the root archive', e) + } +} + +/** + * @param {User} user + * @returns {Promise} + */ +exports.addUser = async function (user) { + await ensureMount(`/users/${user.label}`, user.url) + if (user.isDefault) await ensureMount(`/public`, user.url) +} + +/** + * @param {User} user + * @returns {Promise} + */ +exports.removeUser = async function (user) { + await ensureUnmount(`/users/${user.label}`) +} + +// internal methods +// = + +async function stat (path) { + try { return await rootArchive.pda.stat(path) } + catch (e) { return null } +} + +async function ensureDir (path) { + try { + let st = await stat(path) + if (!st) { + logger.info('Creating directory', path) + await rootArchive.pda.mkdir(path) + } else if (!st.isDirectory()) { + logger.error('Warning! Filesystem expects a folder but an unexpected file exists at this location.', {path}) + } + } catch (e) { + logger.error('Filesystem failed to make directory', {path, error: e}) + } +} + +async function ensureMount (path, url) { + try { + let st = await stat(path) + let key = await dat.library.fromURLToKey(url, true) + if (!st) { + // add mount + logger.info('Adding mount', {path, key}) + await rootArchive.pda.mount(path, key) + } else if (st.mount) { + if (st.mount.key.toString('hex') !== key) { + // change mount + logger.info('Reassigning mount', {path, key, oldKey: st.mount.key.toString('hex')}) + await rootArchive.pda.unmount(path) + await rootArchive.pda.mount(path, key) + } + } else { + logger.error('Warning! Filesystem expects a mount but an unexpected file exists at this location.', {path}) + } + } catch (e) { + logger.error('Filesystem failed to mount archive', {path, url, error: e}) + } +} + +async function ensureUnmount (path) { + try { + let st = await stat(path) + if (st && st.mount) { + // remove mount + logger.info('Removing mount', {path}) + await rootArchive.pda.unmount(path) + } + } catch (e) { + logger.error('Filesystem failed to unmount archive', {path, error: e}) + } +} \ No newline at end of file diff --git a/users/index.js b/users/index.js index 4606d0b1..3db65d6c 100644 --- a/users/index.js +++ b/users/index.js @@ -3,6 +3,7 @@ const Events = require('events') const logger = require('../logger').category('crawler') const dat = require('../dat') const crawler = require('../crawler') +const filesystem = require('./filesystem') const followsCrawler = require('../crawler/follows') const bookmarksCrawler = require('../crawler/bookmarks') const db = require('../dbs/profile-data-db') @@ -55,9 +56,6 @@ exports.removeListener = events.removeListener.bind(events) * @returns {Promise} */ exports.setup = async function () { - // initiate ticker - queueTick() - // load the current users users = await db.all(`SELECT * FROM users`) await Promise.all(users.map(async (user) => { @@ -104,6 +102,12 @@ exports.setup = async function () { invalids.forEach(async (invalidUser) => { await db.run(`DELETE FROM users WHERE url = ?`, [invalidUser.url]) }) + + // ensure root archive fits desired shape + await filesystem.setup(users) + + // initiate ticker + queueTick() } function queueTick () { @@ -229,20 +233,21 @@ exports.add = async function (label, url, setDefault = false, isTemporary = fals if (existingUser) throw new Error('User already exists at that label') // create the new user - var user = { + var user = /** @type User */({ label, url, archive: null, isDefault: setDefault || users.length === 0, isTemporary, createdAt: new Date() - } + }) logger.verbose('Adding user', {details: user.url}) await db.run( `INSERT INTO users (label, url, isDefault, isTemporary, createdAt) VALUES (?, ?, ?, ?, ?)`, [user.label, user.url, Number(user.isDefault), Number(user.isTemporary), Number(user.createdAt)] ) users.push(user) + await filesystem.addUser(user) // fetch the user archive user.archive = await dat.library.getOrLoadArchive(user.url) @@ -271,8 +276,14 @@ exports.edit = async function (url, opts) { var existingUser = users.find(user => user.label === opts.label) if (existingUser && existingUser.url !== url) throw new Error('User already exists at that label') - // update the user var user = users.find(user => user.url === url) + + // remove old filesystem mount if the label is changing + if (opts.label && opts.label !== user.label) { + await filesystem.removeUser(user) + } + + // update the user if (opts.title) user.title = opts.title if (opts.description) user.description = opts.title if (opts.setDefault) { @@ -286,7 +297,8 @@ exports.edit = async function (url, opts) { user.label = opts.label await db.run(`UPDATE users SET label = ? WHERE url = ?`, [opts.label, user.url]) } - logger.verbose('Updating user', {details: user.url}) + await filesystem.addUser(user) + logger.verbose('Updated user', {details: user.url}) // fetch the user archive user.archive = await dat.library.getOrLoadArchive(user.url) @@ -306,6 +318,7 @@ exports.remove = async function (url) { // remove the user logger.verbose('Removing user', {details: user.url}) + await filesystem.removeUser(user) users.splice(users.indexOf(user), 1) await db.run(`DELETE FROM users WHERE url = ?`, [user.url]) /* dont await */crawler.unwatchSite(user.archive) @@ -490,4 +503,4 @@ function watchAndSyncBookmarks (user) { // if (!existing) await bookmarksCrawler.deleteBookmark(user.archive, b.pathname) // remove // } // } -} \ No newline at end of file +} From d275f34d593481a3a12699845f8ff2b28bfba8bb Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Mon, 19 Aug 2019 16:57:33 -0500 Subject: [PATCH 30/74] Add navigator.filesystem Web API --- web-apis/bg.js | 3 +++ web-apis/bg/navigator-filesystem.js | 27 +++++++++++++++++++ web-apis/fg/navigator-methods.js | 9 +++++++ .../external/navigator-filesystem.js | 3 +++ 4 files changed, 42 insertions(+) create mode 100644 web-apis/bg/navigator-filesystem.js create mode 100644 web-apis/manifests/external/navigator-filesystem.js diff --git a/web-apis/bg.js b/web-apis/bg.js index f0ae4e51..3956e612 100644 --- a/web-apis/bg.js +++ b/web-apis/bg.js @@ -29,6 +29,7 @@ const usersAPI = require('./bg/users') // external manifests const navigatorManifest = require('./manifests/external/navigator') const navigatorSessionManifest = require('./manifests/external/navigator-session') +const navigatorFilesystemManifest = require('./manifests/external/navigator-filesystem') const datArchiveManifest = require('./manifests/external/dat-archive') const spellCheckerManifest = require('./manifests/external/spell-checker') const bookmarksManifest = require('./manifests/external/bookmarks') @@ -47,6 +48,7 @@ const votesManifest = require('./manifests/external/unwalled-garden-votes') // external apis const navigatorAPI = require('./bg/navigator') const navigatorSessionAPI = require('./bg/navigator-session') +const navigatorFilesystemAPI = require('./bg/navigator-filesystem') const datArchiveAPI = require('./bg/dat-archive') const spellCheckerAPI = require('./bg/spell-checker') const bookmarksAPI = require('./bg/bookmarks') @@ -92,6 +94,7 @@ exports.setup = function () { // external apis globals.rpcAPI.exportAPI('navigator', navigatorManifest, navigatorAPI, secureOnly) globals.rpcAPI.exportAPI('navigator-session', navigatorSessionManifest, navigatorSessionAPI, secureOnly) + globals.rpcAPI.exportAPI('navigator-filesystem', navigatorFilesystemManifest, navigatorFilesystemAPI, secureOnly) globals.rpcAPI.exportAPI('dat-archive', datArchiveManifest, datArchiveAPI, secureOnly) globals.rpcAPI.exportAPI('spell-checker', spellCheckerManifest, spellCheckerAPI) globals.rpcAPI.exportAPI('bookmarks', bookmarksManifest, bookmarksAPI, secureOnly) diff --git a/web-apis/bg/navigator-filesystem.js b/web-apis/bg/navigator-filesystem.js new file mode 100644 index 00000000..3e747a65 --- /dev/null +++ b/web-apis/bg/navigator-filesystem.js @@ -0,0 +1,27 @@ +const { PermissionsError } = require('beaker-error-constants') +const filesystem = require('../../users/filesystem') + +// typedefs +// = + +/** + * @typedef {Object} NavigatorFilesystemPublicAPIRootArchiveRecord + * @prop {string} url + */ + +// exported api +// = + +module.exports = { + /** + * @returns {Promise} + */ + async getRootArchive () { + if (!this.sender.getURL().startsWith('beaker:')) { + throw new PermissionsError() + } + return { + url: filesystem.get().url + } + } +} diff --git a/web-apis/fg/navigator-methods.js b/web-apis/fg/navigator-methods.js index 374c2adf..19f945f1 100644 --- a/web-apis/fg/navigator-methods.js +++ b/web-apis/fg/navigator-methods.js @@ -1,6 +1,7 @@ const errors = require('beaker-error-constants') const manifest = require('../manifests/external/navigator') const sessionManifest = require('../manifests/external/navigator-session') +const filesystemManifest = require('../manifests/external/navigator-filesystem') const RPC_OPTS = { timeout: false, errors } @@ -19,4 +20,12 @@ exports.setup = function (rpc) { navigator.session[k] = sessionApi[k].bind(sessionApi) } } + + var filesystemApi = rpc.importAPI('navigator-filesystem', filesystemManifest, RPC_OPTS) + navigator.filesystem = { + async getRootArchive () { + var {url} = await filesystemApi.getRootArchive() + return new DatArchive(url) + } + } } diff --git a/web-apis/manifests/external/navigator-filesystem.js b/web-apis/manifests/external/navigator-filesystem.js new file mode 100644 index 00000000..5c93714d --- /dev/null +++ b/web-apis/manifests/external/navigator-filesystem.js @@ -0,0 +1,3 @@ +module.exports = { + getRootArchive: 'promise' +} \ No newline at end of file From c9af1d594218c585bd1550b0c285a7ff7cfbb5b3 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Mon, 19 Aug 2019 16:57:43 -0500 Subject: [PATCH 31/74] Include .mount on DatArchive stat output --- web-apis/fg/stat.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web-apis/fg/stat.js b/web-apis/fg/stat.js index a5535283..e09beded 100644 --- a/web-apis/fg/stat.js +++ b/web-apis/fg/stat.js @@ -22,7 +22,9 @@ const Stat = module.exports = function Stat (data) { this.atime = new Date(data ? data.mtime : 0) // we just set this to mtime ... this.mtime = new Date(data ? data.mtime : 0) this.ctime = new Date(data ? data.ctime : 0) - + this.mount = data && data.mount && data.mount.key + ? {key: data.mount.key.toString('hex')} + : null this.linkname = data ? data.linkname : null } From 79d56b7e7be181281fad0ac1a904146fe68cd56a Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 23 Aug 2019 10:58:29 -0500 Subject: [PATCH 32/74] Readd .forkOf to dat.json manifests of forks --- dat/library.js | 7 ++++--- dbs/archives.js | 27 +++++++++++++++++++++------ dbs/schemas/profile-data.sql.js | 2 +- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/dat/library.js b/dat/library.js index aefede84..c66e3090 100644 --- a/dat/library.js +++ b/dat/library.js @@ -194,12 +194,12 @@ const pullLatestArchiveMeta = exports.pullLatestArchiveMeta = async function pul archivesDb.getMeta(key), archive.pda.readSize('/') ]) - var {title, description, type} = (manifest || {}) + var {title, description, type, forkOf} = (manifest || {}) var isOwner = archive.writable var mtime = updateMTime ? Date.now() : oldMeta.mtime // write the record - var details = {title, description, type, mtime, size, isOwner} + var details = {title, description, type, mtime, size, forkOf, isOwner} await archivesDb.setMeta(key, details) // emit the updated event @@ -274,7 +274,8 @@ exports.forkArchive = async function forkArchive (srcArchiveUrl, manifest = {}, title: (manifest.title) ? manifest.title : srcManifest.title, description: (manifest.description) ? manifest.description : srcManifest.description, type: (manifest.type) ? manifest.type : srcManifest.type, - author: manifest.author + author: manifest.author, + forkOf: srcArchiveUrl } DAT_PRESERVED_FIELDS_ON_FORK.forEach(field => { if (srcManifest[field]) { diff --git a/dbs/archives.js b/dbs/archives.js index e8b3bbb2..c8260ceb 100644 --- a/dbs/archives.js +++ b/dbs/archives.js @@ -27,6 +27,7 @@ const { * @prop {Array} type * @prop {number} mtime * @prop {number} size + * @prop {string} forkOf * @prop {boolean} isOwner * @prop {number} lastAccessTime * @prop {number} lastLibraryAccessTime @@ -48,6 +49,7 @@ const { * @prop {Array} installedNames * @prop {number} mtime * @prop {number} size + * @prop {string} forkOf * @prop {boolean} isOwner * @prop {number} lastAccessTime * @prop {number} lastLibraryAccessTime @@ -163,6 +165,7 @@ exports.removeListener = events.removeListener.bind(events) * @param {boolean} [query.isSaved] * @param {boolean} [query.isNetworked] * @param {boolean} [query.isOwner] + * @param {string} [query.forkOf] * @param {boolean} [query.showHidden] * @param {string} [query.type] * @param {string} [query.string] @@ -176,6 +179,10 @@ exports.query = async function (profileId, query = {}) { if (query.isOwner === false) whereList.push('archives_meta.isOwner = 0') if (query.isNetworked === true) whereList.push('archives.networked = 1') if (query.isNetworked === false) whereList.push('archives.networked = 0') + if ('forkOf' in query) { + whereList.push('archives_meta.forkOf = ?') + values.push(query.forkOf) + } if ('isSaved' in query) { if (query.isSaved) { whereList.push('archives.profileId = ?') @@ -242,7 +249,6 @@ exports.query = async function (profileId, query = {}) { // deprecated attrs delete archive.createdByTitle delete archive.createdByUrl - delete archive.forkOf delete archive.metaSize delete archive.stagingSize delete archive.stagingSizeLessIgnored @@ -528,7 +534,6 @@ const getMeta = exports.getMeta = async function (key) { // remove old attrs delete meta.createdByTitle delete meta.createdByUrl - delete meta.forkOf delete meta.metaSize delete meta.stagingSize delete meta.stagingSizeLessIgnored @@ -555,12 +560,13 @@ exports.setMeta = async function (key, value) { } // extract the desired values - var {title, description, type, size, mtime, isOwner} = value + var {title, description, type, size, forkOf, mtime, isOwner} = value title = typeof title === 'string' ? title : '' description = typeof description === 'string' ? description : '' if (typeof type === 'string') type = type.split(' ') else if (Array.isArray(type)) type = type.filter(v => v && typeof v === 'string') var isOwnerFlag = flag(isOwner) + if (typeof forkOf === 'string') forkOf = normalizeDatUrl(forkOf) // write var release = await lock('archives-db:meta') @@ -568,9 +574,9 @@ exports.setMeta = async function (key, value) { try { await db.run(` INSERT OR REPLACE INTO - archives_meta (key, title, description, mtime, size, isOwner, lastAccessTime, lastLibraryAccessTime) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) - `, [keyStr, title, description, mtime, size, isOwnerFlag, lastAccessTime, lastLibraryAccessTime]) + archives_meta (key, title, description, mtime, size, forkOf, isOwner, lastAccessTime, lastLibraryAccessTime) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + `, [keyStr, title, description, mtime, size, forkOf, isOwnerFlag, lastAccessTime, lastLibraryAccessTime]) await db.run(`DELETE FROM archives_meta_type WHERE key=?`, keyStr) if (type) { await Promise.all(type.map(t => ( @@ -612,6 +618,7 @@ function defaultMeta (key) { title: null, description: null, type: [], + forkOf: null, mtime: 0, isOwner: false, lastAccessTime: 0, @@ -638,3 +645,11 @@ exports.extractOrigin = function (originURL) { if (!urlp || !urlp.host || !urlp.protocol) return return (urlp.protocol + (urlp.slashes ? '//' : '') + urlp.host) } + +function normalizeDatUrl (url) { + var match = url.match(DAT_HASH_REGEX) + if (match) { + return `dat://${match[0]}` + } + return exports.extractOrigin(url) +} \ No newline at end of file diff --git a/dbs/schemas/profile-data.sql.js b/dbs/schemas/profile-data.sql.js index 9adff13b..68c4ace9 100644 --- a/dbs/schemas/profile-data.sql.js +++ b/dbs/schemas/profile-data.sql.js @@ -49,11 +49,11 @@ CREATE TABLE archives_meta ( description TEXT, mtime INTEGER, size INTEGER, + forkOf TEXT, isOwner INTEGER, lastAccessTime INTEGER DEFAULT 0, lastLibraryAccessTime INTEGER DEFAULT 0, - forkOf TEXT, -- deprecated createdByUrl TEXT, -- deprecated createdByTitle TEXT, -- deprecated metaSize INTEGER, -- deprecated From 6f961179697d28a997a129848c18ad990f3faf27 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Wed, 28 Aug 2019 14:58:01 -0500 Subject: [PATCH 33/74] Remove uwg discussions --- crawler/discussions.js | 418 ------------------ crawler/json-schemas/discussion.js | 43 -- web-apis/bg.js | 3 - web-apis/bg/unwalled-garden-discussions.js | 209 --------- web-apis/fg/navigator-import.js | 5 - .../external/unwalled-garden-discussions.js | 7 - 6 files changed, 685 deletions(-) delete mode 100644 crawler/discussions.js delete mode 100644 crawler/json-schemas/discussion.js delete mode 100644 web-apis/bg/unwalled-garden-discussions.js delete mode 100644 web-apis/manifests/external/unwalled-garden-discussions.js diff --git a/crawler/discussions.js b/crawler/discussions.js deleted file mode 100644 index 69adc3a4..00000000 --- a/crawler/discussions.js +++ /dev/null @@ -1,418 +0,0 @@ -const assert = require('assert') -const {URL} = require('url') -const Events = require('events') -const Ajv = require('ajv') -const logger = require('../logger').child({category: 'crawler', dataset: 'discussions'}) -const db = require('../dbs/profile-data-db') -const crawler = require('./index') -const datLibrary = require('../dat/library') -const lock = require('../lib/lock') -const knex = require('../lib/knex') -const siteDescriptions = require('./site-descriptions') -const {doCrawl, doCheckpoint, emitProgressEvent, getMatchingChangesInOrder, generateTimeFilename, ensureDirectory} = require('./util') -const discussionSchema = require('./json-schemas/discussion') - -// constants -// = - -const TABLE_VERSION = 1 -const JSON_TYPE = 'unwalled.garden/discussion' -const JSON_PATH_REGEX = /^\/data\/discussions\/([^/]+)\.json$/i - -// typedefs -// = - -/** - * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive - * @typedef {import('./util').CrawlSourceRecord} CrawlSourceRecord - * @typedef { import("./site-descriptions").SiteDescription } SiteDescription - * - * @typedef {Object} Discussion - * @prop {string} pathname - * @prop {string} title - * @prop {string} body - * @prop {string} href - * @prop {string[]} tags - * @prop {string} createdAt - * @prop {string} updatedAt - * @prop {SiteDescription} author - * @prop {string} visibility - */ - -// globals -// = - -const events = new Events() -const ajv = (new Ajv()) -const validateDiscussion = ajv.compile(discussionSchema) - -// exported api -// = - -exports.on = events.on.bind(events) -exports.addListener = events.addListener.bind(events) -exports.removeListener = events.removeListener.bind(events) - -/** - * @description - * Crawl the given site for discussions. - * - * @param {DaemonDatArchive} archive - site to crawl. - * @param {CrawlSourceRecord} crawlSource - internal metadata about the crawl target. - * @returns {Promise} - */ -exports.crawlSite = async function (archive, crawlSource) { - return doCrawl(archive, crawlSource, 'crawl_discussions', TABLE_VERSION, async ({changes, resetRequired}) => { - const supressEvents = resetRequired === true // dont emit when replaying old info - logger.silly('Crawling discussions', {details: {url: archive.url, numChanges: changes.length, resetRequired}}) - if (resetRequired) { - // reset all data - logger.debug('Resetting dataset', {details: {url: archive.url}}) - await db.run(` - DELETE FROM crawl_discussions WHERE crawlSourceId = ? - `, [crawlSource.id]) - await doCheckpoint('crawl_discussions', TABLE_VERSION, crawlSource, 0) - } - - // collect changed discussions - var changedDiscussions = getMatchingChangesInOrder(changes, JSON_PATH_REGEX) - if (changedDiscussions.length) { - logger.verbose('Collected new/changed discussion files', {details: {url: archive.url, changedDiscussions: changedDiscussions.map(p => p.name)}}) - } else { - logger.debug('No new discussion-files found', {details: {url: archive.url}}) - } - emitProgressEvent(archive.url, 'crawl_discussions', 0, changedDiscussions.length) - - // read and apply each discussion in order - var progress = 0 - for (let changedDiscussion of changedDiscussions) { - // TODO Currently the crawler will abort reading the feed if any discussion fails to load - // this means that a single unreachable file can stop the forward progress of discussion indexing - // to solve this, we need to find a way to tolerate unreachable discussion-files without losing our ability to efficiently detect new discussions - // -prf - if (changedDiscussion.type === 'del') { - // delete - await db.run(` - DELETE FROM crawl_discussions WHERE crawlSourceId = ? AND pathname = ? - `, [crawlSource.id, changedDiscussion.name]) - events.emit('discussion-removed', archive.url) - } else { - // read - let discussionString - try { - discussionString = await archive.pda.readFile(changedDiscussion.name, 'utf8') - } catch (err) { - logger.warn('Failed to read discussion file, aborting', {details: {url: archive.url, name: changedDiscussion.name, err}}) - return // abort indexing - } - - // parse and validate - let discussion - try { - discussion = JSON.parse(discussionString) - let valid = validateDiscussion(discussion) - if (!valid) throw ajv.errorsText(validateDiscussion.errors) - } catch (err) { - logger.warn('Failed to parse discussion file, skipping', {details: {url: archive.url, name: changedDiscussion.name, err}}) - continue // skip - } - - // massage the discussion - discussion.createdAt = Number(new Date(discussion.createdAt)) - discussion.updatedAt = Number(new Date(discussion.updatedAt)) - if (!discussion.title) discussion.title = '' // optional - if (!discussion.href) discussion.href = '' // optional - if (!discussion.tags) discussion.tags = [] // optional - if (isNaN(discussion.updatedAt)) discussion.updatedAt = 0 // optional - - // upsert - let discussionId = 0 - let existingDiscussion = await db.get(knex('crawl_discussions') - .select('id') - .where({ - crawlSourceId: crawlSource.id, - pathname: changedDiscussion.name - }) - ) - if (existingDiscussion) { - let res = await db.run(knex('crawl_discussions') - .where({ - crawlSourceId: crawlSource.id, - pathname: changedDiscussion.name - }).update({ - crawledAt: Date.now(), - title: discussion.title, - body: discussion.body, - href: discussion.href, - createdAt: discussion.createdAt, - updatedAt: discussion.updatedAt, - }) - ) - discussionId = existingDiscussion.id - events.emit('discussion-updated', archive.url) - } else { - let res = await db.run(knex('crawl_discussions') - .insert({ - crawlSourceId: crawlSource.id, - pathname: changedDiscussion.name, - crawledAt: Date.now(), - title: discussion.title, - body: discussion.body, - href: discussion.href, - createdAt: discussion.createdAt, - updatedAt: discussion.updatedAt, - }) - ) - discussionId = +res.lastID - events.emit('discussion-added', archive.url) - } - await db.run(`DELETE FROM crawl_discussions_tags WHERE crawlDiscussionId = ?`, [discussionId]) - for (let tag of discussion.tags) { - await db.run(`INSERT OR IGNORE INTO crawl_tags (tag) VALUES (?)`, [tag]) - let tagRow = await db.get(`SELECT id FROM crawl_tags WHERE tag = ?`, [tag]) - await db.run(`INSERT INTO crawl_discussions_tags (crawlDiscussionId, crawlTagId) VALUES (?, ?)`, [discussionId, tagRow.id]) - } - } - - // checkpoint our progress - await doCheckpoint('crawl_discussions', TABLE_VERSION, crawlSource, changedDiscussion.version) - emitProgressEvent(archive.url, 'crawl_discussions', ++progress, changedDiscussions.length) - } - logger.silly(`Finished crawling discussions`, {details: {url: archive.url}}) - }) -} - -/** - * @description - * List crawled discussions. - * - * @param {Object} [opts] - * @param {Object} [opts.filters] - * @param {string|string[]} [opts.filters.authors] - * @param {string|string[]} [opts.filters.tags] - * @param {string} [opts.filters.visibility] - * @param {string} [opts.sortBy] - * @param {number} [opts.offset=0] - * @param {number} [opts.limit] - * @param {boolean} [opts.reverse] - * @returns {Promise>} - */ -exports.list = async function (opts) { - // TODO: handle visibility - // TODO: sortBy options - - // validate & parse params - if (opts && 'sortBy' in opts) assert(typeof opts.sortBy === 'number', 'SortBy must be a string') - if (opts && 'offset' in opts) assert(typeof opts.offset === 'number', 'Offset must be a number') - if (opts && 'limit' in opts) assert(typeof opts.limit === 'number', 'Limit must be a number') - if (opts && 'reverse' in opts) assert(typeof opts.reverse === 'boolean', 'Reverse must be a boolean') - if (opts && opts.filters) { - if ('authors' in opts.filters) { - if (Array.isArray(opts.filters.authors)) { - assert(opts.filters.authors.every(v => typeof v === 'string'), 'Authors filter must be a string or array of strings') - } else { - assert(typeof opts.filters.authors === 'string', 'Authors filter must be a string or array of strings') - opts.filters.authors = [opts.filters.authors] - } - opts.filters.authors = await Promise.all(opts.filters.authors.map(datLibrary.getPrimaryUrl)) - } - if ('tags' in opts.filters) { - if (Array.isArray(opts.filters.tags)) { - assert(opts.filters.tags.every(v => typeof v === 'string'), 'Tags filter must be a string or array of strings') - } else { - assert(typeof opts.filters.tags === 'string', 'Tags filter must be a string or array of strings') - opts.filters.tags = [opts.filters.tags] - } - } - } - - // build query - var sql = knex('crawl_discussions') - .select('crawl_discussions.*') - .select('crawl_sources.url as crawlSourceUrl') - .select(knex.raw('group_concat(crawl_tags.tag, ",") as tags')) - .innerJoin('crawl_sources', 'crawl_sources.id', '=', 'crawl_discussions.crawlSourceId') - .leftJoin('crawl_discussions_tags', 'crawl_discussions_tags.crawlDiscussionId', '=', 'crawl_discussions.id') - .leftJoin('crawl_tags', 'crawl_discussions_tags.crawlTagId', '=', 'crawl_tags.id') - .groupBy('crawl_discussions.id') - .orderBy('crawl_discussions.createdAt', opts.reverse ? 'DESC' : 'ASC') - if (opts && opts.filters && opts.filters.authors) { - sql = sql.whereIn('crawl_sources.url', opts.filters.authors) - } - if (opts && opts.limit) sql = sql.limit(opts.limit) - if (opts && opts.offset) sql = sql.offset(opts.offset) - - // execute query - var rows = await db.all(sql) - var discussions = await Promise.all(rows.map(massageDiscussionRow)) - - // apply tags filter - if (opts && opts.filters && opts.filters.tags) { - const someFn = t => opts.filters.tags.includes(t) - discussions = discussions.filter(discussion => discussion.tags.some(someFn)) - } - - return discussions -} - -/** - * @description - * Get crawled discussion. - * - * @param {string} url - The URL of the discussion - * @returns {Promise} - */ -const get = exports.get = async function (url) { - // validate & parse params - var urlParsed - if (url) { - try { urlParsed = new URL(url) } - catch (e) { throw new Error('Invalid URL: ' + url) } - } - - // build query - var sql = knex('crawl_discussions') - .select('crawl_discussions.*') - .select('crawl_sources.url as crawlSourceUrl') - .select(knex.raw('group_concat(crawl_tags.tag, ",") as tags')) - .innerJoin('crawl_sources', function () { - this.on('crawl_sources.id', '=', 'crawl_discussions.crawlSourceId') - .andOn('crawl_sources.url', '=', knex.raw('?', `${urlParsed.protocol}//${urlParsed.hostname}`)) - }) - .leftJoin('crawl_discussions_tags', 'crawl_discussions_tags.crawlDiscussionId', '=', 'crawl_discussions.id') - .leftJoin('crawl_tags', 'crawl_tags.id', '=', 'crawl_discussions_tags.crawlTagId') - .where('crawl_discussions.pathname', urlParsed.pathname) - .groupBy('crawl_discussions.id') - - // execute query - return await massageDiscussionRow(await db.get(sql)) -} - -/** - * @description - * Create a new discussion. - * - * @param {DaemonDatArchive} archive - where to write the discussion to. - * @param {Object} discussion - * @param {string} discussion.title - * @param {string} discussion.body - * @param {string} discussion.href - * @param {string[]} discussion.tags - * @param {string} discussion.visibility - * @returns {Promise} url - */ -exports.add = async function (archive, discussion) { - // TODO visibility - - var discussionObject = { - type: JSON_TYPE, - title: discussion.title, - body: discussion.body, - href: discussion.href, - tags: discussion.tags, - createdAt: (new Date()).toISOString() - } - var valid = validateDiscussion(discussionObject) - if (!valid) throw ajv.errorsText(validateDiscussion.errors) - - var filename = generateTimeFilename() - var filepath = `/data/discussions/${filename}.json` - await ensureDirectory(archive, '/data') - await ensureDirectory(archive, '/data/discussions') - await archive.pda.writeFile(filepath, JSON.stringify(discussionObject, null, 2)) - await crawler.crawlSite(archive) - return archive.url + filepath -} - -/** - * @description - * Update the content of an existing discussion. - * - * @param {DaemonDatArchive} archive - where to write the discussion to. - * @param {string} pathname - the pathname of the discussion. - * @param {Object} discussion - * @param {string} [discussion.title] - * @param {string} [discussion.body] - * @param {string} [discussion.href] - * @param {string[]} [discussion.tags] - * @param {string} [discussion.visibility] - * @returns {Promise} - */ -exports.edit = async function (archive, pathname, discussion) { - // TODO visibility - - var release = await lock('crawler:discussions:' + archive.url) - try { - // fetch discussion - var existingDiscussion = await get(archive.url + pathname) - if (!existingDiscussion) throw new Error('Discussion not found') - - // update discussion content - var discussionObject = { - type: JSON_TYPE, - title: ('title' in discussion) ? discussion.title : existingDiscussion.title, - body: ('body' in discussion) ? discussion.body : existingDiscussion.body, - href: ('href' in discussion) ? discussion.href : existingDiscussion.href, - tags: ('tags' in discussion) ? discussion.tags : existingDiscussion.tags, - createdAt: existingDiscussion.createdAt, - updatedAt: (new Date()).toISOString() - } - - // validate - var valid = validateDiscussion(discussionObject) - if (!valid) throw ajv.errorsText(validateDiscussion.errors) - - // write - await archive.pda.writeFile(pathname, JSON.stringify(discussionObject, null, 2)) - await crawler.crawlSite(archive) - } finally { - release() - } -} - -/** - * @description - * Delete an existing discussion - * - * @param {DaemonDatArchive} archive - where to write the discussion to. - * @param {string} pathname - the pathname of the discussion. - * @returns {Promise} - */ -exports.remove = async function (archive, pathname) { - assert(typeof pathname === 'string', 'Remove() must be provided a valid URL string') - await archive.pda.unlink(pathname) - await crawler.crawlSite(archive) -} - -// internal methods -// = - -/** - * @param {Object} row - * @returns {Promise} - */ -async function massageDiscussionRow (row) { - if (!row) return null - var author = await siteDescriptions.getBest({subject: row.crawlSourceUrl}) - if (!author) { - author = { - url: row.crawlSourceUrl, - title: '', - description: '', - type: [], - thumbUrl: `${row.crawlSourceUrl}/thumb`, - descAuthor: {url: null} - } - } - return { - pathname: row.pathname, - author, - title: row.title, - body: row.body, - href: row.href, - tags: row.tags ? row.tags.split(',').filter(Boolean) : [], - createdAt: new Date(row.createdAt).toISOString(), - updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null, - visibility: 'public' // TODO visibility - } -} diff --git a/crawler/json-schemas/discussion.js b/crawler/json-schemas/discussion.js deleted file mode 100644 index ba561eea..00000000 --- a/crawler/json-schemas/discussion.js +++ /dev/null @@ -1,43 +0,0 @@ -module.exports = { - '$schema': 'http://json-schema.org/draft-07/schema#', - '$id': 'dat://unwalled.garden/discussion.json', - 'type': 'object', - 'title': 'Discussion', - 'description': 'A forum discussion.', - 'required': ['type', 'title', 'createdAt'], - 'properties': { - 'type': { - 'type': 'string', - 'description': "The object's type", - 'const': 'unwalled.garden/discussion' - }, - 'title': { - 'type': 'string', - 'maxLength': 280 - }, - 'body': { - 'type': 'string', - 'maxLength': 1000000 - }, - 'href': { - 'type': 'string', - 'format': 'uri' - }, - 'tags': { - 'type': 'array', - 'items': { - 'type': 'string', - 'maxLength': 100, - 'pattern': '^[A-Za-z][A-Za-z0-9-_?]*$' - } - }, - 'createdAt': { - 'type': 'string', - 'format': 'date-time' - }, - 'updatedAt': { - 'type': 'string', - 'format': 'date-time' - } - } -} \ No newline at end of file diff --git a/web-apis/bg.js b/web-apis/bg.js index 3956e612..c25cb1e6 100644 --- a/web-apis/bg.js +++ b/web-apis/bg.js @@ -36,7 +36,6 @@ const bookmarksManifest = require('./manifests/external/bookmarks') const libraryManifest = require('./manifests/external/library') const searchManifest = require('./manifests/external/search') const commentsManifest = require('./manifests/external/unwalled-garden-comments') -const discussionsManifest = require('./manifests/external/unwalled-garden-discussions') const followsManifest = require('./manifests/external/unwalled-garden-follows') const mediaManifest = require('./manifests/external/unwalled-garden-media') const postsManifest = require('./manifests/external/unwalled-garden-posts') @@ -55,7 +54,6 @@ const bookmarksAPI = require('./bg/bookmarks') const libraryAPI = require('./bg/library') const searchAPI = require('./bg/search') const commentsAPI = require('./bg/unwalled-garden-comments') -const discussionsAPI = require('./bg/unwalled-garden-discussions') const followsAPI = require('./bg/unwalled-garden-follows') const mediaAPI = require('./bg/unwalled-garden-media') const postsAPI = require('./bg/unwalled-garden-posts') @@ -101,7 +99,6 @@ exports.setup = function () { globals.rpcAPI.exportAPI('library', libraryManifest, libraryAPI, secureOnly) globals.rpcAPI.exportAPI('search', searchManifest, searchAPI, secureOnly) globals.rpcAPI.exportAPI('unwalled-garden-comments', commentsManifest, commentsAPI, secureOnly) - globals.rpcAPI.exportAPI('unwalled-garden-discussions', discussionsManifest, discussionsAPI, secureOnly) globals.rpcAPI.exportAPI('unwalled-garden-follows', followsManifest, followsAPI, secureOnly) globals.rpcAPI.exportAPI('unwalled-garden-media', mediaManifest, mediaAPI, secureOnly) globals.rpcAPI.exportAPI('unwalled-garden-posts', postsManifest, postsAPI, secureOnly) diff --git a/web-apis/bg/unwalled-garden-discussions.js b/web-apis/bg/unwalled-garden-discussions.js deleted file mode 100644 index 52868c5f..00000000 --- a/web-apis/bg/unwalled-garden-discussions.js +++ /dev/null @@ -1,209 +0,0 @@ -const globals = require('../../globals') -const assert = require('assert') -const {URL} = require('url') -const dat = require('../../dat') -const discussionsCrawler = require('../../crawler/discussions') -const sessionPerms = require('../../lib/session-perms') - -// typedefs -// = - -/** - * @typedef {Object} DiscussionAuthorPublicAPIRecord - * @prop {string} url - * @prop {string} title - * @prop {string} description - * @prop {string[]} type - * - * @typedef {Object} DiscussionPublicAPIRecord - * @prop {string} url - * @prop {string} title - * @prop {string} body - * @prop {string} href - * @prop {string[]} tags - * @prop {string} createdAt - * @prop {string} updatedAt - * @prop {DiscussionAuthorPublicAPIRecord} author - * @prop {string} visibility - */ - -// exported api -// = - -module.exports = { - /** - * @param {Object} [opts] - * @param {Object} [opts.filters] - * @param {string|string[]} [opts.filters.authors] - * @param {string|string[]} [opts.filters.tags] - * @param {string} [opts.filters.visibility] - * @param {string} [opts.sortBy] - * @param {number} [opts.offset=0] - * @param {number} [opts.limit] - * @param {boolean} [opts.reverse] - * @returns {Promise} - */ - async list (opts) { - await sessionPerms.assertCan(this.sender, 'unwalled.garden/api/discussions', 'read') - opts = (opts && typeof opts === 'object') ? opts : {} - if (opts && 'sortBy' in opts) assert(typeof opts.sortBy === 'string', 'SortBy must be a string') - if (opts && 'offset' in opts) assert(typeof opts.offset === 'number', 'Offset must be a number') - if (opts && 'limit' in opts) assert(typeof opts.limit === 'number', 'Limit must be a number') - if (opts && 'reverse' in opts) assert(typeof opts.reverse === 'boolean', 'Reverse must be a boolean') - if (opts && opts.filters) { - if ('authors' in opts.filters) { - if (Array.isArray(opts.filters.authors)) { - assert(opts.filters.authors.every(v => typeof v === 'string'), 'Authors filter must be a string or array of strings') - } else { - assert(typeof opts.filters.authors === 'string', 'Authors filter must be a string or array of strings') - } - } - if ('tags' in opts.filters) { - if (Array.isArray(opts.filters.tags)) { - assert(opts.filters.tags.every(v => typeof v === 'string'), 'Tags filter must be a string or array of strings') - } else { - assert(typeof opts.filters.tags === 'string', 'Tags filter must be a string or array of strings') - } - } - if ('visibility' in opts.filters) { - assert(typeof opts.filters.visibility === 'string', 'Visibility filter must be a string') - } - } - var discussions = await discussionsCrawler.list(opts) - return Promise.all(discussions.map(massageDiscussionRecord)) - }, - - /** - * @param {string} url - * @returns {Promise} - */ - async get (url) { - await sessionPerms.assertCan(this.sender, 'unwalled.garden/api/discussions', 'read') - return massageDiscussionRecord(await discussionsCrawler.get(url)) - }, - - /** - * @param {Object} discussion - * @param {string} discussion.title - * @param {string} discussion.body - * @param {string} discussion.href - * @param {string[]} discussion.tags - * @param {string} discussion.visibility - * @returns {Promise} - */ - async add (discussion) { - await sessionPerms.assertCan(this.sender, 'unwalled.garden/api/discussions', 'write') - var userArchive = await sessionPerms.getSessionUserArchive(this.sender) - - assert(discussion && typeof discussion === 'object', 'The `discussion` parameter must be a string or object') - assert(discussion.title && typeof discussion.title === 'string', 'The `discussion.title` parameter must be a non-empty string') - if ('body' in discussion) assert(typeof discussion.body === 'string', 'The `discussion.body` parameter must be a string') - if ('href' in discussion) assert(typeof discussion.href === 'string', 'The `discussion.href` parameter must be a string') - if ('tags' in discussion) assert(discussion.tags.every(tag => typeof tag === 'string'), 'The `discussion.tags` parameter must be an array of strings') - if ('visibility' in discussion) assert(typeof discussion.visibility === 'string', 'The `discussion.visibility` parameter must be "public" or "private"') - - // default values - if (!discussion.visibility) { - discussion.visibility = 'public' - } - - var url = await discussionsCrawler.add(userArchive, discussion) - return massageDiscussionRecord(await discussionsCrawler.get(url)) - }, - - /** - * @param {string} url - * @param {Object} discussion - * @param {string} discussion.title - * @param {string} discussion.body - * @param {string} discussion.href - * @param {string[]} discussion.tags - * @param {string} discussion.visibility - * @returns {Promise} - */ - async edit (url, discussion) { - await sessionPerms.assertCan(this.sender, 'unwalled.garden/api/discussions', 'write') - var userArchive = await sessionPerms.getSessionUserArchive(this.sender) - - assert(url && typeof url === 'string', 'The `url` parameter must be a valid URL') - assert(discussion && typeof discussion === 'object', 'The `discussion` parameter must be an object') - if ('title' in discussion) assert(discussion.title && typeof discussion.title === 'string', 'The `discussion.title` parameter must be a non-empty string') - if ('body' in discussion) assert(typeof discussion.body === 'string', 'The `discussion.body` parameter must be a string') - if ('href' in discussion) assert(typeof discussion.href === 'string', 'The `discussion.href` parameter must be a string') - if ('tags' in discussion) assert(discussion.tags.every(tag => typeof tag === 'string'), 'The `discussion.tags` parameter must be an array of strings') - if ('visibility' in discussion) assert(typeof discussion.visibility === 'string', 'The `discussion.visibility` parameter must be "public" or "private"') - - var filepath = await urlToFilepath(url, userArchive.url) - await discussionsCrawler.edit(userArchive, filepath, discussion) - return massageDiscussionRecord(await discussionsCrawler.get(userArchive.url + filepath)) - }, - - /** - * @param {string} url - * @returns {Promise} - */ - async remove (url) { - await sessionPerms.assertCan(this.sender, 'unwalled.garden/api/discussions', 'write') - var userArchive = await sessionPerms.getSessionUserArchive(this.sender) - - assert(url && typeof url === 'string', 'The `url` parameter must be a valid URL') - - var filepath = await urlToFilepath(url, userArchive.url) - await discussionsCrawler.remove(userArchive, filepath) - } -} - -// internal methods -// = - -/** - * Tries to parse the URL and return the pathname. If fails, assumes the string was a pathname. - * @param {string} url - * @returns {Promise} - */ -async function urlToFilepath (url, origin) { - var urlp - var filepath - try { - // if `url` is a full URL, extract the path - urlp = new URL(url) - filepath = urlp.pathname - } catch (e) { - // assume `url` is a path - return url - } - - // double-check the origin - var key = await dat.dns.resolveName(urlp.hostname) - var urlp2 = new URL(origin) - if (key !== urlp2.hostname) { - throw new Error('Unable to edit discussions on other sites than your own') - } - - return filepath -} - -/** - * @param {Object} discussion - * @returns {DiscussionPublicAPIRecord} - */ -function massageDiscussionRecord (discussion) { - if (!discussion) return null - var url = discussion.author.url + discussion.pathname - return { - url, - title: discussion.title, - body: discussion.body, - href: discussion.href, - tags: discussion.tags, - createdAt: discussion.createdAt, - updatedAt: discussion.updatedAt, - author: { - url: discussion.author.url, - title: discussion.author.title, - description: discussion.author.description, - type: discussion.author.type - }, - visibility: discussion.visibility - } -} diff --git a/web-apis/fg/navigator-import.js b/web-apis/fg/navigator-import.js index 57c8c4c6..35906fdb 100644 --- a/web-apis/fg/navigator-import.js +++ b/web-apis/fg/navigator-import.js @@ -28,11 +28,6 @@ const APIs = { manifest: require('../manifests/external/unwalled-garden-comments'), create: makeCreateFn('unwalled-garden-comments') }, - // TODO readd when stablized -prf - // 'unwalled-garden-discussions': { - // manifest: require('../manifests/external/unwalled-garden-discussions'), - // create: makeCreateFn('unwalled-garden-discussions') - // }, 'unwalled-garden-follows': { manifest: require('../manifests/external/unwalled-garden-follows'), create: makeCreateFn('unwalled-garden-follows') diff --git a/web-apis/manifests/external/unwalled-garden-discussions.js b/web-apis/manifests/external/unwalled-garden-discussions.js deleted file mode 100644 index 06aeb28a..00000000 --- a/web-apis/manifests/external/unwalled-garden-discussions.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - list: 'promise', - get: 'promise', - add: 'promise', - edit: 'promise', - remove: 'promise' -} \ No newline at end of file From 38008e96edfcd287466465330af87cc11befbb80 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Wed, 28 Aug 2019 15:02:29 -0500 Subject: [PATCH 34/74] Remove uwg media --- crawler/json-schemas/media.js | 52 -- crawler/media.js | 450 ------------------ web-apis/bg.js | 3 - web-apis/bg/unwalled-garden-media.js | 231 --------- web-apis/fg/navigator-import.js | 5 - .../external/unwalled-garden-media.js | 7 - 6 files changed, 748 deletions(-) delete mode 100644 crawler/json-schemas/media.js delete mode 100644 crawler/media.js delete mode 100644 web-apis/bg/unwalled-garden-media.js delete mode 100644 web-apis/manifests/external/unwalled-garden-media.js diff --git a/crawler/json-schemas/media.js b/crawler/json-schemas/media.js deleted file mode 100644 index c904f02c..00000000 --- a/crawler/json-schemas/media.js +++ /dev/null @@ -1,52 +0,0 @@ -module.exports = { - '$schema': 'http://json-schema.org/draft-07/schema#', - '$id': 'dat://unwalled.garden/media.json', - 'type': 'object', - 'title': 'media', - 'description': 'A published item of content.', - 'required': [ - 'type', - 'subtype', - 'href', - 'title', - 'createdAt' - ], - 'properties': { - 'type': { - 'type': 'string', - 'const': 'unwalled.garden/media' - }, - 'subtype': { - 'type': 'string' - }, - 'href': { - 'type': 'string', - 'format': 'uri' - }, - 'title': { - 'type': 'string' - }, - 'description': { - 'type': 'string' - }, - 'tags': { - 'type': 'array', - 'items': { - 'type': 'string', - 'maxLength': 100, - 'pattern': '^[A-Za-z][A-Za-z0-9-_?]*$' - } - }, - 'createdAt': { - 'type': 'string', - 'format': 'date-time' - }, - 'updatedAt': { - 'type': 'string', - 'format': 'date-time' - }, - 'ext': { - 'type': 'object' - } - } -} \ No newline at end of file diff --git a/crawler/media.js b/crawler/media.js deleted file mode 100644 index 953e139b..00000000 --- a/crawler/media.js +++ /dev/null @@ -1,450 +0,0 @@ -const assert = require('assert') -const {URL} = require('url') -const Events = require('events') -const Ajv = require('ajv') -const logger = require('../logger').child({category: 'crawler', dataset: 'media'}) -const db = require('../dbs/profile-data-db') -const crawler = require('./index') -const lock = require('../lib/lock') -const knex = require('../lib/knex') -const siteDescriptions = require('./site-descriptions') -const {doCrawl, doCheckpoint, emitProgressEvent, getMatchingChangesInOrder, generateTimeFilename, ensureDirectory, normalizeSchemaUrl, toOrigin} = require('./util') -const mediaSchema = require('./json-schemas/media') - -// constants -// = - -const TABLE_VERSION = 1 -const JSON_TYPE = 'unwalled.garden/media' -const JSON_PATH_REGEX = /^\/data\/media\/([^/]+)\.json$/i - -// typedefs -// = - -/** - * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive - * @typedef {import('./util').CrawlSourceRecord} CrawlSourceRecord - * @typedef { import("./site-descriptions").SiteDescription } SiteDescription - * - * @typedef {Object} Media - * @prop {string} pathname - * @prop {string} subtype - * @prop {string} href - * @prop {string} title - * @prop {string} description - * @prop {string[]} tags - * @prop {string} createdAt - * @prop {string} updatedAt - * @prop {SiteDescription} author - * @prop {string} visibility - */ - -// globals -// = - -const events = new Events() -const ajv = (new Ajv()) -const validateMedia = ajv.compile(mediaSchema) - -// exported api -// = - -exports.on = events.on.bind(events) -exports.addListener = events.addListener.bind(events) -exports.removeListener = events.removeListener.bind(events) - -/** - * @description - * Crawl the given site for media. - * - * @param {DaemonDatArchive} archive - site to crawl. - * @param {CrawlSourceRecord} crawlSource - internal metadata about the crawl target. - * @returns {Promise} - */ -exports.crawlSite = async function (archive, crawlSource) { - return doCrawl(archive, crawlSource, 'crawl_media', TABLE_VERSION, async ({changes, resetRequired}) => { - const supressEvents = resetRequired === true // dont emit when replaying old info - logger.silly('Crawling media', {details: {url: archive.url, numChanges: changes.length, resetRequired}}) - if (resetRequired) { - // reset all data - logger.debug('Resetting dataset', {details: {url: archive.url}}) - await db.run(` - DELETE FROM crawl_media WHERE crawlSourceId = ? - `, [crawlSource.id]) - await doCheckpoint('crawl_media', TABLE_VERSION, crawlSource, 0) - } - - // collect changed media - var changedMedia = getMatchingChangesInOrder(changes, JSON_PATH_REGEX) - if (changedMedia.length) { - logger.verbose('Collected new/changed media files', {details: {url: archive.url, changedMedia: changedMedia.map(p => p.name)}}) - } else { - logger.debug('No new media-files found', {details: {url: archive.url}}) - } - emitProgressEvent(archive.url, 'crawl_media', 0, changedMedia.length) - - // read and apply each media in order - var progress = 0 - for (let changedMediaItem of changedMedia) { - // TODO Currently the crawler will abort reading the feed if any media fails to load - // this means that a single unreachable file can stop the forward progress of media indexing - // to solve this, we need to find a way to tolerate unreachable media-files without losing our ability to efficiently detect new media - // -prf - if (changedMediaItem.type === 'del') { - // delete - await db.run(` - DELETE FROM crawl_media WHERE crawlSourceId = ? AND pathname = ? - `, [crawlSource.id, changedMediaItem.name]) - events.emit('media-removed', archive.url) - } else { - // read - let mediaString - try { - mediaString = await archive.pda.readFile(changedMediaItem.name, 'utf8') - } catch (err) { - logger.warn('Failed to read media file, aborting', {details: {url: archive.url, name: changedMediaItem.name, err}}) - return // abort indexing - } - - // parse and validate - let media - try { - media = JSON.parse(mediaString) - let valid = validateMedia(media) - if (!valid) throw ajv.errorsText(validateMedia.errors) - } catch (err) { - logger.warn('Failed to parse media file, skipping', {details: {url: archive.url, name: changedMediaItem.name, err}}) - continue // skip - } - - // massage the media - media.subtype = normalizeSchemaUrl(media.subtype) - media.createdAt = Number(new Date(media.createdAt)) - media.updatedAt = Number(new Date(media.updatedAt)) - if (!media.description) media.description = '' // optional - if (!media.tags) media.tags = [] // optional - if (isNaN(media.updatedAt)) media.updatedAt = 0 // optional - - // upsert - let mediaId = 0 - let existingMedia = await db.get(knex('crawl_media') - .select('id') - .where({ - crawlSourceId: crawlSource.id, - pathname: changedMediaItem.name - }) - ) - if (existingMedia) { - await db.run(knex('crawl_media') - .where({ - crawlSourceId: crawlSource.id, - pathname: changedMediaItem.name - }).update({ - crawledAt: Date.now(), - subtype: media.subtype, - href: media.href, - title: media.title, - description: media.description, - createdAt: media.createdAt, - updatedAt: media.updatedAt, - }) - ) - mediaId = existingMedia.id - events.emit('media-updated', archive.url) - } else { - let res = await db.run(knex('crawl_media') - .insert({ - crawlSourceId: crawlSource.id, - pathname: changedMediaItem.name, - crawledAt: Date.now(), - subtype: media.subtype, - href: media.href, - title: media.title, - description: media.description, - createdAt: media.createdAt, - updatedAt: media.updatedAt, - }) - ) - mediaId = +res.lastID - events.emit('media-added', archive.url) - } - await db.run(`DELETE FROM crawl_media_tags WHERE crawlMediaId = ?`, [mediaId]) - for (let tag of media.tags) { - await db.run(`INSERT OR IGNORE INTO crawl_tags (tag) VALUES (?)`, [tag]) - let tagRow = await db.get(`SELECT id FROM crawl_tags WHERE tag = ?`, [tag]) - await db.run(`INSERT INTO crawl_media_tags (crawlMediaId, crawlTagId) VALUES (?, ?)`, [mediaId, tagRow.id]) - } - } - - // checkpoint our progress - await doCheckpoint('crawl_media', TABLE_VERSION, crawlSource, changedMediaItem.version) - emitProgressEvent(archive.url, 'crawl_media', ++progress, changedMedia.length) - } - logger.silly(`Finished crawling media`, {details: {url: archive.url}}) - }) -} - -/** - * @description - * List crawled media. - * - * @param {Object} [opts] - * @param {Object} [opts.filters] - * @param {string|string[]} [opts.filters.authors] - * @param {string|string[]} [opts.filters.hrefs] - * @param {string|string[]} [opts.filters.subtypes] - * @param {string|string[]} [opts.filters.tags] - * @param {string} [opts.filters.visibility] - * @param {string} [opts.sortBy] - * @param {number} [opts.offset=0] - * @param {number} [opts.limit] - * @param {boolean} [opts.reverse] - * @returns {Promise>} - */ -exports.list = async function (opts) { - // TODO: handle visibility - // TODO: sortBy options - - // validate & parse params - if (opts && 'sortBy' in opts) assert(typeof opts.sortBy === 'number', 'SortBy must be a string') - if (opts && 'offset' in opts) assert(typeof opts.offset === 'number', 'Offset must be a number') - if (opts && 'limit' in opts) assert(typeof opts.limit === 'number', 'Limit must be a number') - if (opts && 'reverse' in opts) assert(typeof opts.reverse === 'boolean', 'Reverse must be a boolean') - if (opts && opts.filters) { - if ('authors' in opts.filters) { - if (Array.isArray(opts.filters.authors)) { - assert(opts.filters.authors.every(v => typeof v === 'string'), 'Authors filter must be a string or array of strings') - } else { - assert(typeof opts.filters.authors === 'string', 'Authors filter must be a string or array of strings') - opts.filters.authors = [opts.filters.authors] - } - opts.filters.authors = opts.filters.authors.map(url => toOrigin(url, true)) - } - if ('hrefs' in opts.filters) { - if (Array.isArray(opts.filters.hrefs)) { - assert(opts.filters.hrefs.every(v => typeof v === 'string'), 'Hrefs filter must be a string or array of strings') - } else { - assert(typeof opts.filters.hrefs === 'string', 'Hrefs filter must be a string or array of strings') - opts.filters.hrefs = [opts.filters.hrefs] - } - } - if ('subtypes' in opts.filters) { - if (Array.isArray(opts.filters.subtypes)) { - assert(opts.filters.subtypes.every(v => typeof v === 'string'), 'Subtypes filter must be a string or array of strings') - } else { - assert(typeof opts.filters.subtypes === 'string', 'Subtypes filter must be a string or array of strings') - opts.filters.subtypes = [opts.filters.subtypes] - } - opts.filters.subtypes = opts.filters.subtypes.map(normalizeSchemaUrl) - } - if ('tags' in opts.filters) { - if (Array.isArray(opts.filters.tags)) { - assert(opts.filters.tags.every(v => typeof v === 'string'), 'Tags filter must be a string or array of strings') - } else { - assert(typeof opts.filters.tags === 'string', 'Tags filter must be a string or array of strings') - opts.filters.tags = [opts.filters.tags] - } - } - } - - // build query - var sql = knex('crawl_media') - .select('crawl_media.*') - .select('crawl_sources.url as crawlSourceUrl') - .select(knex.raw('group_concat(crawl_tags.tag, ",") as tags')) - .innerJoin('crawl_sources', 'crawl_sources.id', '=', 'crawl_media.crawlSourceId') - .leftJoin('crawl_media_tags', 'crawl_media_tags.crawlMediaId', '=', 'crawl_media.id') - .leftJoin('crawl_tags', 'crawl_media_tags.crawlTagId', '=', 'crawl_tags.id') - .groupBy('crawl_media.id') - .orderBy('crawl_media.createdAt', opts.reverse ? 'DESC' : 'ASC') - if (opts && opts.filters && opts.filters.authors) { - sql = sql.whereIn('crawl_sources.url', opts.filters.authors) - } - if (opts && opts.filters && opts.filters.hrefs) { - sql = sql.whereIn('crawl_media.href', opts.filters.hrefs) - } - if (opts && opts.filters && opts.filters.subtypes) { - sql = sql.whereIn('crawl_media.subtype', opts.filters.subtypes) - } - if (opts && opts.limit) sql = sql.limit(opts.limit) - if (opts && opts.offset) sql = sql.offset(opts.offset) - - // execute query - var rows = await db.all(sql) - var media = await Promise.all(rows.map(massageMediaRow)) - - // apply tags filter - if (opts && opts.filters && opts.filters.tags) { - const someFn = t => opts.filters.tags.includes(t) - media = media.filter(m => m.tags.some(someFn)) - } - - return media -} - -/** - * @description - * Get crawled media. - * - * @param {string} url - The URL of the media - * @returns {Promise} - */ -const get = exports.get = async function (url) { - // validate & parse params - var urlParsed - if (url) { - try { urlParsed = new URL(url) } - catch (e) { throw new Error('Invalid URL: ' + url) } - } - - // build query - var sql = knex('crawl_media') - .select('crawl_media.*') - .select('crawl_sources.url as crawlSourceUrl') - .select(knex.raw('group_concat(crawl_tags.tag, ",") as tags')) - .innerJoin('crawl_sources', function () { - this.on('crawl_sources.id', '=', 'crawl_media.crawlSourceId') - .andOn('crawl_sources.url', '=', knex.raw('?', `${urlParsed.protocol}//${urlParsed.hostname}`)) - }) - .leftJoin('crawl_media_tags', 'crawl_media_tags.crawlMediaId', '=', 'crawl_media.id') - .leftJoin('crawl_tags', 'crawl_tags.id', '=', 'crawl_media_tags.crawlTagId') - .where('crawl_media.pathname', urlParsed.pathname) - .groupBy('crawl_media.id') - - // execute query - return await massageMediaRow(await db.get(sql)) -} - -/** - * @description - * Create a new media. - * - * @param {DaemonDatArchive} archive - where to write the media to. - * @param {Object} media - * @param {string} media.subtype - * @param {string} media.href - * @param {string} media.title - * @param {string} media.description - * @param {string[]} media.tags - * @param {string} media.visibility - * @returns {Promise} url - */ -exports.add = async function (archive, media) { - // TODO visibility - - var mediaObject = { - type: JSON_TYPE, - subtype: normalizeSchemaUrl(media.subtype), - href: media.href, - title: media.title, - description: media.description, - tags: media.tags, - createdAt: (new Date()).toISOString() - } - var valid = validateMedia(mediaObject) - if (!valid) throw ajv.errorsText(validateMedia.errors) - - var filename = generateTimeFilename() - var filepath = `/data/media/${filename}.json` - await ensureDirectory(archive, '/data') - await ensureDirectory(archive, '/data/media') - await archive.pda.writeFile(filepath, JSON.stringify(mediaObject, null, 2)) - await crawler.crawlSite(archive) - return archive.url + filepath -} - -/** - * @description - * Update the content of an existing media. - * - * @param {DaemonDatArchive} archive - where to write the media to. - * @param {string} pathname - the pathname of the media. - * @param {Object} media - * @param {string} [media.subtype] - * @param {string} [media.href] - * @param {string} [media.title] - * @param {string} [media.description] - * @param {string[]} [media.tags] - * @param {string} [media.visibility] - * @returns {Promise} - */ -exports.edit = async function (archive, pathname, media) { - // TODO visibility - - var release = await lock('crawler:media:' + archive.url) - try { - // fetch media - var existingMedia = await get(archive.url + pathname) - if (!existingMedia) throw new Error('Media not found') - - // update media content - var mediaObject = { - type: JSON_TYPE, - subtype: normalizeSchemaUrl(('subtype' in media) ? media.subtype : existingMedia.subtype), - href: ('href' in media) ? media.href : existingMedia.href, - title: ('title' in media) ? media.title : existingMedia.title, - description: ('description' in media) ? media.description : existingMedia.description, - tags: ('tags' in media) ? media.tags : existingMedia.tags, - createdAt: existingMedia.createdAt, - updatedAt: (new Date()).toISOString() - } - - // validate - var valid = validateMedia(mediaObject) - if (!valid) throw ajv.errorsText(validateMedia.errors) - - // write - await archive.pda.writeFile(pathname, JSON.stringify(mediaObject, null, 2)) - await crawler.crawlSite(archive) - } finally { - release() - } -} - -/** - * @description - * Delete an existing media - * - * @param {DaemonDatArchive} archive - where to write the media to. - * @param {string} pathname - the pathname of the media. - * @returns {Promise} - */ -exports.remove = async function (archive, pathname) { - assert(typeof pathname === 'string', 'Remove() must be provided a valid URL string') - await archive.pda.unlink(pathname) - await crawler.crawlSite(archive) -} - -// internal methods -// = - -/** - * @param {Object} row - * @returns {Promise} - */ -async function massageMediaRow (row) { - if (!row) return null - var author = await siteDescriptions.getBest({subject: row.crawlSourceUrl}) - if (!author) { - author = { - url: row.crawlSourceUrl, - title: '', - description: '', - type: [], - thumbUrl: `${row.crawlSourceUrl}/thumb`, - descAuthor: {url: null} - } - } - return { - pathname: row.pathname, - author, - subtype: row.subtype, - href: row.href, - title: row.title, - description: row.description, - tags: row.tags ? row.tags.split(',').filter(Boolean) : [], - createdAt: new Date(row.createdAt).toISOString(), - updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null, - visibility: 'public' // TODO visibility - } -} diff --git a/web-apis/bg.js b/web-apis/bg.js index c25cb1e6..a0a0c7c5 100644 --- a/web-apis/bg.js +++ b/web-apis/bg.js @@ -37,7 +37,6 @@ const libraryManifest = require('./manifests/external/library') const searchManifest = require('./manifests/external/search') const commentsManifest = require('./manifests/external/unwalled-garden-comments') const followsManifest = require('./manifests/external/unwalled-garden-follows') -const mediaManifest = require('./manifests/external/unwalled-garden-media') const postsManifest = require('./manifests/external/unwalled-garden-posts') const profilesManifest = require('./manifests/external/unwalled-garden-profiles') const reactionsManifest = require('./manifests/external/unwalled-garden-reactions') @@ -55,7 +54,6 @@ const libraryAPI = require('./bg/library') const searchAPI = require('./bg/search') const commentsAPI = require('./bg/unwalled-garden-comments') const followsAPI = require('./bg/unwalled-garden-follows') -const mediaAPI = require('./bg/unwalled-garden-media') const postsAPI = require('./bg/unwalled-garden-posts') const profilesAPI = require('./bg/unwalled-garden-profiles') const reactionsAPI = require('./bg/unwalled-garden-reactions') @@ -100,7 +98,6 @@ exports.setup = function () { globals.rpcAPI.exportAPI('search', searchManifest, searchAPI, secureOnly) globals.rpcAPI.exportAPI('unwalled-garden-comments', commentsManifest, commentsAPI, secureOnly) globals.rpcAPI.exportAPI('unwalled-garden-follows', followsManifest, followsAPI, secureOnly) - globals.rpcAPI.exportAPI('unwalled-garden-media', mediaManifest, mediaAPI, secureOnly) globals.rpcAPI.exportAPI('unwalled-garden-posts', postsManifest, postsAPI, secureOnly) globals.rpcAPI.exportAPI('unwalled-garden-profiles', profilesManifest, profilesAPI, secureOnly) globals.rpcAPI.exportAPI('unwalled-garden-reactions', reactionsManifest, reactionsAPI, secureOnly) diff --git a/web-apis/bg/unwalled-garden-media.js b/web-apis/bg/unwalled-garden-media.js deleted file mode 100644 index 5ee72ef2..00000000 --- a/web-apis/bg/unwalled-garden-media.js +++ /dev/null @@ -1,231 +0,0 @@ -const globals = require('../../globals') -const assert = require('assert') -const {URL} = require('url') -const dat = require('../../dat') -const mediaCrawler = require('../../crawler/media') -const sessionPerms = require('../../lib/session-perms') - -// typedefs -// = - -/** - * @typedef {Object} MediaAuthorPublicAPIRecord - * @prop {string} url - * @prop {string} title - * @prop {string} description - * @prop {string[]} type - * - * @typedef {Object} MediaPublicAPIRecord - * @prop {string} url - * @prop {string} subtype - * @prop {string} href - * @prop {string} title - * @prop {string} description - * @prop {string[]} tags - * @prop {string} createdAt - * @prop {string} updatedAt - * @prop {MediaAuthorPublicAPIRecord} author - * @prop {string} visibility - */ - -// exported api -// = - -module.exports = { - /** - * @param {Object} [opts] - * @param {Object} [opts.filters] - * @param {string|string[]} [opts.filters.authors] - * @param {string|string[]} [opts.filters.hrefs] - * @param {string|string[]} [opts.filters.subtypes] - * @param {string|string[]} [opts.filters.tags] - * @param {string} [opts.filters.visibility] - * @param {string} [opts.sortBy] - * @param {number} [opts.offset=0] - * @param {number} [opts.limit] - * @param {boolean} [opts.reverse] - * @returns {Promise} - */ - async list (opts) { - await sessionPerms.assertCan(this.sender, 'unwalled.garden/api/media', 'read') - opts = (opts && typeof opts === 'object') ? opts : {} - if (opts && 'sortBy' in opts) assert(typeof opts.sortBy === 'string', 'SortBy must be a string') - if (opts && 'offset' in opts) assert(typeof opts.offset === 'number', 'Offset must be a number') - if (opts && 'limit' in opts) assert(typeof opts.limit === 'number', 'Limit must be a number') - if (opts && 'reverse' in opts) assert(typeof opts.reverse === 'boolean', 'Reverse must be a boolean') - if (opts && opts.filters) { - if ('authors' in opts.filters) { - if (Array.isArray(opts.filters.authors)) { - assert(opts.filters.authors.every(v => typeof v === 'string'), 'Authors filter must be a string or array of strings') - } else { - assert(typeof opts.filters.authors === 'string', 'Authors filter must be a string or array of strings') - } - } - if ('hrefs' in opts.filters) { - if (Array.isArray(opts.filters.hrefs)) { - assert(opts.filters.hrefs.every(v => typeof v === 'string'), 'Hrefs filter must be a string or array of strings') - } else { - assert(typeof opts.filters.hrefs === 'string', 'Hrefs filter must be a string or array of strings') - } - } - if ('subtypes' in opts.filters) { - if (Array.isArray(opts.filters.subtypes)) { - assert(opts.filters.subtypes.every(v => typeof v === 'string'), 'Subtypes filter must be a string or array of strings') - } else { - assert(typeof opts.filters.subtypes === 'string', 'Subtypes filter must be a string or array of strings') - } - } - if ('tags' in opts.filters) { - if (Array.isArray(opts.filters.tags)) { - assert(opts.filters.tags.every(v => typeof v === 'string'), 'Tags filter must be a string or array of strings') - } else { - assert(typeof opts.filters.tags === 'string', 'Tags filter must be a string or array of strings') - } - } - if ('visibility' in opts.filters) { - assert(typeof opts.filters.visibility === 'string', 'Visibility filter must be a string') - } - } - var media = await mediaCrawler.list(opts) - return Promise.all(media.map(massageMediaRecord)) - }, - - /** - * @param {string} url - * @returns {Promise} - */ - async get (url) { - await sessionPerms.assertCan(this.sender, 'unwalled.garden/api/media', 'read') - return massageMediaRecord(await mediaCrawler.get(url)) - }, - - /** - * @param {Object} media - * @param {string} media.subtype - * @param {string} media.href - * @param {string} media.title - * @param {string} media.description - * @param {string[]} media.tags - * @param {string} media.visibility - * @returns {Promise} - */ - async add (media) { - await sessionPerms.assertCan(this.sender, 'unwalled.garden/api/media', 'write') - var userArchive = await sessionPerms.getSessionUserArchive(this.sender) - - assert(media && typeof media === 'object', 'The `media` parameter must be a string or object') - assert(media.subtype && typeof media.subtype === 'string', 'The `media.subtype` parameter must be a non-empty URL string') - assert(media.href && typeof media.href === 'string', 'The `media.href` parameter must be a non-empty URL string') - assert(media.title && typeof media.title === 'string', 'The `media.title` parameter must be a non-empty string') - if ('description' in media) assert(typeof media.description === 'string', 'The `media.description` parameter must be a string') - if ('tags' in media) assert(media.tags.every(tag => typeof tag === 'string'), 'The `media.tags` parameter must be an array of strings') - if ('visibility' in media) assert(typeof media.visibility === 'string', 'The `media.visibility` parameter must be "public" or "private"') - - // default values - if (!media.visibility) { - media.visibility = 'public' - } - - var url = await mediaCrawler.add(userArchive, media) - return massageMediaRecord(await mediaCrawler.get(url)) - }, - - /** - * @param {string} url - * @param {Object} media - * @param {string} media.subtype - * @param {string} media.href - * @param {string} media.title - * @param {string} media.description - * @param {string[]} media.tags - * @param {string} media.visibility - * @returns {Promise} - */ - async edit (url, media) { - await sessionPerms.assertCan(this.sender, 'unwalled.garden/api/media', 'write') - var userArchive = await sessionPerms.getSessionUserArchive(this.sender) - - assert(url && typeof url === 'string', 'The `url` parameter must be a valid URL') - assert(media && typeof media === 'object', 'The `media` parameter must be an object') - if ('subtype' in media) assert(typeof media.subtype === 'string', 'The `media.subtype` parameter must be a URL string') - if ('href' in media) assert(typeof media.href === 'string', 'The `media.href` parameter must be a URL string') - if ('title' in media) assert(media.title && typeof media.title === 'string', 'The `media.title` parameter must be a non-empty string') - if ('description' in media) assert(typeof media.description === 'string', 'The `media.description` parameter must be a string') - if ('tags' in media) assert(media.tags.every(tag => typeof tag === 'string'), 'The `media.tags` parameter must be an array of strings') - if ('visibility' in media) assert(typeof media.visibility === 'string', 'The `media.visibility` parameter must be "public" or "private"') - - var filepath = await urlToFilepath(url, userArchive.url) - await mediaCrawler.edit(userArchive, filepath, media) - return massageMediaRecord(await mediaCrawler.get(userArchive.url + filepath)) - }, - - /** - * @param {string} url - * @returns {Promise} - */ - async remove (url) { - await sessionPerms.assertCan(this.sender, 'unwalled.garden/api/media', 'write') - var userArchive = await sessionPerms.getSessionUserArchive(this.sender) - - assert(url && typeof url === 'string', 'The `url` parameter must be a valid URL') - - var filepath = await urlToFilepath(url, userArchive.url) - await mediaCrawler.remove(userArchive, filepath) - } -} - -// internal methods -// = - -/** - * Tries to parse the URL and return the pathname. If fails, assumes the string was a pathname. - * @param {string} url - * @returns {Promise} - */ -async function urlToFilepath (url, origin) { - var urlp - var filepath - try { - // if `url` is a full URL, extract the path - urlp = new URL(url) - filepath = urlp.pathname - } catch (e) { - // assume `url` is a path - return url - } - - // double-check the origin - var key = await dat.dns.resolveName(urlp.hostname) - var urlp2 = new URL(origin) - if (key !== urlp2.hostname) { - throw new Error('Unable to edit media on other sites than your own') - } - - return filepath -} - -/** - * @param {Object} media - * @returns {MediaPublicAPIRecord} - */ -function massageMediaRecord (media) { - if (!media) return null - var url = media.author.url + media.pathname - return { - url, - subtype: media.subtype, - href: media.href, - title: media.title, - description: media.description, - tags: media.tags, - createdAt: media.createdAt, - updatedAt: media.updatedAt, - author: { - url: media.author.url, - title: media.author.title, - description: media.author.description, - type: media.author.type - }, - visibility: media.visibility - } -} diff --git a/web-apis/fg/navigator-import.js b/web-apis/fg/navigator-import.js index 35906fdb..3e56e279 100644 --- a/web-apis/fg/navigator-import.js +++ b/web-apis/fg/navigator-import.js @@ -32,11 +32,6 @@ const APIs = { manifest: require('../manifests/external/unwalled-garden-follows'), create: makeCreateFn('unwalled-garden-follows') }, - // TODO readd when stablized -prf - // 'unwalled-garden-media': { - // manifest: require('../manifests/external/unwalled-garden-media'), - // create: makeCreateFn('unwalled-garden-media') - // }, 'unwalled-garden-posts': { manifest: require('../manifests/external/unwalled-garden-posts'), create: makeCreateFn('unwalled-garden-posts') diff --git a/web-apis/manifests/external/unwalled-garden-media.js b/web-apis/manifests/external/unwalled-garden-media.js deleted file mode 100644 index 06aeb28a..00000000 --- a/web-apis/manifests/external/unwalled-garden-media.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - list: 'promise', - get: 'promise', - add: 'promise', - edit: 'promise', - remove: 'promise' -} \ No newline at end of file From f48d3995285fbf8c022e86bffec4cf6af5c8937d Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Wed, 28 Aug 2019 15:05:12 -0500 Subject: [PATCH 35/74] Remove applications --- applications.js | 69 -------- index.js | 1 - web-apis/bg.js | 3 - web-apis/bg/applications.js | 186 -------------------- web-apis/manifests/internal/applications.js | 9 - 5 files changed, 268 deletions(-) delete mode 100644 applications.js delete mode 100644 web-apis/bg/applications.js delete mode 100644 web-apis/manifests/internal/applications.js diff --git a/applications.js b/applications.js deleted file mode 100644 index 654a0651..00000000 --- a/applications.js +++ /dev/null @@ -1,69 +0,0 @@ -const sessionPerms = require('./lib/session-perms') -const knex = require('./lib/knex') -const db = require('./dbs/profile-data-db') -const sitedataDb = require('./dbs/sitedata') -const dat = require('./dat') - -// typedefs -// = - -/** - * @typedef {Object} ApplicationPermission - * @prop {string} id - * @prop {string[]} caps - * @prop {string} description - * - * @typedef {Object} ApplicationState - * @prop {string} url - * @prop {ApplicationPermission[]} permissions - * @prop {boolean} installed - * @prop {boolean} enabled - * @prop {string} installedAt - */ - -// exported api -// = - -/** - * @param {Object} opts - * @param {number} opts.userId - * @param {string} opts.url - * @returns {Promise} - */ -exports.getApplicationState = async function ({userId, url}) { - url = await dat.library.getPrimaryUrl(url) - var record = await db.get(knex('installed_applications').where({userId, url})) - if (record) { - record.installed = true - } else { - record = { - url, - installed: false, - enabled: false, - installedAt: null - } - } - record.permissions = await sitedataDb.getAppPermissions(record.url) - return massageAppRecord(record) -} - -// internal methods -// = - -/** - * @param {Object} record - * @returns {ApplicationState} - */ -function massageAppRecord (record) { - return { - url: record.url, - permissions: Object.entries(record.permissions).map(([id, caps]) => ({ - id, - caps, - description: sessionPerms.describePerm(id, caps) - })), - installed: record.installed, - enabled: Boolean(record.enabled), - installedAt: record.createdAt ? (new Date(record.createdAt)).toISOString() : null - } -} \ No newline at end of file diff --git a/index.js b/index.js index f063ec3d..1da37121 100644 --- a/index.js +++ b/index.js @@ -3,7 +3,6 @@ const {join} = require('path') const debugLogger = require('./lib/debug-logger') const globals = require('./globals') const logger = require('./logger') -const applications = require('./applications') const {getEnvVar} = require('./lib/env') const dat = require('./dat') const dbs = require('./dbs') diff --git a/web-apis/bg.js b/web-apis/bg.js index a0a0c7c5..546a8726 100644 --- a/web-apis/bg.js +++ b/web-apis/bg.js @@ -4,7 +4,6 @@ const SECURE_ORIGIN_REGEX = /^(beaker:|dat:|https:|http:\/\/localhost(\/|:))/i // internal manifests const loggerManifest = require('./manifests/internal/logger') -const applicationsManifest = require('./manifests/internal/applications') const archivesManifest = require('./manifests/internal/archives') const beakerBrowserManifest = require('./manifests/internal/browser') const downloadsManifest = require('./manifests/internal/downloads') @@ -17,7 +16,6 @@ const usersManifest = require('./manifests/internal/users') // internal apis const loggerAPI = require('../logger').WEBAPI -const applicationsAPI = require('./bg/applications') const archivesAPI = require('./bg/archives') const historyAPI = require('./bg/history') const sitedataAPI = require('../dbs/sitedata').WEBAPI @@ -76,7 +74,6 @@ const experimentalGlobalFetchAPI = require('./bg/experimental/global-fetch') exports.setup = function () { // internal apis globals.rpcAPI.exportAPI('logger', loggerManifest, loggerAPI, internalOnly) - globals.rpcAPI.exportAPI('applications', applicationsManifest, applicationsAPI, internalOnly) globals.rpcAPI.exportAPI('archives', archivesManifest, archivesAPI, internalOnly) globals.rpcAPI.exportAPI('beaker-browser', beakerBrowserManifest, globals.browserWebAPI, internalOnly) globals.rpcAPI.exportAPI('downloads', downloadsManifest, globals.downloadsWebAPI, internalOnly) diff --git a/web-apis/bg/applications.js b/web-apis/bg/applications.js deleted file mode 100644 index 108e2b29..00000000 --- a/web-apis/bg/applications.js +++ /dev/null @@ -1,186 +0,0 @@ -const globals = require('../../globals') -const dat = require('../../dat') -const sessionPerms = require('../../lib/session-perms') -const sitedataDb = require('../../dbs/sitedata') -const knex = require('../../lib/knex') -const db = require('../../dbs/profile-data-db') - -// typedefs -// = - -/** - * @typedef {import('../../users').User} User - * - * @typedef {Object} WebAPIApplicationPermission - * @prop {string} id - * @prop {string[]} caps - * @prop {string} description - * - * @typedef {Object} WebAPIApplication - * @prop {string} url - * @prop {string} title - * @prop {string} description - * @prop {WebAPIApplicationPermission[]} permissions - * @prop {boolean} installed - * @prop {boolean} enabled - * @prop {string} installedAt - */ - -// exported api -// = - -module.exports = { - /** - * @param {string} url - * @returns {Promise} - */ - async getInfo (url) { - url = toDatOrigin(url) - var userId = await sessionPerms.getSessionUserId(this.sender) - var record = await db.get(knex('installed_applications').where({userId, url})) - var archiveInfo = await dat.library.getArchiveInfo(url) - return massageArchiveInfo(archiveInfo, record) - }, - - /** - * @param {string} url - * @returns {Promise} - */ - async install (url) { - url = toDatOrigin(url) - var userId = await sessionPerms.getSessionUserId(this.sender) - var archiveInfo = await dat.library.getArchiveInfo(url) - var record = await db.get(knex('installed_applications').where({userId, url})) - if (!record) { - await db.run(knex('installed_applications').insert({ - userId, - enabled: 1, - url, - createdAt: Date.now() - })) - } - // await sitedataDb.setAppPermissions(url, getArchivePerms(archiveInfo)) DEPRECATED - }, - - /** - * @param {string} url - * @returns {Promise} - */ - async requestInstall (url) { - // run the install modal - try { - return globals.uiAPI.showModal(this.sender, 'install-application', {url}) - } catch (e) { - console.log('ohno', e) - return false - } - }, - - /** - * @returns {Promise} - */ - async list () { - var userId = await sessionPerms.getSessionUserId(this.sender) - var records = await db.all(knex('installed_applications').where({userId})) - await Promise.all(records.map(async (record) => { - var archiveInfo = await dat.library.getArchiveInfo(record.url) - record.title = archiveInfo.title - record.description = archiveInfo.description - // record.permissions = await sitedataDb.getAppPermissions(record.url) DEPRECATED - })) - return records.map(massageAppRecord) - }, - - /** - * @param {string} url - * @returns {Promise} - */ - async enable (url) { - url = toDatOrigin(url) - var userId = await sessionPerms.getSessionUserId(this.sender) - await db.run(knex('installed_applications').update({enabled: 1}).where({userId, url})) - }, - - /** - * @param {string} url - * @returns {Promise} - */ - async disable (url) { - url = toDatOrigin(url) - var userId = await sessionPerms.getSessionUserId(this.sender) - await db.run(knex('installed_applications').update({enabled: 0}).where({userId, url})) - }, - - /** - * @param {string} url - * @returns {Promise} - */ - async uninstall (url) { - url = toDatOrigin(url) - var userId = await sessionPerms.getSessionUserId(this.sender) - // await sitedataDb.setAppPermissions(url, {}) DEPRECATED - await db.run(knex('installed_applications').delete().where({userId, url})) - } -} - -// internal methods -// = - -function toDatOrigin (url) { - try { - var urlParsed = new URL(url) - } catch (e) { - throw new Error('Invalid URL: ' + url) - } - if (urlParsed.protocol !== 'dat:') throw new Error('Can only install dat applications') - return `${urlParsed.protocol}//${urlParsed.hostname}`.replace('+preview', '') -} - -function getArchivePerms (archiveInfo) { - try { - return archiveInfo.manifest.application.permissions - } catch (e) { - return [] - } -} - -/** - * @param {Object} archiveInfo - * @param {Object} record - * @returns {WebAPIApplication} - */ -function massageArchiveInfo (archiveInfo, record) { - return { - url: archiveInfo.url, - title: archiveInfo.title, - description: archiveInfo.description, - permissions: Object.entries(getArchivePerms(archiveInfo)).map(([id, caps]) => ({ - id, - caps, - description: sessionPerms.describePerm(id, caps) - })), - installed: !!record, - enabled: Boolean(record && record.enabled), - installedAt: record ? (new Date(record.createdAt)).toISOString() : null - } -} - -/** - * @param {Object} record - * @returns {WebAPIApplication} - */ -function massageAppRecord (record) { - return { - url: record.url, - title: record.title, - description: record.description, - permissions: Object.entries(record.permissions).map(([id, caps]) => ({ - id, - caps, - description: sessionPerms.describePerm(id, caps) - })), - installed: true, - enabled: Boolean(record.enabled), - installedAt: (new Date(record.createdAt)).toISOString() - } -} \ No newline at end of file diff --git a/web-apis/manifests/internal/applications.js b/web-apis/manifests/internal/applications.js deleted file mode 100644 index 5d58a9d0..00000000 --- a/web-apis/manifests/internal/applications.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - getInfo: 'promise', - install: 'promise', - requestInstall: 'promise', - list: 'promise', - enable: 'promise', - disable: 'promise', - uninstall: 'promise', -} From 4f86a52ffb4f959fd5c4f354305184d7dc44d34f Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Wed, 28 Aug 2019 15:22:16 -0500 Subject: [PATCH 36/74] Big rewrite: move the dat library to the filesystem; rename crawler dir to uwg; rename users dir to filesystem; remove some old code (templates, archive-drafts); remove folder-sync and preview-mode --- README.md | 2 +- dat/{library.js => archives.js} | 249 +++------ dat/daemon.js | 2 + dat/debugging.js | 2 +- dat/dns.js | 4 +- dat/folder-sync.js | 614 --------------------- dat/garbage-collector.js | 93 ---- dat/index.js | 9 +- dat/protocol.js | 28 +- dat/watchlist.js | 6 +- dbs/archive-drafts.js | 30 - dbs/archives.js | 402 +------------- dbs/dat-dns.js | 6 +- dbs/index.js | 2 - dbs/schemas/profile-data.sql.js | 65 +-- dbs/templates.js | 69 --- filesystem/const.js | 14 + filesystem/dat-library.js | 412 ++++++++++++++ users/filesystem.js => filesystem/index.js | 81 ++- {users => filesystem}/site-sessions.js | 0 filesystem/trash.js | 129 +++++ users/index.js => filesystem/users.js | 72 +-- index.js | 17 +- lib/const.js | 18 +- lib/scoped-fses.js | 2 +- lib/session-perms.js | 14 +- scripts/import-schemas.js | 2 +- {crawler => uwg}/bookmarks.js | 24 +- {crawler => uwg}/comments.js | 26 +- {crawler => uwg}/follows.js | 22 +- {crawler => uwg}/index.js | 34 +- {crawler => uwg}/json-schemas/bookmark.js | 0 {crawler => uwg}/json-schemas/comment.js | 0 {crawler => uwg}/json-schemas/follows.js | 0 {crawler => uwg}/json-schemas/post.js | 0 {crawler => uwg}/json-schemas/reaction.js | 0 {crawler => uwg}/json-schemas/vote.js | 0 {crawler => uwg}/posts.js | 23 +- {crawler => uwg}/reactions.js | 24 +- {crawler => uwg}/search.js | 10 +- {crawler => uwg}/site-descriptions.js | 12 +- {crawler => uwg}/tags.js | 8 +- {crawler => uwg}/util.js | 12 +- {crawler => uwg}/votes.js | 24 +- web-apis/bg.js | 8 +- web-apis/bg/archives.js | 316 +++-------- web-apis/bg/bookmarks.js | 10 +- web-apis/bg/dat-archive.js | 134 ++--- web-apis/bg/experimental/dat-peers.js | 20 +- web-apis/bg/library.js | 318 ----------- web-apis/bg/navigator-filesystem.js | 2 +- web-apis/bg/navigator-session.js | 8 +- web-apis/bg/navigator.js | 16 +- web-apis/bg/search.js | 4 +- web-apis/bg/templates.js | 22 - web-apis/bg/unwalled-garden-comments.js | 18 +- web-apis/bg/unwalled-garden-follows.js | 12 +- web-apis/bg/unwalled-garden-posts.js | 16 +- web-apis/bg/unwalled-garden-profiles.js | 26 +- web-apis/bg/unwalled-garden-reactions.js | 18 +- web-apis/bg/unwalled-garden-tags.js | 10 +- web-apis/bg/unwalled-garden-votes.js | 16 +- web-apis/bg/users.js | 13 +- web-apis/bg/watchlist.js | 1 - web-apis/fg/beaker.js | 40 +- web-apis/fg/navigator-import.js | 13 - web-apis/manifests/external/library.js | 11 - web-apis/manifests/external/navigator.js | 3 +- web-apis/manifests/internal/archives.js | 24 +- web-apis/manifests/internal/browser.js | 1 - web-apis/manifests/internal/templates.js | 6 - 71 files changed, 1145 insertions(+), 2504 deletions(-) rename dat/{library.js => archives.js} (65%) delete mode 100644 dat/folder-sync.js delete mode 100644 dat/garbage-collector.js delete mode 100644 dbs/archive-drafts.js delete mode 100644 dbs/templates.js create mode 100644 filesystem/const.js create mode 100644 filesystem/dat-library.js rename users/filesystem.js => filesystem/index.js (60%) rename {users => filesystem}/site-sessions.js (100%) create mode 100644 filesystem/trash.js rename users/index.js => filesystem/users.js (87%) rename {crawler => uwg}/bookmarks.js (96%) rename {crawler => uwg}/comments.js (97%) rename {crawler => uwg}/follows.js (95%) rename {crawler => uwg}/index.js (83%) rename {crawler => uwg}/json-schemas/bookmark.js (100%) rename {crawler => uwg}/json-schemas/comment.js (100%) rename {crawler => uwg}/json-schemas/follows.js (100%) rename {crawler => uwg}/json-schemas/post.js (100%) rename {crawler => uwg}/json-schemas/reaction.js (100%) rename {crawler => uwg}/json-schemas/vote.js (100%) rename {crawler => uwg}/posts.js (96%) rename {crawler => uwg}/reactions.js (96%) rename {crawler => uwg}/search.js (97%) rename {crawler => uwg}/site-descriptions.js (96%) rename {crawler => uwg}/tags.js (98%) rename {crawler => uwg}/util.js (93%) rename {crawler => uwg}/votes.js (96%) delete mode 100644 web-apis/bg/library.js delete mode 100644 web-apis/bg/templates.js delete mode 100644 web-apis/manifests/external/library.js delete mode 100644 web-apis/manifests/internal/templates.js diff --git a/README.md b/README.md index 65436571..4ff39e67 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ debug('dat-related stuff') ### `dat.debug` -### `crawler` +### `uwg` ### `users` diff --git a/dat/library.js b/dat/archives.js similarity index 65% rename from dat/library.js rename to dat/archives.js index c66e3090..b7605145 100644 --- a/dat/library.js +++ b/dat/archives.js @@ -1,15 +1,12 @@ const emitStream = require('emit-stream') const EventEmitter = require('events') const datEncoding = require('dat-encoding') -const pify = require('pify') -const signatures = require('sodium-signatures') const parseDatURL = require('parse-dat-url') const _debounce = require('lodash.debounce') -const mkdirp = require('mkdirp') const pda = require('pauls-dat-api2') const scopedFSes = require('../lib/scoped-fses') const baseLogger = require('../logger').get() -const logger = baseLogger.child({category: 'dat', subcategory: 'library'}) +const logger = baseLogger.child({category: 'dat', subcategory: 'archives'}) // dbs const siteData = require('../dbs/sitedata') @@ -19,9 +16,7 @@ const datDnsDb = require('../dbs/dat-dns') // dat modules const daemon = require('./daemon') -const datGC = require('./garbage-collector') const datAssets = require('./assets') -const folderSync = require('./folder-sync') // constants // = @@ -52,6 +47,10 @@ var archivesEvents = new EventEmitter() // exported API // = +exports.on = archivesEvents.on.bind(archivesEvents) +exports.addListener = archivesEvents.addListener.bind(archivesEvents) +exports.removeListener = archivesEvents.removeListener.bind(archivesEvents) + /** * @param {Object} opts * @param {Object} opts.rpcAPI @@ -62,49 +61,8 @@ var archivesEvents = new EventEmitter() exports.setup = async function setup ({rpcAPI, disallowedSavePaths}) { // connect to the daemon await daemon.setup() - folderSync.setup({ - datPath: archivesDb.getDatPath(), - disallowedSavePaths - }) - // daemonEvents = emitStream(daemon.createEventStream()) TODO - - // pipe the log - // TODO needed? - // var daemonLogEvents = emitStream(daemon.createLogStream()) - // daemonLogEvents.on('log', ({level, message, etc}) => { - // baseLogger.log(level, message, etc) - // }) - - // wire up event handlers - archivesDb.on('update:archive-user-settings', async (key, userSettings, newUserSettings) => { - // emit event - var details = { - url: 'dat://' + key, - isSaved: userSettings.isSaved, - hidden: userSettings.hidden, - networked: userSettings.networked, - autoDownload: userSettings.autoDownload, - autoUpload: userSettings.autoUpload, - localSyncPath: userSettings.localSyncPath, - previewMode: userSettings.previewMode - } - archivesEvents.emit('updated', {details}) - if ('isSaved' in newUserSettings) { - archivesEvents.emit(newUserSettings.isSaved ? 'added' : 'removed', {details}) - } - - // delete all perms for deleted archives - if (!userSettings.isSaved) { - siteData.clearPermissionAllOrigins('modifyDat:' + key) - } - // update the archive based on these settings - let archive = getArchive(key) - if (archive) { - folderSync.reconfigureArchive(archive, userSettings) - } - }) - datDnsDb.on('update', ({key, name}) => { + datDnsDb.on('updated', ({key, name}) => { var archive = getArchive(key) if (archive) { archive.domain = name @@ -114,8 +72,6 @@ exports.setup = async function setup ({rpcAPI, disallowedSavePaths}) { // re-export events // TODO // daemonEvents.on('network-changed', evt => archivesEvents.emit('network-changed', evt)) - // daemonEvents.on('folder-synced', evt => archivesEvents.emit('folder-synced', evt)) - // daemonEvents.on('folder-sync-error', evt => archivesEvents.emit('folder-sync-error', evt)) // configure the bandwidth throttle // TODO @@ -128,33 +84,27 @@ exports.setup = async function setup ({rpcAPI, disallowedSavePaths}) { // settingsDb.on('set:dat_bandwidth_limit_up', up => daemon.setBandwidthThrottle({up})) // settingsDb.on('set:dat_bandwidth_limit_down', down => daemon.setBandwidthThrottle({down})) - // start the GC manager - datGC.setup() - logger.info('Initialized dat library') + logger.info('Initialized dat daemon') } /** * @returns {Promise} */ -exports.loadSavedArchives = function () { - // load and configure all saved archives - return archivesDb.query(0, {isSaved: true}).then( - async (/** @type LibraryArchiveRecord[] */archives) => { - // HACK - // load the archives one at a time and give 5 seconds between each - // why: the purpose of loading saved archives is to seed them - // loading them all at once can bog down the user's device - // if the user tries to access an archive, Beaker will load it immediately - // so spacing out the loads has no visible impact on the user - // (except for reducing the overall load for the user) - // -prf - for (let a of archives) { - loadArchive(a.key, a.userSettings) - await new Promise(r => setTimeout(r, 5e3)) // wait 5s - } - }, - err => console.error('Failed to load networked archives', err) - ) +exports.loadSavedArchives = async function () { + // load all saved archives + var archives = require('../filesystem/dat-library').query({isHosting: true}) + // HACK + // load the archives one at a time and give 5 seconds between each + // why: the purpose of loading saved archives is to seed them + // loading them all at once can bog down the user's device + // if the user tries to access an archive, Beaker will load it immediately + // so spacing out the loads has no visible impact on the user + // (except for reducing the overall load for the user) + // -prf + for (let a of archives) { + loadArchive(a.key) + await new Promise(r => setTimeout(r, 5e3)) // wait 5s + } } /** @@ -204,7 +154,7 @@ const pullLatestArchiveMeta = exports.pullLatestArchiveMeta = async function pul // emit the updated event details.url = 'dat://' + key - archivesEvents.emit('updated', {details}) + archivesEvents.emit('updated', {key, details, oldMeta}) return details } catch (e) { console.error('Error pulling meta', e) @@ -215,21 +165,21 @@ const pullLatestArchiveMeta = exports.pullLatestArchiveMeta = async function pul // = /** - * @param {Object} [manifest] - * @param {Object|boolean} [settings] + * @returns {Promise} */ -const createNewArchive = exports.createNewArchive = async function createNewArchive (manifest = {}, settings = false) { - var userSettings = { - isSaved: !(settings && settings.isSaved === false), - networked: !(settings && settings.networked === false), - hidden: settings && settings.hidden === true, - previewMode: settings && settings.previewMode === true, - localSyncPath: settings && settings.localSyncPath - } +exports.createNewRootArchive = async function () { + var archive = await loadArchive(null, {visibility: 'private'}) + await pullLatestArchiveMeta(archive) + return archive +} +/** + * @param {Object} [manifest] + * @returns {Promise} + */ +const createNewArchive = exports.createNewArchive = async function (manifest = {}) { // create the archive - var archive = await loadArchive(null, userSettings) - var key = datEncoding.toStr(archive.key) + var archive = await loadArchive(null) // write the manifest and default datignore await Promise.all([ @@ -237,16 +187,18 @@ const createNewArchive = exports.createNewArchive = async function createNewArch archive.pda.writeFile('/.datignore', await settingsDb.get('default_dat_ignore'), 'utf8') ]) - // write the user settings - await archivesDb.setUserSettings(0, key, userSettings) - - // write the metadata + // save the metadata await pullLatestArchiveMeta(archive) - return `dat://${key}/` + return archive } -exports.forkArchive = async function forkArchive (srcArchiveUrl, manifest = {}, settings = undefined) { +/** + * @param {string} srcArchiveUrl + * @param {Object} [manifest] + * @returns {Promise} + */ +exports.forkArchive = async function forkArchive (srcArchiveUrl, manifest = {}) { srcArchiveUrl = fromKeyToURL(srcArchiveUrl) // get the source archive @@ -284,8 +236,7 @@ exports.forkArchive = async function forkArchive (srcArchiveUrl, manifest = {}, }) // create the new archive - var dstArchiveUrl = await createNewArchive(dstManifest, settings) - var dstArchive = getArchive(dstArchiveUrl) + var dstArchive = await createNewArchive(dstManifest) // copy files var ignore = ['/.dat', '/.git', '/dat.json'] @@ -303,13 +254,13 @@ exports.forkArchive = async function forkArchive (srcArchiveUrl, manifest = {}, await dstArchive.pda.writeFile('/.datignore', await settingsDb.get('default_dat_ignore'), 'utf8') } - return dstArchiveUrl + return dstArchive } // archive management // = -const loadArchive = exports.loadArchive = async function loadArchive (key, userSettings = null) { +const loadArchive = exports.loadArchive = async function loadArchive (key, settingsOverride) { // validate key if (key) { if (!Buffer.isBuffer(key)) { @@ -329,7 +280,7 @@ const loadArchive = exports.loadArchive = async function loadArchive (key, userS } // run and cache the promise - var p = loadArchiveInner(key, userSettings) + var p = loadArchiveInner(key, settingsOverride) if (key) archiveLoadPromises[keyStr] = p p.catch(err => { console.error('Failed to load archive', keyStr, err.toString()) @@ -345,19 +296,7 @@ const loadArchive = exports.loadArchive = async function loadArchive (key, userS } // main logic, separated out so we can capture the promise -async function loadArchiveInner (key, userSettings = null) { - // load the user settings as needed - if (!userSettings) { - try { - userSettings = await archivesDb.getUserSettings(0, key) - } catch (e) { - userSettings = {networked: true} - } - } - if (!('networked' in userSettings)) { - userSettings.networked = true - } - +async function loadArchiveInner (key, settingsOverride) { // ensure the folders exist // TODO needed? // var metaPath = archivesDb.getArchiveMetaPath(key) @@ -366,9 +305,21 @@ async function loadArchiveInner (key, userSettings = null) { // create the archive session with the daemon var archive = await daemon.createDatArchiveSession({key}) key = archive.key + var keyStr = datEncoding.toStr(archive.key) + // fetch library settings + var userSettings = require('../filesystem/dat-library').getConfig(keyStr) + if (!userSettings) { + if (require('../filesystem/users').isUser(archive.url)) { + userSettings = {key: keyStr, isSaved: true, isHosting: true, visibility: 'unlisted', savedAt: null, meta: null} + } + } + if (settingsOverride) { + userSettings = Object.assign(userSettings || {}, settingsOverride) + } + // put the archive on the network - if (userSettings.networked) { + if (!userSettings || userSettings.visibility !== 'private') { archive.session.publish() } @@ -380,8 +331,6 @@ async function loadArchiveInner (key, userSettings = null) { archivesDb.touch(archive.key).catch(err => console.error('Failed to update lastAccessTime for archive', archive.key, err)) await pullLatestArchiveMeta(archive) datAssets.update(archive) - // configure subsystems - folderSync.reconfigureArchive(archive, userSettings) // wire up events archive.pullLatestArchiveMeta = _debounce(opts => pullLatestArchiveMeta(archive, opts), 1e3) @@ -390,22 +339,10 @@ async function loadArchiveInner (key, userSettings = null) { if (event !== 'changed') return archive.pullLatestArchiveMeta({updateMTime: true}) datAssets.update(archive, [path]) - - let localSyncSettings = folderSync.getLocalSyncSettings(archive) - if (localSyncSettings) { - // need to sync this change to the local folder - if (localSyncSettings.autoPublish) { - // bidirectional sync: use the sync queue - folderSync.queueSyncEvent(archive, {toFolder: true}) - } else { - // preview mode: just write this update to disk - folderSync.syncArchiveToFolder(archive, {paths: [path], shallow: false}) - } - } }) // now store in main archives listing, as loaded - archives[datEncoding.toStr(archive.key)] = archive + archives[keyStr] = archive return archive } @@ -416,25 +353,12 @@ const getArchive = exports.getArchive = function getArchive (key) { exports.getArchiveCheckout = async function getArchiveCheckout (archive, version) { var isHistoric = false - var isPreview = false var checkoutFS = archive if (typeof version !== 'undefined' && version !== null) { let seq = parseInt(version) if (Number.isNaN(seq)) { if (version === 'latest') { // ignore, we use latest by default - } else if (version === 'preview') { - let localSyncSettings = folderSync.getLocalSyncSettings(archive) - if (localSyncSettings) { - isPreview = true - checkoutFS = scopedFSes.get(localSyncSettings.path) - checkoutFS.setFilter(p => folderSync.applyDatIgnoreFilter(archive, p)) - checkoutFS.domain = archive.domain - } else { - var err = new Error('Preview mode is not active') - err.noPreviewMode = true - throw err - } } else { throw new Error('Invalid version identifier:' + version) } @@ -452,20 +376,20 @@ exports.getArchiveCheckout = async function getArchiveCheckout (archive, version isHistoric = true } } - return {isHistoric, isPreview, checkoutFS} + return {isHistoric, checkoutFS} } exports.getActiveArchives = function getActiveArchives () { return archives } -const getOrLoadArchive = exports.getOrLoadArchive = async function getOrLoadArchive (key, opts) { +const getOrLoadArchive = exports.getOrLoadArchive = async function getOrLoadArchive (key) { key = await fromURLToKey(key, true) var archive = getArchive(key) if (archive) { return archive } - return loadArchive(key, opts) + return loadArchive(key) } exports.unloadArchive = async function unloadArchive (key) { @@ -489,41 +413,15 @@ const isArchiveLoaded = exports.isArchiveLoaded = function isArchiveLoaded (key) // archive fetch/query // = -exports.queryArchives = async function queryArchives (query) { - // run the query - var archiveInfos = await archivesDb.query(0, query) - if (!archiveInfos) return undefined - var isArray = Array.isArray(archiveInfos) - if (!isArray) archiveInfos = [archiveInfos] - - if (query && ('inMemory' in query)) { - archiveInfos = archiveInfos.filter(archiveInfo => isArchiveLoaded(archiveInfo.key) === query.inMemory) - } - - // attach some live data - await Promise.all(archiveInfos.map(async (archiveInfo) => { - var archive = getArchive(archiveInfo.key) - if (archive) { - var info = await archive.getInfo() - archiveInfo.isSwarmed = archiveInfo.userSettings.networked - archiveInfo.peers = info.peers - } else { - archiveInfo.isSwarmed = false - archiveInfo.peers = 0 - } - })) - return isArray ? archiveInfos : archiveInfos[0] -} - exports.getArchiveInfo = async function getArchiveInfo (key) { // get the archive key = await fromURLToKey(key, true) var archive = await getOrLoadArchive(key) // fetch archive data - var [meta, userSettings, manifest, archiveInfo] = await Promise.all([ + var userSettings = require('../filesystem/dat-library').getConfig(key) + var [meta, manifest, archiveInfo] = await Promise.all([ archivesDb.getMeta(key), - archivesDb.getUserSettings(0, key), archive.pda.readManifest().catch(_ => {}), archive.getInfo() ]) @@ -535,14 +433,10 @@ exports.getArchiveInfo = async function getArchiveInfo (key) { meta.manifest = manifest meta.version = archiveInfo.version meta.userSettings = { - isSaved: userSettings.isSaved, - hidden: userSettings.hidden, - networked: userSettings.networked, - autoDownload: userSettings.autoDownload, - autoUpload: userSettings.autoUpload, - expiresAt: userSettings.expiresAt, - localSyncPath: userSettings.localSyncPath, - previewMode: userSettings.previewMode + isSaved: userSettings ? true : false, + isHosting: userSettings ? userSettings.isHosting : false, + visibility: userSettings ? userSettings.visibility : undefined, + savedAt: userSettings ? userSettings.savedAt : null } meta.peers = archiveInfo.peers meta.networkStats = archiveInfo.networkStats @@ -556,7 +450,6 @@ exports.getArchiveNetworkStats = async function getArchiveNetworkStats (key) { } exports.clearFileCache = async function clearFileCache (key) { - var userSettings = await archivesDb.getUserSettings(0, key) return {} // TODO daemon.clearFileCache(key, userSettings) } diff --git a/dat/daemon.js b/dat/daemon.js index 057e8afb..40873ef2 100644 --- a/dat/daemon.js +++ b/dat/daemon.js @@ -36,6 +36,8 @@ const SETUP_RETRIES = 10 * @prop {function(string, string): Promise} rename * @prop {function(string): Promise} unlink * @prop {function(string, Object=): Promise} rmdir +* @prop {function(string, string|Buffer): Promise} mount +* @prop {function(string): Promise} unmount * @prop {function(string=): Promise} download * @prop {function(string=): NodeJS.ReadableStream} watch * @prop {function(): NodeJS.ReadableStream} createNetworkActivityStream diff --git a/dat/debugging.js b/dat/debugging.js index 9d1d1aa0..7572fad8 100644 --- a/dat/debugging.js +++ b/dat/debugging.js @@ -1,4 +1,4 @@ -const {getActiveArchives} = require('./library') +const {getActiveArchives} = require('./archives') const datDns = require('./dns') /** diff --git a/dat/dns.js b/dat/dns.js index b75e6f57..3461c076 100644 --- a/dat/dns.js +++ b/dat/dns.js @@ -1,7 +1,7 @@ const parseDatURL = require('parse-dat-url') const {InvalidDomainName} = require('beaker-error-constants') const datDnsDb = require('../dbs/dat-dns') -const library = require('./library') +const archives = require('./archives') const {DAT_HASH_REGEX} = require('../lib/const') const logger = require('../logger').child({category: 'dat', subcategory: 'dns'}) @@ -40,5 +40,5 @@ async function read (name, err) { } async function write (name, key) { if (DAT_HASH_REGEX.test(name)) return // dont write for raw urls - await library.confirmDomain(key) + await archives.confirmDomain(key) } diff --git a/dat/folder-sync.js b/dat/folder-sync.js deleted file mode 100644 index b5e60a56..00000000 --- a/dat/folder-sync.js +++ /dev/null @@ -1,614 +0,0 @@ -const bytes = require('bytes') -const dft = require('diff-file-tree') -const diff = require('diff') -const anymatch = require('anymatch') -const fs = require('fs') -const jetpack = require('fs-jetpack') -const path = require('path') -const EventEmitter = require('events') -const datEncoding = require('dat-encoding') -const mkdirp = require('mkdirp') -const isEqual = require('lodash.isequal') -const {toAnymatchRules} = require('@beaker/datignore') -const logger = require('../logger').child({category: 'dat', subcategory: 'folder-sync'}) -const {isFileNameBinary, isFileContentBinary} = require('../lib/mime') -const lock = require('../lib/lock') -const scopedFSes = require('../lib/scoped-fses') -const { - NotFoundError, - NotAFolderError, - ProtectedFileNotWritableError, - ArchiveNotWritableError, - InvalidEncodingError, - SourceTooLargeError -} = require('beaker-error-constants') - -const MAX_DIFF_SIZE = bytes('100kb') - -// typedefs -// = - -/** - * @typedef {import('./daemon').DaemonDatArchive} DaemonDatArchive - */ - -// globals -// = - -var datPath = '' -var disallowedSavePaths = [] -var localSyncSettings = {} // key -> settings object -var syncEventQueues = {} // key -> queue object -var watchingLocalFolderStreams = {} // key -> function -var watchingDatIgnoreFnsStreams = {} // key -> function -var compareContentCaches = {} // key -> object -var datIgnoreRules = {} // key -> object -var syncCallCounts = {} // key -> number -var activeSyncs = {} // key -> number - -// exported api -// = - -const events = exports.events = new EventEmitter() - -exports.setup = function (opts) { - datPath = opts.datPath - disallowedSavePaths = opts.disallowedSavePaths -} - -exports.reconfigureArchive = function (archive, userSettings) { - var oldLocalSyncSettings = localSyncSettings[archive.key] - localSyncSettings[archive.key] = createLocalSyncSettings(archive, userSettings) - - if (!isEqual(localSyncSettings[archive.key], oldLocalSyncSettings)) { - // configure the local folder watcher if a change occurred - configureFolderToArchiveWatcher(archive) - } - - if (!localSyncSettings[archive.key] || !localSyncSettings[archive.key].isUsingInternal) { - // clear the internal directory if it's not in use - jetpack.removeAsync(getInternalLocalSyncPath(archive)) - } -} - -exports.getLocalSyncSettings = function (archive) { - return localSyncSettings[archive.key] -} - -/** - * @desc Sync dat to the folder - * @param {DaemonDatArchive} archive - * @param {Object} [opts] - * @param {boolean} [opts.shallow=true] dont descend into changed folders (default true) - * @param {boolean} [opts.compareContent=true] compare the actual content (default true) - * @param {string[]} [opts.paths] a whitelist of files to compare - * @param {string} [opts.localSyncPath] override the archive localSyncPath - * @param {boolean} [opts.addOnly=false] dont modify or remove any files (default false) - * @returns {Promise} - */ -const syncArchiveToFolder = exports.syncArchiveToFolder = function (archive, opts = {}) { - opts = opts || {} - return sync(archive, false, opts) -} - -/** - * @desc sync folder to the dat - * @param {DaemonDatArchive} archive - * @param {Object} [opts] - * @param {boolean} [opts.shallow=true] dont descend into changed folders (default true) - * @param {boolean} [opts.compareContent=true] compare the actual content (default true) - * @param {string[]} [opts.paths] a whitelist of files to compare - * @param {string} [opts.localSyncPath] override the archive localSyncPath - * @param {boolean} [opts.addOnly=false] dont modify or remove any files (default false) - * @returns {Promise} - */ -const syncFolderToArchive = exports.syncFolderToArchive = function (archive, opts = {}) { - opts = opts || {} - if (!archive.writable) throw new ArchiveNotWritableError() - return sync(archive, true, opts) -} - -/** - * @desc Helper to wait for sync on an archive to be finished - * @param {DaemonDatArchive} archive - * @returns {Promise} - */ -const ensureSyncFinished = exports.ensureSyncFinished = async function (archive) { - var isFinished - var release = await getArchiveSyncLock(archive) - try { isFinished = (activeSyncs[archive.key] == 0) } - finally { release() } - if (!isFinished) { - return ensureSyncFinished(archive) // check again - } -} - -/** - * @desc Queue a sync event from folder->archive or archive->folder - * - debounces the sync event with a 500ms timeout - * - call with toFolder: true to sync from archive->folder - * - call with toArchive: true to sync from folder->archive - * - if both toFolder && toArchive are queued, toArchive wins (local folder wins) - * - this *will* result in lost changes in the archive if simultaneous changes happen in the local folder, - * but it creates very deterministic results - * @param {DaemonDatArchive} archive - * @param {Object} opts - * @param {boolean} [opts.toFolder=false] - * @param {boolean} [opts.toArchive=false] - * @returns {void} - */ -const queueSyncEvent = exports.queueSyncEvent = function (archive, {toFolder, toArchive}) { - if (!syncEventQueues[archive.key]) { - syncEventQueues[archive.key] = newQueueObj() - } - var queue = syncEventQueues[archive.key] - - // ignore if currently syncing - if (queue.isSyncing) { - logger.silly('Already syncing, ignored') - return - } - - // debounce the handler - if (queue.timeout) { - clearTimeout(queue.timeout) - } - - // queue - if (toFolder) queue.toFolder = true - if (toArchive) queue.toArchive = true - queue.timeout = setTimeout(async () => { - const localSyncPath = localSyncSettings[archive.key].path - const {toArchive, toFolder} = queue - - // lock - queue.isSyncing = true - logger.silly('Ok timed out, beginning sync', {details: {toArchive, toFolder}}) - - try { - let st = await jetpack.existsAsync(localSyncPath) - if (!st) { - // folder has been removed - watchingLocalFolderStreams[archive.key].destroy() - watchingLocalFolderStreams[archive.key] = null - logger.warn('Local sync folder not found, aborting watch', {details: {path: localSyncPath}}) - return - } - // sync with priority given to the local folder - if (toArchive) await syncFolderToArchive(archive, {localSyncPath, shallow: false}) - else if (toFolder) await syncArchiveToFolder(archive, {localSyncPath, shallow: false}) - } catch (e) { - logger.error('Error syncing folder', {details: {path: localSyncPath, error: e.toString()}}) - if (e.name === 'CycleError') { - events.emit('error', archive.key, e) - } - } finally { - // reset the queue - queue = newQueueObj() - } - }, 500) -} -function newQueueObj () { - return {timeout: null, toFolder: false, toArchive: false, isSyncing: false} -} - -/** - * @desc Attach/detach a watcher on the local folder and sync it to the dat. - * @param {DaemonDatArchive} archive - * @returns {Promise} - */ -const configureFolderToArchiveWatcher = exports.configureFolderToArchiveWatcher = async function (archive) { - // HACKish - // it's possible that configureFolderToArchiveWatcher() could be called multiple times in sequence - // (for instance because of multiple settings changes) - // this is problematic because the method is async, and a previous call may still be in progress - // shouldAbort() tracks whether such an event has occurred and lets you drop out - // put this after every await: - // - // if (shouldAbort()) return - // - // -prf - var callCount = syncCallCounts[archive.key] = (syncCallCounts[archive.key] || 0) + 1 - const shouldAbort = () => callCount !== syncCallCounts[archive.key] - - // teardown the existing watch (his watch has ended) - // = - - if (watchingLocalFolderStreams[archive.key]) { - // stop watching - watchingLocalFolderStreams[archive.key].destroy() - watchingLocalFolderStreams[archive.key] = null - if (syncEventQueues[archive.key] && syncEventQueues[archive.key].timeout) { - clearTimeout(syncEventQueues[archive.key].timeout) - syncEventQueues[archive.key] = null - } - } - if (watchingDatIgnoreFnsStreams[archive.key]) { - watchingDatIgnoreFnsStreams[archive.key].destroy() - watchingDatIgnoreFnsStreams[archive.key] = null - } - - // start a new watch - // = - - if (localSyncSettings[archive.key]) { - logger.silly('Configuring archive sync', {details: {key: archive.key.toString('hex'), settings: localSyncSettings[archive.key]}}) - - // create diff cache - compareContentCaches[archive.key] = {} - - // create internal folder if needed - if (localSyncSettings[archive.key].isUsingInternal) { - mkdirp.sync(localSyncSettings[archive.key].path) - } - - // make sure the folder exists - let exists = await jetpack.exists(localSyncSettings[archive.key].path) - if (shouldAbort()) return - if (!exists) { - logger.warn('Local sync folder not found, aborting watch', {details: {path: localSyncSettings[archive.key].path}}) - } - var scopedFS = scopedFSes.get(localSyncSettings[archive.key].path) - - // track datignore rules - readDatIgnore(scopedFS).then(rules => { datIgnoreRules[archive.key] = rules }) - watchingDatIgnoreFnsStreams[archive.key] = scopedFS.pda.watch('/.datignore', async () => { - datIgnoreRules[archive.key] = await readDatIgnore(scopedFS) - }) - - if (!localSyncSettings[archive.key].autoPublish) { - // no need to setup watcher - // just do an add-only sync from archive->folder - await sync(archive, false, {shallow: false, addOnly: true}) - if (shouldAbort()) return - } else { - // sync up - try { - await mergeArchiveAndFolder(archive, localSyncSettings[archive.key].path) - } catch (err) { - logger.error('Failed to merge local sync folder', {details: {err}}) - } - if (shouldAbort()) return - - // start watching - watchingLocalFolderStreams[archive.key] = scopedFS.pda.watch('/', path => { - // TODO - // it would be possible to make this more efficient by ignoring changes that match .datignore - // but you need to make sure you have the latest .datignore and reading that on every change-event isnt efficient - // so you either need to: - // A. queue up all the changed paths, then read the datignore inside the timeout and filter, if filteredList.length === 0 then abort - // B. maintain an in-memory copy of the datignore and keep it up-to-date, and then check at time of the event - // -prf - - logger.silly('Change detected', {details: {path}}) - queueSyncEvent(archive, {toArchive: true}) - }) - } - } else { - // clear diff cache - compareContentCaches[archive.key] = {} - } -} - -/** - * @desc List the files that differ. - * @param {DaemonDatArchive} archive - * @param {Object} opts - * @param {boolean} [opts.shallow=true] dont descend into changed folders (default true) - * @param {boolean} [opts.compareContent=true] compare the actual content (default true) - * @param {string[]} [opts.paths] a whitelist of files to compare - * @param {string} [opts.localSyncPath] override the archive localSyncPath - * @returns {Promise} - */ -exports.diffListing = async function (archive, opts = {}) { - opts = opts || {} - var localSyncPath = opts.localSyncPath || (localSyncSettings[archive.key] && localSyncSettings[archive.key].path) - if (!localSyncPath) { - logger.warn('Sanity check failed - diffListing() aborting, no localSyncPath') - return [] - } - var scopedFS = scopedFSes.get(localSyncPath) - opts = massageDiffOpts(opts) - - // build ignore rules - var newOpts = /** @type Object */({...opts}) - if (opts.paths) { - newOpts.filter = makeDiffFilterByPaths(opts.paths) - } else { - const ignoreRules = await readDatIgnore(scopedFS) - newOpts.filter = (filepath) => anymatch(ignoreRules, filepath) - } - - // run diff - newOpts.compareContentCache = compareContentCaches[archive.key] - return dft.diff({fs: scopedFS.pda}, {fs: archive.pda}, newOpts) -} - -/** - * @desc Diff an individual file - * @param {DaemonDatArchive} archive - * @param {string} filepath the path of the file in the archive/folder - * @returns {Promise} - */ -exports.diffFile = async function (archive, filepath) { - if (!localSyncSettings[archive.key].path) { - logger.warn('Sanity check failed - diffFile() aborting, no localSyncPath') - return [] - } - var scopedFS = scopedFSes.get(localSyncSettings[archive.key].path) - filepath = path.normalize(filepath) - - // check the filename to see if it's binary - var isBinary = isFileNameBinary(filepath) - if (isBinary === true) { - throw new InvalidEncodingError('Cannot diff a binary file') - } - - // make sure we can handle the buffers involved - let st - st = await stat(scopedFS, filepath) - if (isBinary !== false && st && st.isFile() && await isFileContentBinary(scopedFS, filepath)) { - throw new InvalidEncodingError('Cannot diff a binary file') - } - if (st && st.isFile() && st.size > MAX_DIFF_SIZE) { - throw new SourceTooLargeError() - } - st = await stat(archive, filepath) - if (isBinary !== false && st && st.isFile() && await isFileContentBinary(archive, filepath)) { - throw new InvalidEncodingError('Cannot diff a binary file') - } - if (st && st.isFile() && st.size > MAX_DIFF_SIZE) { - throw new SourceTooLargeError() - } - - // read the file in both sources - const [newFile, oldFile] = await Promise.all([readFile(scopedFS, filepath), readFile(archive, filepath)]) - - // return the diff - return diff.diffLines(oldFile, newFile) -} - -/** - * @desc Validate a path to be used for sync. - * @param {string} p - */ -exports.assertSafePath = async function (p) { - // check whether this is an OS path - for (let disallowedSavePath of disallowedSavePaths) { - if (path.normalize(p) === path.normalize(disallowedSavePath)) { - throw new ProtectedFileNotWritableError(`This is a protected folder. Please pick another folder or subfolder.`) - } - } - - // stat the folder - const info = await jetpack.inspect(p) - - if (!info) { - throw new NotFoundError() - } - - if (info.type !== 'dir') { - throw new NotAFolderError('Invalid target folder: not a folder') - } -} - -/** - * @desc Read a datignore from a fs space and turn it into anymatch rules. - * @param {Object} fs - * @returns {Promise} - */ -const readDatIgnore = exports.readDatIgnore = async function (fs) { - var rulesRaw = await readFile(fs, '.datignore') - return toAnymatchRules(rulesRaw) -} - -/** - * @desc Filter function used by scoped-fs to hide files in the datignore. - * @param {DaemonDatArchive} archive - * @param {string} filepath - * @return {boolean} - */ -exports.applyDatIgnoreFilter = function (archive, filepath) { - const rules = datIgnoreRules[archive.key] || toAnymatchRules('') - var filepaths = explodeFilePaths(filepath) // we need to check parent paths in addition to the target path - var res = filepaths.filter(p => anymatch(rules, p)).length === 0 - return res -} - -/** - * @desc Merge the dat.json in the folder and then merge files, with preference to folder files. - * @param {DaemonDatArchive} archive - * @param {string} localSyncPath - * @returns {Promise} - */ -const mergeArchiveAndFolder = exports.mergeArchiveAndFolder = async function (archive, localSyncPath) { - logger.silly('Merging archive and folder', {details: {path: localSyncPath, key: archive.key.toString('hex')}}) - const readManifest = async (fs) => { - try { return await fs.pda.readManifest() } catch (e) { return {} } - } - var localFS = scopedFSes.get(localSyncPath) - var localManifest = await readManifest(localFS) - var archiveManifest = await readManifest(archive) - var mergedManifest = Object.assign(archiveManifest || {}, localManifest || {}) - await localFS.pda.writeManifest(mergedManifest) - await sync(archive, false, {localSyncPath, shallow: false, addOnly: true}) // archive -> folder (add-only) - await sync(archive, true, {localSyncPath, shallow: false}) // folder -> archive - events.emit('merge:' + archive.key.toString('hex'), archive.key) - logger.silly('Done merging archive and folder', {details: {path: localSyncPath, key: archive.key.toString('hex')}}) -} - -// internal methods -// = - -/** - * @desc Sync the dat & folder content - * @param {DaemonDatArchive} archive - * @param {boolean} toArchive true to sync folder to archive, false to sync archive to folder - * @param {Object} [opts] - * @param {boolean} [opts.shallow=true] dont descend into changed folders (default true) - * @param {boolean} [opts.compareContent=true] compare the actual content (default true) - * @param {string[]} [opts.paths] a whitelist of files to compare - * @param {string} [opts.localSyncPath] override the archive localSyncPath - * @param {boolean} [opts.addOnly=false] dont modify or remove any files (default false) - * @returns {Promise} - */ -async function sync (archive, toArchive, opts = {}) { - opts = opts || {} - var localSyncPath = opts.localSyncPath || (localSyncSettings[archive.key] && localSyncSettings[archive.key].path) - if (!localSyncPath) { - logger.warn('Sanity check failed - sync() aborting, no localSyncPath') - return - } - - activeSyncs[archive.key] = (activeSyncs[archive.key] || 0) + 1 - var release = await getArchiveSyncLock(archive) - try { - var scopedFS = scopedFSes.get(localSyncPath) - opts = massageDiffOpts(opts) - var diffOpts = /** @type Object */({...opts}) - - // build ignore rules - if (opts.paths) { - diffOpts.filter = makeDiffFilterByPaths(opts.paths) - } else { - let ignoreRules = await readDatIgnore(scopedFS) - diffOpts.filter = (filepath) => anymatch(ignoreRules, filepath) - } - - // choose direction - var left = toArchive ? {fs: scopedFS.pda} : {fs: archive.pda} - var right = toArchive ? {fs: archive.pda} : {fs: scopedFS.pda} - - // run diff - diffOpts.compareContentCache = compareContentCaches[archive.key] - var diff = await dft.diff(left, right, diffOpts) - if (opts.addOnly) { - diff = diff.filter(d => d.change === 'add') - } - logger.silly(`Syncing to ${toArchive ? 'archive' : 'folder'}`, {details: {key: archive.key.toString('hex'), path: localSyncPath}}) - - // sync data - await dft.applyRight(left, right, diff) - events.emit('sync', archive.key, toArchive ? 'archive' : 'folder') - events.emit('sync:' + archive.key.toString('hex'), archive.key, toArchive ? 'archive' : 'folder') - - // decrement active syncs - activeSyncs[archive.key]-- - } catch (err) { - logger.error('Failed to sync archive to local path', {details: {key: archive.key.toString('hex'), path: localSyncPath, err: err.toString()}}) - } finally { - release() - } -} - -/** - * @param {DaemonDatArchive} archive - * @returns {Promise} - */ -function getArchiveSyncLock (archive) { - return lock('sync:' + archive.key.toString('hex')) -} - -/** - * @param {string[]} targetPaths - * @return {Function(string): boolean} - */ -function makeDiffFilterByPaths (targetPaths) { - targetPaths = targetPaths.map(path.normalize) - return (filepath) => { - for (let i = 0; i < targetPaths.length; i++) { - let targetPath = targetPaths[i] - - if (targetPath.endsWith(path.sep)) { - // a directory - if (filepath === targetPath.slice(0, -1)) return false // the directory itself - if (filepath.startsWith(targetPath)) return false // a file within the directory - } else { - // a file - if (filepath === targetPath) return false - } - if (targetPath.startsWith(filepath) && targetPath.charAt(filepath.length) === path.sep) { - return false // a parent folder - } - } - return true - } -} - -/** - * @param {Object} opts - * @returns {Object} - */ -function massageDiffOpts (opts) { - return { - compareContent: typeof opts.compareContent === 'boolean' ? opts.compareContent : true, - shallow: typeof opts.shallow === 'boolean' ? opts.shallow : true, - paths: Array.isArray(opts.paths) ? opts.paths.filter(v => typeof v === 'string') : false, - addOnly: typeof opts.addOnly === 'boolean' ? opts.addOnly : false - } -} - -/** - * @param {string|DaemonDatArchive} archiveOrKey - * @returns {string} - */ -function getInternalLocalSyncPath (archiveOrKey) { - var key = datEncoding.toStr(typeof archiveOrKey === 'string' ? archiveOrKey : archiveOrKey.key) - return path.join(datPath, 'Archives', 'LocalCopy', key.slice(0, 2), key.slice(2)) -} - -/** - * @param {DaemonDatArchive} archive - * @param {Object} userSettings - * @returns {Object} - */ -function createLocalSyncSettings (archive, userSettings) { - if (!archive.writable || !userSettings.isSaved) { - return false - } - if (userSettings.localSyncPath) { - return { - path: userSettings.localSyncPath, - autoPublish: !userSettings.previewMode - } - } - if (userSettings.previewMode) { - return { - path: getInternalLocalSyncPath(archive), - autoPublish: false, - isUsingInternal: true - } - } - return false -} - -// helper to read a file via promise and return a null on fail -async function stat (fs, filepath) { - try { - return await fs.pda.stat(filepath) - } catch (e) { - return null - } -} - -// helper to read a file via promise and return an empty string on fail -async function readFile (fs, filepath) { - var data - try { - data = await fs.pda.readFile(filepath, {encoding: 'utf8'}) - } catch (e) { - // ignore - } - return data || '' -} - -// helper to go from '/foo/bar/baz' to ['/', '/foo', '/foo/bar', '/foo/bar/baz'] -function explodeFilePaths (str) { - str = str.replace(/^\/|\/$/g, '') // strip leading and trailing slashes - var paths = str.split('/') - let lastPath = '' - for (let i = 0; i < paths.length; i++) { - lastPath = paths[i] = `${lastPath}/${paths[i]}` - } - return paths -} diff --git a/dat/garbage-collector.js b/dat/garbage-collector.js deleted file mode 100644 index 1c28db8e..00000000 --- a/dat/garbage-collector.js +++ /dev/null @@ -1,93 +0,0 @@ -const ms = require('ms') -const archivesDb = require('../dbs/archives') -const datLibrary = require('./library') -const { - DAT_GC_FIRST_COLLECT_WAIT, - DAT_GC_REGULAR_COLLECT_WAIT -} = require('../lib/const') -const logger = require('../logger').child({category: 'dat', subcategory: 'garbage-collector'}) - -// typedefs -// = - -/** - * @typedef {Object} CollectResult - * @prop {number} totalBytes - * @prop {number} totalArchives - * @prop {number} skippedArchives - */ - -// globals -// = - -var nextGCTimeout - -// exported API -// = - -exports.setup = function () { - schedule(DAT_GC_FIRST_COLLECT_WAIT) -} - -/** - * @param {Object} [opts] - * @param {number} [opts.olderThan] - * @param {boolean} [opts.isOwner] - * @returns {Promise} - */ -const collect = exports.collect = async function ({olderThan, isOwner} = {}) { - logger.info('Running GC') - - // clear any scheduled GC - if (nextGCTimeout) { - clearTimeout(nextGCTimeout) - nextGCTimeout = null - } - - // run the GC - var totalBytes = 0 - var skippedArchives = 0 - var startTime = Date.now() - - // first unsave expired archives - var expiredArchives = await archivesDb.listExpiredArchives() - if (expiredArchives.length) { - logger.info(`Unsaving ${expiredArchives.length} expired archives`) - } - var promises = [] - for (let i = 0; i < expiredArchives.length; i++) { - promises.push(archivesDb.setUserSettings(0, expiredArchives[i].key, {isSaved: false})) - } - await Promise.all(promises) - - // now GC old archives - var unusedArchives = await archivesDb.listGarbageCollectableArchives({olderThan, isOwner}) - if (unusedArchives.length) { - logger.info(`Cleaning out ${unusedArchives.length} unused archives`) - logger.silly('Archives:', {urls: unusedArchives.map(a => a.key)}) - } - for (let i = 0; i < unusedArchives.length; i++) { - await datLibrary.unloadArchive(unusedArchives[i].key) - totalBytes += await archivesDb.deleteArchive(unusedArchives[i].key) - } - - logger.debug(`GC completed in ${Date.now() - startTime} ms`) - - // schedule the next GC - schedule(DAT_GC_REGULAR_COLLECT_WAIT) - logger.debug(`Scheduling next run to happen in ${ms(DAT_GC_REGULAR_COLLECT_WAIT)}`) - - // return stats - return {totalBytes, totalArchives: unusedArchives.length - skippedArchives, skippedArchives} -} - -// helpers -// = - -/** - * @param {number} time - */ -function schedule (time) { - nextGCTimeout = setTimeout(collect, time) - nextGCTimeout.unref() -} diff --git a/dat/index.js b/dat/index.js index 512518b3..53150eb9 100644 --- a/dat/index.js +++ b/dat/index.js @@ -1,9 +1,12 @@ module.exports = { + archives: require('./archives'), assets: require('./assets'), debug: require('./debugging'), dns: require('./dns'), - garbageCollector: require('./garbage-collector'), - library: require('./library'), protocol: require('./protocol'), - watchlist: require('./watchlist') + watchlist: require('./watchlist'), + async setup (opts) { + await this.archives.setup(opts) + await this.watchlist.setup() + } } diff --git a/dat/protocol.js b/dat/protocol.js index 196d96d0..1602b919 100644 --- a/dat/protocol.js +++ b/dat/protocol.js @@ -9,7 +9,7 @@ const slugify = require('slugify') const markdown = require('../lib/markdown') const datDns = require('./dns') -const datLibrary = require('./library') +const datArchives = require('./archives') const datServeResolvePath = require('@beaker/dat-serve-resolve-path') const errorPage = require('../lib/error-page') @@ -118,7 +118,7 @@ exports.electronHandler = async function (request, respond) { try { // start searching the network - archive = await datLibrary.getOrLoadArchive(archiveKey) + archive = await datArchives.getOrLoadArchive(archiveKey) } catch (err) { logger.warn('Failed to open archive', {url: archiveKey, err}) cleanup() @@ -133,25 +133,11 @@ exports.electronHandler = async function (request, respond) { // checkout version if needed try { - var {checkoutFS} = await datLibrary.getArchiveCheckout(archive, urlp.version) - if (urlp.version === 'preview') { - await checkoutFS.pda.stat('/') // run a stat to ensure preview mode exists - } + var {checkoutFS} = await datArchives.getArchiveCheckout(archive, urlp.version) } catch (err) { - if (err.noPreviewMode) { - // redirect to non-preview version - return respond({ - statusCode: 303, - headers: { - Location: `dat://${urlp.host}${urlp.pathname || '/'}${urlp.search || ''}` - }, - data: intoStream('') - }) - } else { - logger.warn('Failed to open archive checkout', {url: archiveKey, err}) - cleanup() - return respondError(500, 'Failed') - } + logger.warn('Failed to open archive checkout', {url: archiveKey, err}) + cleanup() + return respondError(500, 'Failed') } // read the manifest (it's needed in a couple places) @@ -257,7 +243,7 @@ exports.electronHandler = async function (request, respond) { // caching is disabled till we can figure out why // -prf // caching if-match - // const ETag = (checkoutFS.isLocalFS) ? false : 'block-' + entry.offset + // const ETag = 'block-' + entry.offset // if (request.headers['if-none-match'] === ETag) { // return respondError(304, 'Not Modified') // } diff --git a/dat/watchlist.js b/dat/watchlist.js index 1be83b1d..d1dfbd74 100644 --- a/dat/watchlist.js +++ b/dat/watchlist.js @@ -3,8 +3,8 @@ const emitStream = require('emit-stream') const logger = require('../logger').child({category: 'dat', subcategory: 'watchlist'}) // dat modules -const datLibrary = require('../dat/library') -const datDns = require('../dat/dns') +const datArchives = require('./archives') +const datDns = require('./dns') const watchlistDb = require('../dbs/watchlist') // globals @@ -92,7 +92,7 @@ async function watch (site) { } // load archive - var archive = await datLibrary.loadArchive(key) + var archive = await datArchives.loadArchive(key) if (site.resolved === 0) { watchlistEvents.emit('resolved', site) } diff --git a/dbs/archive-drafts.js b/dbs/archive-drafts.js deleted file mode 100644 index f39974b8..00000000 --- a/dbs/archive-drafts.js +++ /dev/null @@ -1,30 +0,0 @@ -const db = require('./profile-data-db') -const archivesDb = require('./archives') - -// exported api -// = - -exports.list = async function (profileId, masterKey) { - // get draft list - var records = await db.all(`SELECT draftKey as key FROM archive_drafts WHERE profileId = ? AND masterKey = ? ORDER BY createdAt`, [profileId, masterKey]) - // fetch full info from archives db - return Promise.all(records.map(async ({key}) => archivesDb.query(profileId, {key, showHidden: true}))) -} - -exports.add = function (profileId, masterKey, draftKey) { - return db.run(` - INSERT OR REPLACE - INTO archive_drafts (profileId, masterKey, draftKey) - VALUES (?, ?, ?) - `, [profileId, masterKey, draftKey]) -} - -exports.remove = function (profileId, masterKey, draftKey) { - return db.run(`DELETE FROM archive_drafts WHERE profileId = ? AND masterKey = ? AND draftKey = ?`, [profileId, masterKey, draftKey]) -} - -exports.getMaster = async function (profileId, draftKey) { - var record = await db.get(`SELECT masterKey as key FROM archive_drafts WHERE profileId = ? AND draftKey = ?`, [profileId, draftKey]) - if (record) return record.key - return draftKey -} \ No newline at end of file diff --git a/dbs/archives.js b/dbs/archives.js index c8260ceb..40582142 100644 --- a/dbs/archives.js +++ b/dbs/archives.js @@ -7,10 +7,7 @@ const jetpack = require('fs-jetpack') const {InvalidArchiveKeyError} = require('beaker-error-constants') const db = require('./profile-data-db') const lock = require('../lib/lock') -const { - DAT_HASH_REGEX, - DAT_GC_EXPIRATION_AGE -} = require('../lib/const') +const {DAT_HASH_REGEX} = require('../lib/const') // typedefs // = @@ -18,35 +15,11 @@ const { /** * @typedef {import('../dat/daemon').DaemonDatArchive} DaemonDatArchive * - * @typedef {Object} LibraryArchiveRecord - * @prop {string} key - * @prop {string} url - * @prop {string?} domain - * @prop {string} title - * @prop {string} description - * @prop {Array} type - * @prop {number} mtime - * @prop {number} size - * @prop {string} forkOf - * @prop {boolean} isOwner - * @prop {number} lastAccessTime - * @prop {number} lastLibraryAccessTime - * @prop {Object} userSettings - * @prop {boolean} userSettings.isSaved - * @prop {boolean} userSettings.hidden - * @prop {boolean} userSettings.networked - * @prop {boolean} userSettings.autoDownload - * @prop {boolean} userSettings.autoUpload - * @prop {number} userSettings.expiresAt - * @prop {string} userSettings.localSyncPath - * @prop {boolean} userSettings.previewMode - * * @typedef {Object} LibraryArchiveMeta * @prop {string} key * @prop {string} title * @prop {string} description * @prop {string | Array} type - * @prop {Array} installedNames * @prop {number} mtime * @prop {number} size * @prop {string} forkOf @@ -54,19 +27,6 @@ const { * @prop {number} lastAccessTime * @prop {number} lastLibraryAccessTime * - * @typedef {Object} LibraryArchiveUserSettings - * @prop {number} profileId - * @prop {string} key - * @prop {boolean} isSaved - * @prop {boolean} hidden - * @prop {boolean} networked - * @prop {boolean} autoDownload - * @prop {boolean} autoUpload - * @prop {number} expiresAt - * @prop {string} localSyncPath - * @prop {boolean} previewMode - * @prop {number} createdAt - * * @typedef {Object} MinimalLibraryArchiveRecord * @prop {string} key */ @@ -115,23 +75,6 @@ const getArchiveMetaPath = exports.getArchiveMetaPath = function (archiveOrKey) return path.join(datPath, 'Archives', 'Meta', key.slice(0, 2), key.slice(2)) } -/** - * @description Get the path to an archive's temporary local sync path. - * @param {string | Buffer | DaemonDatArchive} archiveOrKey - * @returns {string} - */ -const getInternalLocalSyncPath = exports.getInternalLocalSyncPath = function (archiveOrKey) { - var key /** @type string */ - if (typeof archiveOrKey === 'string') { - key = archiveOrKey - } else if (Buffer.isBuffer(archiveOrKey)) { - key = datEncoding.toStr(archiveOrKey) - } else { - key = datEncoding.toStr(archiveOrKey.key) - } - return path.join(datPath, 'Archives', 'LocalCopy', key.slice(0, 2), key.slice(2)) -} - /** * @description Delete all db entries and files for an archive. * @param {string} key @@ -144,8 +87,7 @@ exports.deleteArchive = async function (key) { db.run(`DELETE FROM archives WHERE key=?`, key), db.run(`DELETE FROM archives_meta WHERE key=?`, key), db.run(`DELETE FROM archives_meta_type WHERE key=?`, key), - jetpack.removeAsync(path), - jetpack.removeAsync(getInternalLocalSyncPath(key)) + jetpack.removeAsync(path) ]) return info ? info.size : 0 } @@ -154,170 +96,6 @@ exports.on = events.on.bind(events) exports.addListener = events.addListener.bind(events) exports.removeListener = events.removeListener.bind(events) -// exported methods: archive user settings -// = - -/** - * @description Get an array of saved archives. - * @param {number} profileId - * @param {Object} [query] - * @param {string} [query.key] - * @param {boolean} [query.isSaved] - * @param {boolean} [query.isNetworked] - * @param {boolean} [query.isOwner] - * @param {string} [query.forkOf] - * @param {boolean} [query.showHidden] - * @param {string} [query.type] - * @param {string} [query.string] - * @returns {Promise>} - */ -exports.query = async function (profileId, query = {}) { - // fetch archive meta - var values = [] - var whereList = [] - if (query.isOwner === true) whereList.push('archives_meta.isOwner = 1') - if (query.isOwner === false) whereList.push('archives_meta.isOwner = 0') - if (query.isNetworked === true) whereList.push('archives.networked = 1') - if (query.isNetworked === false) whereList.push('archives.networked = 0') - if ('forkOf' in query) { - whereList.push('archives_meta.forkOf = ?') - values.push(query.forkOf) - } - if ('isSaved' in query) { - if (query.isSaved) { - whereList.push('archives.profileId = ?') - values.push(profileId) - whereList.push('archives.isSaved = 1') - } else { - whereList.push('(archives.isSaved = 0 OR archives.isSaved IS NULL)') - } - } - if (typeof query.key !== 'undefined') { - whereList.push('archives_meta.key = ?') - values.push(query.key) - } - if (!query.showHidden) whereList.push('(archives.hidden = 0 OR archives.hidden IS NULL)') - var WHERE = whereList.length ? `WHERE ${whereList.join(' AND ')}` : '' - - var archives = await db.all(` - SELECT - archives_meta.*, - GROUP_CONCAT(archives_meta_type.type) AS type, - archives.isSaved, - archives.hidden, - archives.networked, - archives.autoDownload, - archives.autoUpload, - archives.expiresAt, - archives.localSyncPath, - archives.previewMode, - dat_dns.name as domain - FROM archives_meta - LEFT JOIN archives ON archives.key = archives_meta.key - LEFT JOIN archives_meta_type ON archives_meta_type.key = archives_meta.key - LEFT JOIN dat_dns ON dat_dns.key = archives_meta.key AND dat_dns.isCurrent = 1 - ${WHERE} - GROUP BY archives_meta.key - `, values) - - // massage the output - archives.forEach(archive => { - archive.url = `dat://${archive.domain || archive.key}` - archive.isOwner = archive.isOwner != 0 - archive.type = archive.type ? archive.type.split(',') : [] - archive.userSettings = { - isSaved: archive.isSaved == 1, - hidden: archive.hidden == 0, - networked: archive.networked == 1, - autoDownload: archive.autoDownload == 1, - autoUpload: archive.autoUpload == 1, - expiresAt: archive.expiresAt, - localSyncPath: archive.localSyncPath, - previewMode: archive.previewMode == 1 - } - - // user settings - delete archive.isSaved - delete archive.hidden - delete archive.networked - delete archive.autoDownload - delete archive.autoUpload - delete archive.expiresAt - delete archive.localSyncPath - delete archive.previewMode - - // deprecated attrs - delete archive.createdByTitle - delete archive.createdByUrl - delete archive.metaSize - delete archive.stagingSize - delete archive.stagingSizeLessIgnored - }) - - // apply manual filters - if ('type' in query) { - let types = Array.isArray(query.type) ? query.type : [query.type] - archives = archives.filter((/** @type LibraryArchiveRecord */ a) => { - for (let type of types) { - if (a.type.indexOf(type) === -1) { - return false - } - } - return true - }) - } - - return ('key' in query) ? archives[0] : archives -} - -/** - * @description Get all archives that should be unsaved. - * @returns {Promise>} - */ -exports.listExpiredArchives = async function () { - return db.all(` - SELECT archives.key - FROM archives - WHERE - archives.isSaved = 1 - AND archives.expiresAt != 0 - AND archives.expiresAt IS NOT NULL - AND archives.expiresAt < ? - `, [Date.now()]) -} - -/** - * @description Get all archives that are ready for garbage collection. - * @param {Object} [opts] - * @param {number} [opts.olderThan] - * @param {boolean} [opts.isOwner] - * @returns {Promise>} - */ -exports.listGarbageCollectableArchives = async function ({olderThan, isOwner} = {}) { - olderThan = typeof olderThan === 'number' ? olderThan : DAT_GC_EXPIRATION_AGE - var isOwnerClause = typeof isOwner === 'boolean' ? `AND archives_meta.isOwner = ${isOwner ? '1' : '0'}` : '' - - // fetch archives - var records = await db.all(` - SELECT archives_meta.key - FROM archives_meta - LEFT JOIN archives ON archives_meta.key = archives.key - WHERE - (archives.isSaved != 1 OR archives.isSaved IS NULL) - AND archives_meta.lastAccessTime < ? - ${isOwnerClause} - `, [Date.now() - olderThan]) - var records2 = records.slice() - - // fetch any related drafts - for (let record of records2) { - let drafts = await db.all(`SELECT draftKey as key FROM archive_drafts WHERE masterKey = ? ORDER BY createdAt`, [record.key]) - records = records.concat(drafts) - } - - return records -} - /** * @description Upsert the last-access time. * @param {string | Buffer} key @@ -340,160 +118,6 @@ exports.touch = async function (key, timeVar = 'lastAccessTime', value = -1) { } } -/** - * @description - * Get a single archive's user settings. - * (Returns an empty object on not found.) - * @param {number} profileId - * @param {string | Buffer} key - * @returns {Promise} - */ -const getUserSettings = exports.getUserSettings = async function (profileId, key) { - // massage inputs - var keyStr = typeof key !== 'string' ? datEncoding.toStr(key) : key - - // validate inputs - if (!DAT_HASH_REGEX.test(keyStr)) { - throw new InvalidArchiveKeyError() - } - - // fetch - try { - var settings = await db.get(` - SELECT * FROM archives WHERE profileId = ? AND key = ? - `, [profileId, keyStr]) - settings.isSaved = !!settings.isSaved - settings.hidden = !!settings.hidden - settings.networked = !!settings.networked - settings.autoDownload = !!settings.autoDownload - settings.autoUpload = !!settings.autoUpload - settings.previewMode = Number(settings.previewMode) === 1 - return /** @type LibraryArchiveUserSettings */(settings) - } catch (e) { - return /** @type LibraryArchiveUserSettings */({}) - } -} - -/** - * @description Write an archive's user setting. - * @param {number} profileId - * @param {string | Buffer} key - * @param {Object} [newValues] - * @param {boolean} [newValues.isSaved] - * @param {boolean} [newValues.hidden] - * @param {boolean} [newValues.networked] - * @param {boolean} [newValues.autoDownload] - * @param {boolean} [newValues.autoUpload] - * @param {number} [newValues.expiresAt] - * @param {string} [newValues.localSyncPath] - * @param {boolean} [newValues.previewMode] - * @returns {Promise} - */ -exports.setUserSettings = async function (profileId, key, newValues = {}) { - // massage inputs - var keyStr = datEncoding.toStr(key) - - // validate inputs - if (!DAT_HASH_REGEX.test(keyStr)) { - throw new InvalidArchiveKeyError() - } - - var release = await lock('archives-db') - try { - // fetch current - var value = await getUserSettings(profileId, keyStr) - - if (!value || typeof value.key === 'undefined') { - // create - value = /** @type LibraryArchiveUserSettings */ ({ - profileId, - key: keyStr, - isSaved: newValues.isSaved, - hidden: newValues.hidden, - networked: ('networked' in newValues) ? newValues.networked : true, - autoDownload: ('autoDownload' in newValues) ? newValues.autoDownload : newValues.isSaved, - autoUpload: ('autoUpload' in newValues) ? newValues.autoUpload : newValues.isSaved, - expiresAt: newValues.expiresAt, - localSyncPath: (newValues.localSyncPath) ? newValues.localSyncPath : '', - previewMode: ('previewMode' in newValues) ? newValues.previewMode : '' - }) - let valueArray = [ - profileId, - keyStr, - flag(value.isSaved), - flag(value.hidden), - flag(value.networked), - flag(value.autoDownload), - flag(value.autoUpload), - value.expiresAt, - value.localSyncPath, - flag(value.previewMode) - ] - await db.run(` - INSERT INTO archives - ( - profileId, - key, - isSaved, - hidden, - networked, - autoDownload, - autoUpload, - expiresAt, - localSyncPath, - previewMode - ) - VALUES (${valueArray.map(_ => '?').join(', ')}) - `, valueArray) - } else { - // update - let { isSaved, hidden, networked, autoDownload, autoUpload, expiresAt, localSyncPath, previewMode } = newValues - if (typeof isSaved === 'boolean') value.isSaved = isSaved - if (typeof hidden === 'boolean') value.hidden = hidden - if (typeof networked === 'boolean') value.networked = networked - if (typeof autoDownload === 'boolean') value.autoDownload = autoDownload - if (typeof autoUpload === 'boolean') value.autoUpload = autoUpload - if (typeof expiresAt === 'number') value.expiresAt = expiresAt - if (typeof localSyncPath === 'string') value.localSyncPath = localSyncPath - if (typeof previewMode === 'boolean') value.previewMode = previewMode - let valueArray = [ - flag(value.isSaved), - flag(value.hidden), - flag(value.networked), - flag(value.autoDownload), - flag(value.autoUpload), - value.expiresAt, - value.localSyncPath, - flag(value.previewMode), - profileId, - keyStr - ] - await db.run(` - UPDATE archives - SET - isSaved = ?, - hidden = ?, - networked = ?, - autoDownload = ?, - autoUpload = ?, - expiresAt = ?, - localSyncPath = ?, - previewMode = ? - WHERE - profileId = ? AND key = ? - `, valueArray) - } - - events.emit('update:archive-user-settings', keyStr, value, newValues) - return value - } finally { - release() - } -} - -// exported methods: archive meta -// = - /** * @description * Get a single archive's metadata. @@ -514,11 +138,9 @@ const getMeta = exports.getMeta = async function (key) { var meta = await db.get(` SELECT archives_meta.*, - GROUP_CONCAT(archives_meta_type.type) AS type, - GROUP_CONCAT(apps.name) as installedNames + GROUP_CONCAT(archives_meta_type.type) AS type FROM archives_meta LEFT JOIN archives_meta_type ON archives_meta_type.key = archives_meta.key - LEFT JOIN apps ON apps.url = ('dat://' || archives_meta.key) WHERE archives_meta.key = ? GROUP BY archives_meta.key `, [keyStr]) @@ -529,7 +151,6 @@ const getMeta = exports.getMeta = async function (key) { // massage some values meta.isOwner = !!meta.isOwner meta.type = meta.type ? meta.type.split(',') : [] - meta.installedNames = meta.installedNames ? meta.installedNames.split(',') : [] // remove old attrs delete meta.createdByTitle @@ -589,22 +210,6 @@ exports.setMeta = async function (key, value) { events.emit('update:archive-meta', keyStr, value) } -/** - * @description Find the archive currently using a given localSyncPath. - * @param {number} profileId - * @param {string} localSyncPath - * @returns {Promise} - */ -exports.getByLocalSyncPath = async function (profileId, localSyncPath) { - try { - return await db.get(` - SELECT key FROM archives WHERE profileId = ? AND localSyncPath = ? - `, [profileId, localSyncPath]) - } catch (e) { - return null - } -} - // internal methods // = @@ -623,7 +228,6 @@ function defaultMeta (key) { isOwner: false, lastAccessTime: 0, lastLibraryAccessTime: 0, - installedNames: [], size: 0 } } diff --git a/dbs/dat-dns.js b/dbs/dat-dns.js index 19a303e3..93899148 100644 --- a/dbs/dat-dns.js +++ b/dbs/dat-dns.js @@ -56,7 +56,7 @@ exports.update = async function ({key, name}) { if (old && old.key !== key) { // unset old await db.run(knex('dat_dns').update({isCurrent: 0}).where({name})) - events.emit('update', {key: old.key, name: undefined}) + events.emit('updated', {key: old.key, name: undefined}) } let curr = await db.get(knex('dat_dns').where({name, key})) @@ -73,7 +73,7 @@ exports.update = async function ({key, name}) { // update current await db.run(knex('dat_dns').update({lastConfirmedAt: Date.now(), isCurrent: 1}).where({name, key})) } - events.emit('update', {key, name}) + events.emit('updated', {key, name}) } finally { release() } @@ -87,7 +87,7 @@ exports.unset = async function (key) { var curr = await db.get(knex('dat_dns').where({key, isCurrent: 1})) if (curr) { await db.run(knex('dat_dns').update({isCurrent: 0}).where({key})) - events.emit('update', {key, name: undefined}) + events.emit('updated', {key, name: undefined}) } } diff --git a/dbs/index.js b/dbs/index.js index a1e5fed6..8e1b8ddd 100644 --- a/dbs/index.js +++ b/dbs/index.js @@ -1,11 +1,9 @@ module.exports = { archives: require('./archives'), - archiveDrafts: require('./archive-drafts'), bookmarks: require('./bookmarks'), history: require('./history'), profileData: require('./profile-data-db'), settings: require('./settings'), sitedata: require('./sitedata'), - templates: require('./templates'), watchlist: require('./watchlist') } diff --git a/dbs/schemas/profile-data.sql.js b/dbs/schemas/profile-data.sql.js index 68c4ace9..ec7b72d3 100644 --- a/dbs/schemas/profile-data.sql.js +++ b/dbs/schemas/profile-data.sql.js @@ -24,25 +24,6 @@ CREATE TABLE user_site_sessions ( FOREIGN KEY (userId) REFERENCES users (id) ON DELETE CASCADE ); -CREATE TABLE archives ( - profileId INTEGER NOT NULL, - key TEXT NOT NULL, -- dat key - - previewMode INTEGER, -- automatically publish changes (0) or write to local folder (1) - localSyncPath TEXT, -- custom local folder that the data is synced to - - isSaved INTEGER, -- is this archive saved to our library? - hidden INTEGER DEFAULT 0, -- should this archive be hidden in the library or select-archive modals? (this is useful for internal dats, such as drafts) - networked INTEGER DEFAULT 1, -- join the swarm (1) or do not swarm (0) - autoDownload INTEGER DEFAULT 1, -- watch and download all available data (1) or sparsely download on demand (0) - autoUpload INTEGER DEFAULT 1, -- join the swarm at startup (1) or only swarm when visiting (0) - expiresAt INTEGER, -- change autoUpload to 0 at this time (used for temporary seeding) - createdAt INTEGER DEFAULT (strftime('%s', 'now')), - - localPath TEXT, -- deprecated - autoPublishLocal INTEGER DEFAULT 0 -- deprecated -- watch localSyncPath and automatically publish changes (1) or not (0) -); - CREATE TABLE archives_meta ( key TEXT PRIMARY KEY, title TEXT, @@ -136,18 +117,6 @@ CREATE TABLE watchlist ( FOREIGN KEY (profileId) REFERENCES profiles (id) ON DELETE CASCADE ); --- list of the users current templates -CREATE TABLE templates ( - profileId INTEGER, - url TEXT NOT NULL, - title TEXT, - screenshot, - createdAt INTEGER DEFAULT (strftime('%s', 'now')), - - PRIMARY KEY (profileId, url), - FOREIGN KEY (profileId) REFERENCES profiles (id) ON DELETE CASCADE -); - -- list of sites being crawled CREATE TABLE crawl_sources ( id INTEGER PRIMARY KEY NOT NULL, @@ -413,6 +382,27 @@ CREATE TABLE crawl_media_tags ( FOREIGN KEY (crawlTagId) REFERENCES crawl_tags (id) ON DELETE CASCADE ); +-- a list of saved archives +-- deprecated +CREATE TABLE archives ( + profileId INTEGER NOT NULL, + key TEXT NOT NULL, -- dat key + + previewMode INTEGER, -- automatically publish changes (0) or write to local folder (1) + localSyncPath TEXT, -- custom local folder that the data is synced to + + isSaved INTEGER, -- is this archive saved to our library? + hidden INTEGER DEFAULT 0, -- should this archive be hidden in the library or select-archive modals? (this is useful for internal dats, such as drafts) + networked INTEGER DEFAULT 1, -- join the swarm (1) or do not swarm (0) + autoDownload INTEGER DEFAULT 1, -- watch and download all available data (1) or sparsely download on demand (0) + autoUpload INTEGER DEFAULT 1, -- join the swarm at startup (1) or only swarm when visiting (0) + expiresAt INTEGER, -- change autoUpload to 0 at this time (used for temporary seeding) + createdAt INTEGER DEFAULT (strftime('%s', 'now')), + + localPath TEXT, -- deprecated + autoPublishLocal INTEGER DEFAULT 0 -- deprecated -- watch localSyncPath and automatically publish changes (1) or not (0) +); + -- a list of the draft-dats for a master-dat -- deprecated CREATE TABLE archive_drafts ( @@ -426,6 +416,19 @@ CREATE TABLE archive_drafts ( FOREIGN KEY (profileId) REFERENCES profiles (id) ON DELETE CASCADE ); +-- list of the users current templates +-- deprecated +CREATE TABLE templates ( + profileId INTEGER, + url TEXT NOT NULL, + title TEXT, + screenshot, + createdAt INTEGER DEFAULT (strftime('%s', 'now')), + + PRIMARY KEY (profileId, url), + FOREIGN KEY (profileId) REFERENCES profiles (id) ON DELETE CASCADE +); + -- list of the users installed apps -- deprecated CREATE TABLE apps ( diff --git a/dbs/templates.js b/dbs/templates.js deleted file mode 100644 index 61a9e387..00000000 --- a/dbs/templates.js +++ /dev/null @@ -1,69 +0,0 @@ -const db = require('./profile-data-db') - -// typedefs -// = - -/** - * @typedef {Object} Template - * @prop {string} url - * @prop {string} title - * @prop {number} createdAt - * - * @typedef {Object} TemplateScreenshot - * @prop {string} url - * @prop {string} screenshot - */ - -// exported api -// = - -/** - * @param {number} profileId - * @param {string} url - * @returns {Promise