diff --git a/README.md b/README.md index 8f515b1..5e49ab4 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,27 @@ You can also have the following entries - name: name of the folder inside `remoteBasePath` that overrides the default from package's name. - snapshotName: name of the snapshot version that will override the default `development` +### Files Cryptographic Digest + +If you need the digest of the files you upload you can also add inside `ccu` in your `package.json` the following + +```json +"digest": { + "hashes": ["sha384"] +} +``` + +This will generate the `sha384` digest of every file to upload and store it in a different file named `.`. In the case you only need to hash only some files, e.g. JS only + +```json +"digest": { + "hashes": ["sha384"], + "extensions": [".js"] +} +``` + +> The valid types of digests are `sha256`, `sha384` and `sha512`, if none is specified the tool will generate no digest files. + ## Usage ``` diff --git a/aws/index.js b/aws/index.js index ca4e7cf..dc954c4 100644 --- a/aws/index.js +++ b/aws/index.js @@ -6,6 +6,7 @@ var s3 = require('s3'); var walk = require('walk'); var path = require('path'); var client = s3.createClient({}); +var files = require('../files'); var uploader = function (version, options) { return from(options.localPaths).map(function (directoryPath) { @@ -21,25 +22,10 @@ var uploader = function (version, options) { }; var logger = options.logger; if (options.dry) { - return Rx.Observable.create(function (observer) { - logger.debug(`Starting upload with following S3 config ${logger.pretty(params)}`); - var workingDir = process.cwd(); - var walker = walk.walk(params.localDir, { followLinks: false }); - walker.on('file', function (root, stats, next) { - var localPath = path.relative(workingDir, path.resolve(root, stats.name)); - var file = localPath.replace(directoryPath, version.remotePath); - observer.next(file); - next(); - }); - walker.on('error', function(root, stats, next) { - observer.onError(stats.error); - next(); - }); - walker.on('end', function() { - observer.onCompleted(); - }); - return function() {}; - }); + logger.debug(`Starting upload with following S3 config ${logger.pretty(params)}`); + return files + .walk(params.localDir) + .map((localFile) => localFile.replace(directoryPath, version.remotePath)); } return Rx.Observable.create(function (observer) { logger.debug(`Starting upload with following S3 config ${logger.pretty(params)}`); diff --git a/configuration/index.js b/configuration/index.js index c9e2597..91323bb 100644 --- a/configuration/index.js +++ b/configuration/index.js @@ -5,6 +5,7 @@ module.exports = function (pkgInfo) { throw 'Missing configuration options from package.json'; } var config = pkgInfo['ccu']; + var digest = config.digest || {}; return { name: config.name || pkgInfo.name, version: pkgInfo.version, @@ -13,6 +14,8 @@ module.exports = function (pkgInfo) { bucket: config.bucket, cdn: config.cdn, mainBundleFile: config.mainBundleFile, - snapshotName: config.snapshotName + snapshotName: config.snapshotName, + hashes: Array.isArray(digest.hashes) ? digest.hashes : [], + hashOnly: Array.isArray(digest.extensions) ? digest.extensions : [] }; }; \ No newline at end of file diff --git a/files/index.js b/files/index.js new file mode 100644 index 0000000..951ee1f --- /dev/null +++ b/files/index.js @@ -0,0 +1,27 @@ +'use strict'; + +const walk = require('walk'); +const path = require('path'); +const Rx = require('rx'); + +module.exports = { + write: (filePath, contents) => fs.writeFileSync(filePath, contents, { encoding:'utf8' }), + walk: (directory) => { + return Rx.Observable.create((observer) => { + const walker = walk.walk(directory, { followLinks: false }); + walker.on('file', (root, stats, next) => { + const workingDir = process.cwd(); + const localPath = path.relative(workingDir, path.resolve(root, stats.name)); + observer.next(localPath); + next(); + }); + walker.on('error', (root, stats, next) => { + observer.onError(stats.error); + next(); + }); + walker.on('end', () => { + observer.onCompleted(); + }); + }); + } +}; diff --git a/hash/digest.js b/hash/digest.js new file mode 100644 index 0000000..7d3bffd --- /dev/null +++ b/hash/digest.js @@ -0,0 +1,41 @@ +'use strict'; + +const Rx = require('rx'); +const from = Rx.Observable.from; +const path = require('path'); +const fs = require('fs'); +const crypto = require('crypto'); + +const availableDigests = ['sha256', 'sha384', 'sha512']; + +const fromFile = (file, hash) => { + return Rx.Observable.create((observer) => { + const fd = fs.createReadStream(file); + fd.on('end', function() { + hash.end(); + const value = hash.read(); + observer.next(value); + observer.onCompleted(); + }); + fd.on('error', (error) => observer.onError(error)); + fd.pipe(hash); + return () => {}; + }); +}; + +const digest = (method, file) => { + const hash = crypto.createHash(method); + hash.setEncoding('base64'); + return fromFile(file, hash).map((value) => { + return { file, digest: value, method }; + }); +}; + +module.exports = (file, options) => { + const digests = availableDigests.filter((d) => options.hashes.length == 0 || options.hashes.indexOf(d) != -1); + return Rx.Observable + .from(digests) + .flatMap((method) => digest(method, file)); +}; + +module.exports.available = availableDigests; \ No newline at end of file diff --git a/hash/index.js b/hash/index.js new file mode 100644 index 0000000..7f74696 --- /dev/null +++ b/hash/index.js @@ -0,0 +1,34 @@ +'use strict'; + +const Rx = require('rx'); +const from = Rx.Observable.from; +const files = require('../files'); +const digest = require('./digest'); +const path = require('path'); + +module.exports = function(options) { + if (options.hashes.length == 0) { + return Rx.Observable.empty(); + } + const logger = options.logger; + const ignoredExtensions = digest.available.map((d) => `.${d}`); + const hashOnly = options.hashOnly; + logger.debug(`Checking for files to hash in ${options.localPaths}`); + return from(options.localPaths).map(function (directoryPath) { + logger.debug(`Starting to hash files in ${directoryPath}`); + return files.walk(directoryPath) + .filter((filePath) => { + const parts = path.parse(filePath); + return ignoredExtensions.indexOf(parts.ext) == -1 && (options.hashOnly.length == 0 || options.hashOnly.indexOf(parts.ext) != -1); + }) + .flatMap((localPath) => { + return digest(localPath, options) + }) + }) + .concatAll() + .doOnNext((value) => { + if (!options.dry) { + files.write(`${value.file}.${value.method}`, value.digest); + } + }); +} \ No newline at end of file diff --git a/index.js b/index.js index 4b0c759..bf3da7c 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,7 @@ var just = Rx.Observable.just; var from = Rx.Observable.from; var Logger = require('./logger'); var extend = require('util')._extend; +var hash = require('./hash'); module.exports = function (options) { var logger = new Logger(options); @@ -15,13 +16,18 @@ module.exports = function (options) { logger.debug(`Starting upload process with parameters ${logger.pretty(options)}`); var state = Object.assign({ logger: logger }, options); var cdn = new CDN(state); - cdn.exists(resolver.full(state).remotePath) - .tapOnNext(function (exists) { - if(exists) { - logger.warn(`File ${state.mainBundleFile} exists for version ${state.version}`); - } - }) - .flatMap(function(exist) { + Rx.Observable.forkJoin([ + cdn.exists(resolver.full(state).remotePath).tapOnNext(function (exists) { + if(exists) { + logger.warn(`File ${state.mainBundleFile} exists for version ${state.version}`); + } + }), + hash(state).tapOnNext(function (result) { + logger.debug(`File ${result.file} has ${result.method} digest ${result.digest}`); + }) + ]) + .flatMap(function(result) { + const exist = result[0]; return from(resolver.for(state, exist)) .flatMap(function (version) { return aws.uploader(version, state); diff --git a/sample/package-lock.json b/sample/package-lock.json new file mode 100644 index 0000000..8bae806 --- /dev/null +++ b/sample/package-lock.json @@ -0,0 +1,2067 @@ +{ + "name": "sample-dus", + "version": "10.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@auth0/component-cdn-uploader": { + "version": "2.0.0", + "requires": { + "chalk": "1.1.3", + "meow": "3.7.0", + "request": "2.81.0", + "rx": "4.1.0", + "s3": "4.4.0", + "semver": "5.3.0", + "walk": "2.3.9" + }, + "dependencies": { + "@auth0/component-cdn-uploader": { + "version": "2.0.0", + "bundled": true, + "requires": { + "chalk": "1.1.3", + "meow": "3.7.0", + "request": "2.87.0", + "rx": "4.1.0", + "s3": "4.4.0", + "semver": "5.5.0", + "walk": "2.3.13" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "bundled": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "array-find-index": { + "version": "1.0.2", + "bundled": true + }, + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true + }, + "aws-sdk": { + "version": "2.0.31", + "bundled": true, + "requires": { + "xml2js": "0.2.6", + "xmlbuilder": "0.4.2" + } + }, + "aws-sign2": { + "version": "0.7.0", + "bundled": true + }, + "aws4": { + "version": "1.7.0", + "bundled": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true + }, + "camelcase": { + "version": "2.1.1", + "bundled": true + }, + "camelcase-keys": { + "version": "2.1.0", + "bundled": true, + "requires": { + "camelcase": "2.1.1", + "map-obj": "1.0.1" + } + }, + "caseless": { + "version": "0.12.0", + "bundled": true + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "co": { + "version": "4.6.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.6", + "bundled": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "currently-unhandled": { + "version": "0.4.1", + "bundled": true, + "requires": { + "array-find-index": "1.0.2" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "bundled": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "error-ex": { + "version": "1.3.1", + "bundled": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "extend": { + "version": "3.0.1", + "bundled": true + }, + "extsprintf": { + "version": "1.3.0", + "bundled": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "bundled": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "bundled": true + }, + "fd-slicer": { + "version": "1.0.1", + "bundled": true, + "requires": { + "pend": "1.2.0" + } + }, + "find-up": { + "version": "1.1.2", + "bundled": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "findit2": { + "version": "2.2.3", + "bundled": true + }, + "foreachasync": { + "version": "3.0.0", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "2.3.2", + "bundled": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.18" + } + }, + "get-stdin": { + "version": "4.0.1", + "bundled": true + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "har-schema": { + "version": "2.0.0", + "bundled": true + }, + "har-validator": { + "version": "5.0.3", + "bundled": true, + "requires": { + "ajv": "5.5.2", + "har-schema": "2.0.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "hosted-git-info": { + "version": "2.6.0", + "bundled": true + }, + "http-signature": { + "version": "1.2.0", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.2" + } + }, + "indent-string": { + "version": "2.1.0", + "bundled": true, + "requires": { + "repeating": "2.0.1" + } + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-finite": { + "version": "1.0.2", + "bundled": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "is-utf8": { + "version": "0.2.1", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "bundled": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "jsprim": { + "version": "1.4.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "bundled": true, + "requires": { + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" + } + }, + "map-obj": { + "version": "1.0.1", + "bundled": true + }, + "meow": { + "version": "3.7.0", + "bundled": true, + "requires": { + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" + } + }, + "mime": { + "version": "1.2.11", + "bundled": true + }, + "mime-db": { + "version": "1.33.0", + "bundled": true + }, + "mime-types": { + "version": "2.1.18", + "bundled": true, + "requires": { + "mime-db": "1.33.0" + } + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true + } + } + }, + "natives": { + "version": "1.1.4", + "bundled": true + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "requires": { + "hosted-git-info": "2.6.0", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-type": { + "version": "1.1.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pend": { + "version": "1.2.0", + "bundled": true + }, + "performance-now": { + "version": "2.1.0", + "bundled": true + }, + "pify": { + "version": "2.3.0", + "bundled": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "punycode": { + "version": "1.4.1", + "bundled": true + }, + "qs": { + "version": "6.5.2", + "bundled": true + }, + "read-pkg": { + "version": "1.1.0", + "bundled": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "bundled": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "redent": { + "version": "1.0.0", + "bundled": true, + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + } + }, + "repeating": { + "version": "2.0.1", + "bundled": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.87.0", + "bundled": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.7.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.2", + "safe-buffer": "5.1.2", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" + } + }, + "rimraf": { + "version": "2.2.8", + "bundled": true + }, + "rx": { + "version": "4.1.0", + "bundled": true + }, + "s3": { + "version": "4.4.0", + "bundled": true, + "requires": { + "aws-sdk": "2.0.31", + "fd-slicer": "1.0.1", + "findit2": "2.2.3", + "graceful-fs": "3.0.11", + "mime": "1.2.11", + "mkdirp": "0.5.1", + "pend": "1.2.0", + "rimraf": "2.2.8", + "streamsink": "1.2.0" + }, + "dependencies": { + "graceful-fs": { + "version": "3.0.11", + "bundled": true, + "requires": { + "natives": "1.1.4" + } + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "sax": { + "version": "0.4.2", + "bundled": true + }, + "semver": { + "version": "5.5.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true + }, + "sshpk": { + "version": "1.14.2", + "bundled": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "safer-buffer": "2.1.2", + "tweetnacl": "0.14.5" + } + }, + "streamsink": { + "version": "1.2.0", + "bundled": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "bundled": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-indent": { + "version": "1.0.1", + "bundled": true, + "requires": { + "get-stdin": "4.0.1" + } + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + }, + "tough-cookie": { + "version": "2.3.4", + "bundled": true, + "requires": { + "punycode": "1.4.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "bundled": true + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "optional": true + }, + "uuid": { + "version": "3.2.1", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.3", + "bundled": true, + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "verror": { + "version": "1.10.0", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, + "walk": { + "version": "2.3.13", + "bundled": true, + "requires": { + "foreachasync": "3.0.0" + } + }, + "xml2js": { + "version": "0.2.6", + "bundled": true, + "requires": { + "sax": "0.4.2" + } + }, + "xmlbuilder": { + "version": "0.4.2", + "bundled": true + } + } + }, + "abbrev": { + "version": "1.0.9", + "bundled": true + }, + "ajv": { + "version": "4.11.7", + "bundled": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "align-text": { + "version": "0.1.4", + "bundled": true, + "requires": { + "kind-of": "3.1.0", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "bundled": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "argparse": { + "version": "1.0.9", + "bundled": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "array-find-index": { + "version": "1.0.2", + "bundled": true + }, + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "assertion-error": { + "version": "1.0.2", + "bundled": true + }, + "async": { + "version": "1.5.2", + "bundled": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true + }, + "aws-sdk": { + "version": "2.0.31", + "bundled": true, + "requires": { + "xml2js": "0.2.6", + "xmlbuilder": "0.4.2" + } + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.0", + "bundled": true + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true + }, + "camelcase": { + "version": "2.1.1", + "bundled": true + }, + "camelcase-keys": { + "version": "2.1.0", + "bundled": true, + "requires": { + "camelcase": "2.1.1", + "map-obj": "1.0.1" + } + }, + "caseless": { + "version": "0.12.0", + "bundled": true + }, + "center-align": { + "version": "0.1.3", + "bundled": true, + "optional": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chai": { + "version": "3.5.0", + "bundled": true, + "requires": { + "assertion-error": "1.0.2", + "deep-eql": "0.1.3", + "type-detect": "1.0.0" + } + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "bundled": true + } + } + }, + "cliui": { + "version": "2.1.0", + "bundled": true, + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "bundled": true, + "optional": true + } + } + }, + "co": { + "version": "4.6.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.9.0", + "bundled": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "requires": { + "boom": "2.10.1" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "bundled": true, + "requires": { + "array-find-index": "1.0.2" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "debug": { + "version": "2.2.0", + "bundled": true, + "requires": { + "ms": "0.7.1" + } + }, + "decamelize": { + "version": "1.2.0", + "bundled": true + }, + "deep-eql": { + "version": "0.1.3", + "bundled": true, + "requires": { + "type-detect": "0.1.1" + }, + "dependencies": { + "type-detect": { + "version": "0.1.1", + "bundled": true + } + } + }, + "deep-equal": { + "version": "1.0.1", + "bundled": true + }, + "deep-is": { + "version": "0.1.3", + "bundled": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true + }, + "diff": { + "version": "1.4.0", + "bundled": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "error-ex": { + "version": "1.3.1", + "bundled": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "escodegen": { + "version": "1.8.1", + "bundled": true, + "requires": { + "esprima": "2.7.3", + "estraverse": "1.9.3", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.2.0" + }, + "dependencies": { + "source-map": { + "version": "0.2.0", + "bundled": true, + "optional": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "esprima": { + "version": "2.7.3", + "bundled": true + }, + "estraverse": { + "version": "1.9.3", + "bundled": true + }, + "esutils": { + "version": "2.0.2", + "bundled": true + }, + "extend": { + "version": "3.0.0", + "bundled": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "bundled": true + }, + "fd-slicer": { + "version": "1.0.1", + "bundled": true, + "requires": { + "pend": "1.2.0" + } + }, + "fill-keys": { + "version": "1.0.2", + "bundled": true, + "requires": { + "is-object": "1.0.1", + "merge-descriptors": "1.0.1" + } + }, + "find-up": { + "version": "1.1.2", + "bundled": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "findit2": { + "version": "2.2.3", + "bundled": true + }, + "foreachasync": { + "version": "3.0.0", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "get-stdin": { + "version": "4.0.1", + "bundled": true + }, + "getpass": { + "version": "0.1.6", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "glob": { + "version": "7.0.5", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.3", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "graceful-readlink": { + "version": "1.0.1", + "bundled": true + }, + "growl": { + "version": "1.9.2", + "bundled": true + }, + "handlebars": { + "version": "4.0.6", + "bundled": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.22" + } + }, + "har-schema": { + "version": "1.0.5", + "bundled": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "requires": { + "ajv": "4.11.7", + "har-schema": "1.0.5" + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "1.0.0", + "bundled": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true + }, + "hosted-git-info": { + "version": "2.4.2", + "bundled": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + }, + "dependencies": { + "assert-plus": { + "version": "0.2.0", + "bundled": true + } + } + }, + "indent-string": { + "version": "2.1.0", + "bundled": true, + "requires": { + "repeating": "2.0.1" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true + }, + "is-buffer": { + "version": "1.1.5", + "bundled": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-finite": { + "version": "1.0.2", + "bundled": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-object": { + "version": "1.0.1", + "bundled": true + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "is-utf8": { + "version": "0.2.1", + "bundled": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "istanbul": { + "bundled": true, + "requires": { + "abbrev": "1.0.9", + "async": "1.5.2", + "escodegen": "1.8.1", + "esprima": "2.7.3", + "glob": "5.0.15", + "handlebars": "4.0.6", + "js-yaml": "3.8.3", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "once": "1.4.0", + "resolve": "1.1.7", + "supports-color": "3.2.3", + "which": "1.2.14", + "wordwrap": "1.0.0" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "bundled": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.3", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "supports-color": { + "version": "3.2.3", + "bundled": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "js-yaml": { + "version": "3.8.3", + "bundled": true, + "requires": { + "argparse": "1.0.9", + "esprima": "3.1.3" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "bundled": true + } + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "json3": { + "version": "3.3.2", + "bundled": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + } + }, + "kind-of": { + "version": "3.1.0", + "bundled": true, + "requires": { + "is-buffer": "1.1.5" + } + }, + "lazy-cache": { + "version": "1.0.4", + "bundled": true, + "optional": true + }, + "levn": { + "version": "0.3.0", + "bundled": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "1.1.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "lodash": { + "version": "4.17.4", + "bundled": true + }, + "lodash._baseassign": { + "version": "3.2.0", + "bundled": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "bundled": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "bundled": true + }, + "lodash._getnative": { + "version": "3.9.1", + "bundled": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "bundled": true + }, + "lodash.create": { + "version": "3.1.1", + "bundled": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "bundled": true + }, + "lodash.isarray": { + "version": "3.0.4", + "bundled": true + }, + "lodash.keys": { + "version": "3.1.2", + "bundled": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "longest": { + "version": "1.0.1", + "bundled": true + }, + "loud-rejection": { + "version": "1.6.0", + "bundled": true, + "requires": { + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" + } + }, + "map-obj": { + "version": "1.0.1", + "bundled": true + }, + "meow": { + "version": "3.7.0", + "bundled": true, + "requires": { + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.3.6", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "bundled": true + }, + "mime": { + "version": "1.2.11", + "bundled": true + }, + "mime-db": { + "version": "1.27.0", + "bundled": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.3", + "bundled": true, + "requires": { + "brace-expansion": "1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "bundled": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.5", + "glob": "7.0.5", + "growl": "1.9.2", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + } + }, + "module-not-found-error": { + "version": "1.0.1", + "bundled": true + }, + "ms": { + "version": "0.7.1", + "bundled": true + }, + "natives": { + "version": "1.1.0", + "bundled": true + }, + "nock": { + "bundled": true, + "requires": { + "chai": "3.5.0", + "debug": "2.2.0", + "deep-equal": "1.0.1", + "json-stringify-safe": "5.0.1", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "propagate": "0.4.0", + "qs": "6.4.0" + }, + "dependencies": { + "changelog": { + "version": "https://registry.npmjs.org/changelog/-/changelog-1.0.7.tgz", + "bundled": true, + "requires": { + "lodash": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "request": "2.81.0" + }, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "bundled": true + } + } + } + } + }, + "nopt": { + "version": "3.0.6", + "bundled": true, + "requires": { + "abbrev": "1.0.9" + } + }, + "normalize-package-data": { + "version": "2.3.6", + "bundled": true, + "requires": { + "hosted-git-info": "2.4.2", + "is-builtin-module": "1.0.0", + "semver": "5.3.0", + "validate-npm-package-license": "3.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "optimist": { + "version": "0.6.1", + "bundled": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "bundled": true + } + } + }, + "optionator": { + "version": "0.8.2", + "bundled": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "path-type": { + "version": "1.1.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pend": { + "version": "1.2.0", + "bundled": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true + }, + "pify": { + "version": "2.3.0", + "bundled": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "prelude-ls": { + "version": "1.1.2", + "bundled": true + }, + "propagate": { + "version": "0.4.0", + "bundled": true + }, + "proxyquire": { + "bundled": true, + "requires": { + "fill-keys": "1.0.2", + "module-not-found-error": "1.0.1", + "resolve": "1.1.7" + } + }, + "punycode": { + "version": "1.4.1", + "bundled": true + }, + "qs": { + "version": "6.4.0", + "bundled": true + }, + "read-pkg": { + "version": "1.1.0", + "bundled": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.3.6", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "bundled": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "redent": { + "version": "1.0.0", + "bundled": true, + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + } + }, + "repeat-string": { + "version": "1.6.1", + "bundled": true + }, + "repeating": { + "version": "2.0.1", + "bundled": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.0", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + } + }, + "resolve": { + "version": "1.1.7", + "bundled": true + }, + "right-align": { + "version": "0.1.3", + "bundled": true, + "optional": true, + "requires": { + "align-text": "0.1.4" + } + }, + "rimraf": { + "version": "2.2.8", + "bundled": true + }, + "rx": { + "version": "4.1.0", + "bundled": true + }, + "s3": { + "version": "4.4.0", + "bundled": true, + "requires": { + "aws-sdk": "2.0.31", + "fd-slicer": "1.0.1", + "findit2": "2.2.3", + "graceful-fs": "3.0.11", + "mime": "1.2.11", + "mkdirp": "0.5.1", + "pend": "1.2.0", + "rimraf": "2.2.8", + "streamsink": "1.2.0" + }, + "dependencies": { + "graceful-fs": { + "version": "3.0.11", + "bundled": true, + "requires": { + "natives": "1.1.0" + } + } + } + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true + }, + "sax": { + "version": "0.4.2", + "bundled": true + }, + "semver": { + "version": "5.3.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + }, + "source-map": { + "version": "0.4.4", + "bundled": true, + "requires": { + "amdefine": "1.0.1" + } + }, + "spdx-correct": { + "version": "1.0.2", + "bundled": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "bundled": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "bundled": true + }, + "sprintf-js": { + "version": "1.0.3", + "bundled": true + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.6", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + } + }, + "streamsink": { + "version": "1.2.0", + "bundled": true + }, + "stringstream": { + "version": "0.0.5", + "bundled": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "bundled": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-indent": { + "version": "1.0.1", + "bundled": true, + "requires": { + "get-stdin": "4.0.1" + } + }, + "supports-color": { + "version": "3.1.2", + "bundled": true, + "requires": { + "has-flag": "1.0.0" + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "requires": { + "punycode": "1.4.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "bundled": true + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "bundled": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "type-detect": { + "version": "1.0.0", + "bundled": true + }, + "uglify-js": { + "version": "2.8.22", + "bundled": true, + "optional": true, + "requires": { + "source-map": "0.5.6", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.6", + "bundled": true, + "optional": true + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "uuid": { + "version": "3.0.1", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "bundled": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "requires": { + "extsprintf": "1.0.2" + } + }, + "walk": { + "version": "2.3.9", + "bundled": true, + "requires": { + "foreachasync": "3.0.0" + } + }, + "which": { + "version": "1.2.14", + "bundled": true, + "requires": { + "isexe": "2.0.0" + } + }, + "window-size": { + "version": "0.1.0", + "bundled": true, + "optional": true + }, + "wordwrap": { + "version": "1.0.0", + "bundled": true + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "xml2js": { + "version": "0.2.6", + "bundled": true, + "requires": { + "sax": "0.4.2" + } + }, + "xmlbuilder": { + "version": "0.4.2", + "bundled": true + }, + "yargs": { + "version": "3.10.0", + "bundled": true, + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "bundled": true, + "optional": true + } + } + } + } + } + } +} diff --git a/sample/package.json b/sample/package.json index 6f50ba2..cefc70b 100644 --- a/sample/package.json +++ b/sample/package.json @@ -9,12 +9,19 @@ }, "author": "", "license": "ISC", + "dependencies": { + "@auth0/component-cdn-uploader": "^2.0.0" + }, "ccu": { "name": "lock", "cdn": "https://cdn.auth0.com", "mainBundleFile": "lock.min.js", "bucket": "hzalaz", "remoteBasePath": "js", - "snapshotName": "development" + "snapshotName": "development", + "digest": { + "hashes": ["sha384", "sha256"], + "extensions": [".js", ".css"] + } } } diff --git a/sample/test-resources/lock.js b/sample/test-resources/lock.js index e69de29..e906f5e 100644 --- a/sample/test-resources/lock.js +++ b/sample/test-resources/lock.js @@ -0,0 +1 @@ +function Random() {}; \ No newline at end of file diff --git a/sample/test-resources/lock.js.sha256 b/sample/test-resources/lock.js.sha256 new file mode 100644 index 0000000..b65c21f --- /dev/null +++ b/sample/test-resources/lock.js.sha256 @@ -0,0 +1 @@ +qyoUQa4ZCWx7U1v8VSHnSV+v3+dzlR+Nl46OCPCYy5E= \ No newline at end of file diff --git a/sample/test-resources/lock.js.sha384 b/sample/test-resources/lock.js.sha384 new file mode 100644 index 0000000..d3ace46 --- /dev/null +++ b/sample/test-resources/lock.js.sha384 @@ -0,0 +1 @@ +GIK71FW/lkngojLMWFGxR80Dd3Xgz75HiEwh5dp5crVGerwYNZFD8Cls+Jn4xFp4 \ No newline at end of file diff --git a/sample/test-resources/lock.js.sha512 b/sample/test-resources/lock.js.sha512 new file mode 100644 index 0000000..d9be91f --- /dev/null +++ b/sample/test-resources/lock.js.sha512 @@ -0,0 +1 @@ +3SiT9eeqCENJLBv9k3Hh+cUN3sA5VAYjGRgJ1UQhlAnWLypBlYdAbqzZWGzvC2uwdKLIoIXpK7kvQZY8CyPgoQ== \ No newline at end of file diff --git a/sample/test-resources/lock.min.js.map.sha256 b/sample/test-resources/lock.min.js.map.sha256 new file mode 100644 index 0000000..a53bce1 --- /dev/null +++ b/sample/test-resources/lock.min.js.map.sha256 @@ -0,0 +1 @@ +47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= \ No newline at end of file diff --git a/sample/test-resources/lock.min.js.map.sha384 b/sample/test-resources/lock.min.js.map.sha384 new file mode 100644 index 0000000..de14a64 --- /dev/null +++ b/sample/test-resources/lock.min.js.map.sha384 @@ -0,0 +1 @@ +OLBgp1GsljhM2TJ+sbHjaiH9txEUvgdDTAzHv2P24donTt6/529l+9Ua0vFImLlb \ No newline at end of file diff --git a/sample/test-resources/lock.min.js.map.sha512 b/sample/test-resources/lock.min.js.map.sha512 new file mode 100644 index 0000000..28a3531 --- /dev/null +++ b/sample/test-resources/lock.min.js.map.sha512 @@ -0,0 +1 @@ +z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg== \ No newline at end of file diff --git a/sample/test-resources/lock.min.js.sha256 b/sample/test-resources/lock.min.js.sha256 new file mode 100644 index 0000000..a53bce1 --- /dev/null +++ b/sample/test-resources/lock.min.js.sha256 @@ -0,0 +1 @@ +47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= \ No newline at end of file diff --git a/sample/test-resources/lock.min.js.sha384 b/sample/test-resources/lock.min.js.sha384 new file mode 100644 index 0000000..de14a64 --- /dev/null +++ b/sample/test-resources/lock.min.js.sha384 @@ -0,0 +1 @@ +OLBgp1GsljhM2TJ+sbHjaiH9txEUvgdDTAzHv2P24donTt6/529l+9Ua0vFImLlb \ No newline at end of file diff --git a/sample/test-resources/lock.min.js.sha512 b/sample/test-resources/lock.min.js.sha512 new file mode 100644 index 0000000..28a3531 --- /dev/null +++ b/sample/test-resources/lock.min.js.sha512 @@ -0,0 +1 @@ +z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg== \ No newline at end of file diff --git a/sample/test-resources/lock.sha256 b/sample/test-resources/lock.sha256 new file mode 100644 index 0000000..a53bce1 --- /dev/null +++ b/sample/test-resources/lock.sha256 @@ -0,0 +1 @@ +47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= \ No newline at end of file diff --git a/sample/test-resources/lock.sha384 b/sample/test-resources/lock.sha384 new file mode 100644 index 0000000..de14a64 --- /dev/null +++ b/sample/test-resources/lock.sha384 @@ -0,0 +1 @@ +OLBgp1GsljhM2TJ+sbHjaiH9txEUvgdDTAzHv2P24donTt6/529l+9Ua0vFImLlb \ No newline at end of file diff --git a/sample/test-resources/lock.sha512 b/sample/test-resources/lock.sha512 new file mode 100644 index 0000000..28a3531 --- /dev/null +++ b/sample/test-resources/lock.sha512 @@ -0,0 +1 @@ +z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg== \ No newline at end of file diff --git a/sample/test-resources/vendor/underscore.js.sha256 b/sample/test-resources/vendor/underscore.js.sha256 new file mode 100644 index 0000000..a53bce1 --- /dev/null +++ b/sample/test-resources/vendor/underscore.js.sha256 @@ -0,0 +1 @@ +47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= \ No newline at end of file diff --git a/sample/test-resources/vendor/underscore.js.sha384 b/sample/test-resources/vendor/underscore.js.sha384 new file mode 100644 index 0000000..de14a64 --- /dev/null +++ b/sample/test-resources/vendor/underscore.js.sha384 @@ -0,0 +1 @@ +OLBgp1GsljhM2TJ+sbHjaiH9txEUvgdDTAzHv2P24donTt6/529l+9Ua0vFImLlb \ No newline at end of file diff --git a/sample/test-resources/vendor/underscore.js.sha512 b/sample/test-resources/vendor/underscore.js.sha512 new file mode 100644 index 0000000..28a3531 --- /dev/null +++ b/sample/test-resources/vendor/underscore.js.sha512 @@ -0,0 +1 @@ +z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg== \ No newline at end of file diff --git a/test/configuration.test.js b/test/configuration.test.js index 042291c..4c3e8dc 100644 --- a/test/configuration.test.js +++ b/test/configuration.test.js @@ -30,7 +30,9 @@ describe('configuration', function () { bucket: 'hzalaz', cdn: 'https://cdn.auth0.com', mainBundleFile: 'lock.min.js', - snapshotName: undefined + snapshotName: undefined, + hashes: [], + hashOnly: [] }); }); diff --git a/test/files.test.js b/test/files.test.js new file mode 100644 index 0000000..34ca259 --- /dev/null +++ b/test/files.test.js @@ -0,0 +1,61 @@ +'use strict'; + +var expect = require('chai').expect; +var proxyrequire = require('proxyquire'); +var events = require('events'); +var Rx = require('rx'); + +describe('files', function () { + + var walker, emitter, files; + + beforeEach(function () { + emitter = new events.EventEmitter(); + walker = () => { + return emitter; + }; + + files = proxyrequire('../files', {'walk': {walk: walker}}); + }); + + it('should return observable', function () { + expect(files.walk('build')).to.be.instanceOf(Rx.Observable); + }); + + const directory = 'auth0/build'; + + it('should emit found file', function (done) { + const walker = files.walk(directory); + walker + .doOnNext((value) => { + expect(value).to.equals(`${directory}/file.js`); + done(); + }) + .subscribe(); + emitter.emit('file', directory, {name: 'file.js'}, () => {}); + emitter.emit('end'); + }); + + it('should complete on walker end', function (done) { + const walker = files.walk(directory); + walker + .doOnCompleted(() => { + done(); + }) + .subscribe(); + emitter.emit('end'); + }); + + it('should report walker error', function (done) { + const walker = files.walk(directory); + const error = new Error('MOCK'); + walker + .doOnError((err) => { + expect(err).to.eql(error); + done(); + }) + .subscribe(); + emitter.emit('error', directory, { error }, () => {}); + }); + +}); diff --git a/test/hash.test.js b/test/hash.test.js new file mode 100644 index 0000000..7cb7bc4 --- /dev/null +++ b/test/hash.test.js @@ -0,0 +1,109 @@ +'use strict'; + +const expect = require('chai').expect; +const proxyrequire = require('proxyquire'); +const Rx = require('rx'); +const Logger = require('../logger'); + +describe('hash', function () { + + const logger = new Logger({logLevels: []}); + + it('should generate hash', function(done) { + const result = {file: 'file.js', method: 'sha256', value: 'hash1'}; + const digest = () => Rx.Observable.just(result); + digest.available = ['sha256']; + const hash = proxyrequire('../hash', { + '../files': { walk: () => Rx.Observable.just('file.js') }, + './digest': digest + }); + + hash({localPaths: ['build'], dry: true, logger, hashes: ['sha256'], hashOnly: []}) + .doOnNext((value) => { + expect(value).to.eql(result); + done(); + }) + .subscribe(); + }); + + it('should generate hash ignoring hash files', function(done) { + const digest = (p) => Rx.Observable.just({file: p, method: 'sha256', digest: 'hash1'}); + digest.available = ['sha256']; + const hash = proxyrequire('../hash', { + '../files': { walk: () => Rx.Observable.from(['file.js', 'file.js.sha256']) }, + './digest': digest + }); + + hash({localPaths: ['build'], dry: true, logger, hashes: ['sha256'], hashOnly: []}) + .map((r) => r.file) + .toArray() + .doOnNext((value) => { + expect(value).to.eql(['file.js']); + done(); + }) + .subscribe(); + }); + + it('should generate no hash by default', function(done) { + const digest = (p) => Rx.Observable.just({file: p, method: 'sha256', digest: 'hash1'}); + digest.available = ['sha256']; + const hash = proxyrequire('../hash', { + '../files': { walk: () => Rx.Observable.from(['file.js', 'file.js.sha256']) }, + './digest': digest + }); + + hash({localPaths: ['build'], dry: true, logger, hashes: [], hashOnly: []}) + .map((r) => r.file) + .toArray() + .doOnNext((value) => { + expect(value).to.eql([]); + done(); + }) + .subscribe(); + }); + + it('should generate hash ignoring specific files', function(done) { + const digest = (p) => Rx.Observable.just({file: p, method: 'sha256', digest: 'hash1'}); + digest.available = ['sha256']; + const hash = proxyrequire('../hash', { + '../files': { walk: () => Rx.Observable.from(['file.js', 'file.css']) }, + './digest': digest + }); + + hash({localPaths: ['build'], dry: true, logger, hashes: ['sha256'], hashOnly: ['.js']}) + .map((r) => r.file) + .toArray() + .doOnNext((value) => { + expect(value).to.eql(['file.js']); + done(); + }) + .subscribe(); + }); + + it('should write hash to file', function(done) { + var filePath, contents; + const result = {file: 'file.js', method: 'sha256', digest: 'hash1'}; + const digest = () => Rx.Observable.just(result); + digest.available = ['sha256']; + const hash = proxyrequire('../hash', { + '../files': { + walk: () => Rx.Observable.just('file.js'), + write: (p, c) => { + filePath = p; + contents = c; + } + }, + './digest': digest + }); + + hash({localPaths: ['build'], logger, hashes: ['sha256'], hashOnly: []}) + .doOnNext((value) => { + expect(value).to.eql(result); + expect(filePath).to.eql('file.js.sha256'); + expect(contents).to.eql('hash1'); + done(); + }) + .subscribe(); + }); + +}); diff --git a/test/index.test.js b/test/index.test.js index adcfd55..9574798 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -39,8 +39,11 @@ describe('uploader', function () { return Rx.Observable.just(false); }; }; + var hash = function () { + return Rx.Observable.just({}); + }; - var uploader = proxyrequire('../index', {'./aws': aws, './cdn': doesNotExist}); + var uploader = proxyrequire('../index', {'./aws': aws, './cdn': doesNotExist, './hash': hash}); options.snapshot = false; uploader(options); });