node-cipher
Advanced tools
Comparing version 3.0.1 to 4.0.0
/** | ||
* NodeCipher class definition. | ||
* Securely encrypt and decrypt sensitive files for use in public source | ||
* control. | ||
* | ||
* @module lib/nodeCipher | ||
* @exports {NodeCipher} | ||
* @author Nathan Buchar | ||
@@ -12,5 +14,5 @@ * @since 3.0.0 | ||
let _ = require('lodash'); | ||
let assert = require('assert'); | ||
let crypto = require('crypto'); | ||
let fs = require('fs'); | ||
let validate = require('validate'); | ||
@@ -36,17 +38,38 @@ /** | ||
* @prop {Array} _algorithms | ||
* @default null | ||
* @private | ||
*/ | ||
this._algorithms = null; | ||
this._algorithms = crypto.getCiphers(); | ||
} | ||
this._init(); | ||
/** | ||
* Parse the options provided and fill in any missing options with default | ||
* values. | ||
* | ||
* @param {Object} options | ||
* @returns {Object} opts | ||
* @private | ||
*/ | ||
_parseOptions(options) { | ||
return _.defaults(options, NodeCipher.Defaults); | ||
} | ||
/** | ||
* Initialize this NodeCipher instance. | ||
* Validates that all NodeCipher options follow the proper schema. | ||
* | ||
* @param {Object} options | ||
* @returns {Array} errors | ||
* @private | ||
*/ | ||
_init() { | ||
this._algorithms = crypto.getCiphers(); | ||
_validateOptions(options) { | ||
let errors = NodeCipher.OptionsSchema.validate(options); | ||
// Verify that the chosen algorithm is valid. | ||
if (!_.includes(this._algorithms, options.algorithm)) { | ||
errors.push({ | ||
path: 'algorithm', | ||
message: `"${options.algorithm}" is not a valid cipher algorithm.` | ||
}); | ||
} | ||
return errors; | ||
} | ||
@@ -67,2 +90,10 @@ | ||
let opts = this._parseOptions(options); | ||
let errors = this._validateOptions(opts); | ||
// Return errors back to the user and exit early. | ||
if (errors.length) { | ||
return callback.call(scope, new Error(errors[0].message)); | ||
} | ||
this._xcrypt(options, NodeCipher.Methods.CIPHER, err => { | ||
@@ -86,2 +117,10 @@ callback.call(scope, err); | ||
let opts = this._parseOptions(options); | ||
let errors = this._validateOptions(opts); | ||
// Return errors back to the user and exit early. | ||
if (errors.length) { | ||
return callback.call(scope, new Error(errors[0].message)); | ||
} | ||
this._xcrypt(options, NodeCipher.Methods.DECIPHER, err => { | ||
@@ -102,8 +141,8 @@ callback.call(scope, err); | ||
_xcrypt(options, method, done) { | ||
let opts = this._parseOptions(options); | ||
let cipher = method(opts.algorithm, opts.password); | ||
let streams = this._createReadWriteSteams(opts.input, opts.output); | ||
let readStream = fs.createReadStream(options.input); | ||
let writeStream = fs.createWriteStream(options.output); | ||
let cipher = method(options.algorithm, options.password); | ||
// Wait for the steam to end, then call our "done" function. | ||
streams.read.on('end', () => { | ||
// Wait for the writable steam to end, then call our "done" function. | ||
writeStream.on('finish', () => { | ||
done(null); | ||
@@ -115,7 +154,10 @@ }); | ||
// our writable output stream. | ||
streams.read.on('error', err => { | ||
readStream.on('error', err => { | ||
readStream.unpipe(); | ||
done(err); | ||
}).pipe(cipher).on('error', err => { | ||
readStream.unpipe(); | ||
done(err); | ||
}).pipe(streams.write).on('error', err => { | ||
}).pipe(writeStream).on('error', err => { | ||
readStream.unpipe(); | ||
done(err); | ||
@@ -126,115 +168,62 @@ }); | ||
/** | ||
* Spawns the read and write Node streams. | ||
* The synchronous version of _encrypt(). | ||
* | ||
* @param {string} input | ||
* @param {string} output | ||
* @returns {Object} | ||
* @private | ||
*/ | ||
_createReadWriteSteams(input, output) { | ||
return { | ||
read: fs.createReadStream(input), | ||
write: fs.createWriteStream(output) | ||
}; | ||
} | ||
/** | ||
* Parse the options provided and fill in any missing options with default | ||
* values. | ||
* | ||
* @see _xcryptSync | ||
* @param {Object} options | ||
* @returns {Object} opts | ||
* @private | ||
*/ | ||
_parseOptions(options) { | ||
let opts = _.defaults(options, NodeCipher.Defaults); | ||
_encryptSync(options) { | ||
let opts = this._parseOptions(options); | ||
let errors = this._validateOptions(opts); | ||
this._validateOptions(opts); | ||
// Handle errors. | ||
if (errors.length) { | ||
throw new Error(errors[0].message); | ||
} | ||
return opts; | ||
this._xcryptSync(opts, NodeCipher.Methods.CIPHER); | ||
} | ||
/** | ||
* Validates that all NodeCipher options follow the proper schema. | ||
* The synchronous version of _decrypt(). | ||
* | ||
* @see _xcryptSync | ||
* @param {Object} options | ||
* @private | ||
*/ | ||
_validateOptions(options) { | ||
this._validateInputOption(options.input); | ||
this._validateInputOption(options.output); | ||
this._validateAlgorithmOption(options.algorithm); | ||
this._validatePasswordOption(options.password); | ||
} | ||
_decryptSync(options) { | ||
let opts = this._parseOptions(options); | ||
let errors = this._validateOptions(opts); | ||
/** | ||
* Validates the the "input" option is not undefined, and a string. | ||
* | ||
* @see _validateOptions | ||
* @param {string} opt | ||
* @private | ||
*/ | ||
_validateInputOption(opt) { | ||
// Handle errors. | ||
if (errors.length) { | ||
throw new Error(errors[0].message); | ||
} | ||
// Verify that the option exists. | ||
assert(!_.isUndefined(opt), '"input" must be specified.'); | ||
// Verify that the option is a string. | ||
assert(_.isString(opt), '"input" must be a string.'); | ||
this._xcryptSync(opts, NodeCipher.Methods.DECIPHER); | ||
} | ||
/** | ||
* Validates the the "output" option is not undefined, and a string. | ||
* The synchronous version of _xcrypt(). | ||
* | ||
* @see _validateOptions | ||
* @param {string} opt | ||
* @param {Object} options | ||
* @param {Crypto.<Cipher|Decipher>} method | ||
* @private | ||
*/ | ||
_validateOutputOption(opt) { | ||
_xcryptSync(options, method) { | ||
try { | ||
let inputBuffer = fs.readFileSync(options.input); | ||
let cipher = method(options.algorithm, options.password); | ||
// Verify that the option exists. | ||
assert(!_.isUndefined(opt), '"output" must be specified.'); | ||
// Verify that the option is a string. | ||
assert(_.isString(opt), '"output" must be a string.'); | ||
// Write the ciphered buffer to our output file. | ||
fs.writeFileSync(options.output, Buffer.concat([ | ||
cipher.update(inputBuffer), | ||
cipher.final() | ||
])); | ||
} catch (err) { | ||
throw err; | ||
} | ||
} | ||
/** | ||
* Validates the the "algorithm" option is not undefined, a string, and not | ||
* invalid. | ||
* | ||
* @see _validateOptions | ||
* @param {string} opt | ||
* @private | ||
*/ | ||
_validateAlgorithmOption(opt) { | ||
// Verify that the option exists. | ||
assert(!_.isUndefined(opt), '"algorithm" must be specified.'); | ||
// Verify that the option is a string. | ||
assert(_.isString(opt), '"algorithm" option must be a string.'); | ||
// Verify that the algorithm is valid. | ||
assert(_.includes(this._algorithms, opt), '"' + opt + '" is not a valid ' + | ||
'cipher algorithm.'); | ||
} | ||
/** | ||
* Validates the the "output" option is not undefined, and a string. | ||
* | ||
* @see _validateOptions | ||
* @param {string} opt | ||
* @private | ||
*/ | ||
_validatePasswordOption(opt) { | ||
// Verify that the option exists. | ||
assert(!_.isUndefined(opt), '"password" must be specified.'); | ||
// Verify that the option is a string. | ||
assert(_.isString(opt), '"password" must be a string.'); | ||
} | ||
/** | ||
* Public method for encrypting using the options provided. | ||
@@ -266,4 +255,5 @@ * | ||
/** | ||
* Public method for synchronously encrypting using the options provided. | ||
* The synchronous version of encrypt(). | ||
* | ||
* @see _encryptSync | ||
* @param {Object} options | ||
@@ -273,9 +263,9 @@ * @access public | ||
encryptSync(options) { | ||
// TODO | ||
throw new Error('decryptSync not yet implemented. I\'ll accept PR\'s'); | ||
this._encryptSync(options); | ||
} | ||
/** | ||
* Public method for synchronously decrypting using the options provided. | ||
* The synchronous version of decrypt(). | ||
* | ||
* @see _decryptSync | ||
* @param {Object} options | ||
@@ -285,4 +275,3 @@ * @access public | ||
decryptSync(options) { | ||
// TODO | ||
throw new Error('decryptSync not yet implemented. I\'ll accept PR\'s'); | ||
this._decryptSync(options); | ||
} | ||
@@ -293,2 +282,3 @@ | ||
* | ||
* @returns {Array} | ||
* @access public | ||
@@ -301,12 +291,2 @@ */ | ||
/** | ||
* Gets all valid cipher algorithms. | ||
* | ||
* @returns {Array} | ||
* @access public | ||
*/ | ||
get algorithms() { | ||
return this._algorithms; | ||
} | ||
/** | ||
* Gets NodeCipher defaults. | ||
@@ -320,12 +300,2 @@ * | ||
} | ||
/** | ||
* Gets NodeCipher commands. | ||
* | ||
* @returns {Array} | ||
* @access public | ||
*/ | ||
get commands() { | ||
return NodeCipher.Commands; | ||
} | ||
} | ||
@@ -352,9 +322,27 @@ | ||
/** | ||
* @enum {Array} Commands | ||
* @enum {Object} OptionsSchema | ||
*/ | ||
NodeCipher.Commands = [ | ||
'encrypt', | ||
'decrypt' | ||
]; | ||
NodeCipher.OptionsSchema = validate({ | ||
input: { | ||
type: 'string', | ||
required: true, | ||
message: '"input" is required and must be a string.' | ||
}, | ||
output: { | ||
type: 'string', | ||
required: true, | ||
message: '"output" is required and must be a string.' | ||
}, | ||
password: { | ||
type: 'string', | ||
required: true, | ||
message: '"password" is required and must be a string.' | ||
}, | ||
algorithm: { | ||
type: 'string', | ||
required: true, | ||
message: '"algorithm" is required and must be a string.' | ||
} | ||
}); | ||
module.exports = new NodeCipher(); |
{ | ||
"name": "node-cipher", | ||
"version": "3.0.1", | ||
"version": "4.0.0", | ||
"description": "Securely encrypt sensitive files for use in public source control.", | ||
@@ -10,4 +10,3 @@ "main": "index.js", | ||
"cipher", | ||
"node", | ||
"cli" | ||
"node" | ||
], | ||
@@ -18,24 +17,17 @@ "repository": { | ||
}, | ||
"engines": { | ||
"node": ">=4.0.0" | ||
}, | ||
"author": "Nathan Buchar <hello@nathanbuchar.com>", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/nathanbuchar/node-cipher/issues" | ||
}, | ||
"scripts": { | ||
"test": "./test/run" | ||
"engines": { | ||
"node": ">=4.0.0" | ||
}, | ||
"bin": { | ||
"nodecipher": "./bin/cipher.js" | ||
"author": { | ||
"name": "Nathan Buchar", | ||
"email": "hello@nathanbuchar.com" | ||
}, | ||
"license": "MIT", | ||
"dependencies": { | ||
"assert": "^1.3.0", | ||
"chalk": "^1.1.1", | ||
"inquirer": "^0.8.5", | ||
"lodash": "^4.0.0", | ||
"promise": "^7.0.4", | ||
"yargs": "^3.21.0" | ||
"validate": "^3.0.1" | ||
} | ||
} |
192
README.md
@@ -6,3 +6,5 @@ node-cipher | ||
Looking for the command line tool? [Click here](http://github.com/nathanbuchar/node-cipher-cli). | ||
**Why would I want to encrypt my files?** | ||
@@ -20,24 +22,2 @@ | ||
Table of Contents | ||
----------------- | ||
* [Install](#install) | ||
* [Command Line Interface](#command-line-interface) | ||
* [Usage](#usage) | ||
* [Commands](#commands) | ||
* [Flags](#flags) | ||
* [Node JS API](#node-js-api) | ||
* [Options](#options) | ||
* [Methods](#methods) | ||
* [`encrypt()`](#encryptoptions-callback-scope) | ||
* [`decrypt()`](#decryptoptions-callback-scope) | ||
* [`list()`](#listarray) | ||
* [Tips](#tips) | ||
* [Authors](#authors) | ||
* [License](#license) | ||
*** | ||
Install | ||
@@ -47,76 +27,24 @@ ------- | ||
``` | ||
$ npm install -g node-cipher | ||
$ npm install node-cipher | ||
``` | ||
*** | ||
Options | ||
------- | ||
## Command Line Interface | ||
Looking for the Node JS API? [Click here](#node-js-api). | ||
### Usage | ||
``` | ||
$ nodecipher [--list] <command> -i input -o output [-p password] [-a algorithm] | ||
``` | ||
When in doubt, `$ nodecipher --help` | ||
### Commands | ||
|Command|Description| | ||
|:---|:----------| | ||
|`encrypt`|Encrypts a file using the [arguments](#arguments) provided.| | ||
|`decrypt`|Decrypts a file using the [arguments](#arguments) provided.| | ||
### Flags | ||
|Flag|Alias|Description|Required|Default| | ||
|:---|:----|:----------|:------:|:-----:| | ||
|`input`|`i`|The input filename relative to the current working directory.|✓|| | ||
|`output`|`p`|The output filename relative to the current working directory.|✓|| | ||
|`password`|`p`|The key that you will use to encrypt or decrypt your file. If this is not supplied directly, you will instead be prompted within your command line. If you are decrypting a file, the password must be the same as the one specified during encryption, or else the decryption will fail.||| | ||
|`algorithm`|`a`|The cipher algorithm that you will use to encrypt or decrypt your file. If you are decrypting a file, the chosen algorithm must be the same as the one specified during encryption, or else the decryption will fail.||`cast5-cbc`| | ||
|`list`|`l`|Lists all available cipher algorithms.| | ||
|`version`|`v`|Show the node-cipher version.| | ||
|`help`|`h`|Show the help menu.| | ||
### Example | ||
Encrypts `config.json` into `config.encrypted.json` using the `aes-128-cbc` cipher algorithm. | ||
```bash | ||
$ nodecipher encrypt -i "config.json" -o "config.encrypted.json" -a aes-128-cbc | ||
``` | ||
*** | ||
Node JS API | ||
----------- | ||
Looking for the CLI? [Click here](#command-line-interface). | ||
### Options | ||
|Name|Type|Description|Required|Default| | ||
|:---|:--:|:----------|:------:|:-----:| | ||
|`input`|`string`|The input filename relative to the current working directory.|✓|| | ||
|`output`|`string`|The output filename relative to the current working directory.|✓|| | ||
|`password`|`string`|The encryption password. Unlike the command line interface, this MUST be specified.|✓|| | ||
|`algorithm`|`string`|The algorithm to use. Use `nodecipher -l` to see a list of available cipher algorithms.||`"cast5-cbc"`| | ||
|`input`|`string`|The input file.|✓|| | ||
|`output`|`string`|The output file.|✓|| | ||
|`password`|`string`|The key that you will use to encrypt or decrypt your input file. If you are decrypting a file, the password must be the same as the one specified during encryption, or else the decryption will fail.|✓|| | ||
|`algorithm`|`string`|The cipher algorithm to use. Use [`list()`](#listarray) to see a list of available cipher algorithms.||`"cast5-cbc"`| | ||
### Methods | ||
Methods | ||
------- | ||
* [`encrypt()`](#encryptoptions-callback-scope) | ||
* [`encryptSync()`](#encryptsyncoptions-callback-scope) | ||
* [`decrypt()`](#decryptoptions-callback-scope) | ||
* [`decryptSync()`](#decryptsyncoptions-callback-scope) | ||
* [`list()`](#listarray) | ||
@@ -126,14 +54,14 @@ | ||
#### `encrypt(options[, callback[, scope]])` | ||
### `encrypt(options[, callback[, scope]])` | ||
Encrypt a file using the [options](#options) provided. | ||
Encrypts a file using the [options](#options) provided. | ||
##### Parameters | ||
|Parameter|Type|Description|Required| | ||
|--------:|:--:|:----------|:------:| | ||
|`options`|`Object`|The NodeCipher [options](#options) Object.|✓| | ||
|`callback`|`Function`|The function to call when the encryption has completed.|| | ||
|`scope`|`Object`|The Function scope for the `callback` parameter, if provided.|| | ||
#### Parameters | ||
|Parameter|Type|Description|Required|Default| | ||
|--------:|:--:|:----------|:------:|:-----:| | ||
|`options`|`Object`|See [options](#options).|✓|| | ||
|`callback`|`Function`|The function to call when the encryption has completed.||| | ||
|`scope`|`Object`|The Function scope for the `callback` parameter, if provided.||`null`| | ||
##### Example | ||
#### Example | ||
@@ -158,14 +86,39 @@ Encrypts `config.json` into `config.encrypted.json` using the password `"b0sco"`. | ||
#### `decrypt(options[, callback[, scope]])` | ||
### `encryptSync(options)` | ||
The synchronous version of [`encrypt()`](#encryptoptions-callback-scope). | ||
#### Parameters | ||
|Parameter|Type|Description|Required|Default| | ||
|--------:|:--:|:----------|:------:|:-----:| | ||
|`options`|`Object`|See [options](#options).|✓|| | ||
#### Example | ||
Synchronously encrypts `config.json` into `config.encrypted.json` using the password `"b0sco"`. | ||
```js | ||
let nodecipher = require('node-cipher'); | ||
nodecipher.encryptSync({ | ||
input: 'config.json', | ||
output: 'config.encrypted.json', | ||
password: 'b0sco' | ||
}); | ||
``` | ||
*** | ||
### `decrypt(options[, callback[, scope]])` | ||
Decrypts a file using the [options](#options) provided. | ||
##### Parameters | ||
#### Parameters | ||
|Parameter|Type|Description|Required| | ||
|--------:|:--:|:----------|:------:| | ||
|`options`|`Object`|The NodeCipher [options](#options) Object.|✓| | ||
|`options`|`Object`|See [options](#options).|✓| | ||
|`callback`|`Function`|The function to call when the decryption has completed.|| | ||
|`scope`|`Object`|The Function scope for the `callback` parameter, if provided.|| | ||
|`scope`|`Object`|The Function scope for the `callback` parameter, if provided.||`null`| | ||
##### Example | ||
#### Example | ||
@@ -190,37 +143,44 @@ Decrypts `config.encrypted.json` back into `config.json` using the password `"b0sco"`. | ||
#### `list():Array` | ||
### `decryptSync(options)` | ||
Lists all available cipher algorithms as an Array. | ||
The synchronous version of [`decrypt()`](#decryptoptions-callback-scope). | ||
##### Example | ||
#### Parameters | ||
|Parameter|Type|Description|Required|Default| | ||
|--------:|:--:|:----------|:------:|:-----:| | ||
|`options`|`Object`|See [options](#options).|✓|| | ||
#### Example | ||
Synchronously decrypts `config.encrypted.json` back into `config.json` using the password `"b0sco"`. | ||
```js | ||
let nodecipher = require('node-cipher'); | ||
console.log(nodecipher.list()); | ||
// => ['CAST-cbc', 'aes-128-cbc', ..., 'seed-ofb'] | ||
nodecipher.decryptSync({ | ||
input: 'config.encrypted.json', | ||
output: 'config.json', | ||
password: 'b0sco' | ||
}); | ||
``` | ||
*** | ||
### `list():Array` | ||
Tips | ||
---- | ||
Lists all available cipher algorithms as an Array. | ||
Using NPM, you can create custom scripts in our `package.json` file to automate much of the encryption/decryption process. | ||
#### Example | ||
```js | ||
{ | ||
// ... | ||
"scripts": { | ||
"encrypt": "nodecipher encrypt -i config.json -o config.encrypted.json", | ||
"decrypt": "nodecipher decrypt -i config.encrypted.json -o config.json" | ||
} | ||
} | ||
let nodecipher = require('node-cipher'); | ||
console.log(nodecipher.list()); | ||
// => ['CAST-cbc', 'aes-128-cbc', ..., 'seed-ofb'] | ||
``` | ||
Simply run `npm run encrypt` or `npm run decrypt` to execute these commands. | ||
*** | ||
Authors | ||
@@ -227,0 +187,0 @@ ------- |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
2
13975
7
296
188
+ Addedvalidate@^3.0.1
+ Addedcomponent-type@1.0.0(transitive)
+ Addedeivindfjeldstad-dot@0.0.1(transitive)
+ Addedtypecast@0.0.1(transitive)
+ Addedvalidate@3.1.0(transitive)
- Removedassert@^1.3.0
- Removedchalk@^1.1.1
- Removedinquirer@^0.8.5
- Removedpromise@^7.0.4
- Removedyargs@^3.21.0
- Removedansi-regex@1.1.12.1.1(transitive)
- Removedansi-styles@2.2.1(transitive)
- Removedasap@2.0.6(transitive)
- Removedassert@1.5.1(transitive)
- Removedcall-bind@1.0.8(transitive)
- Removedcall-bind-apply-helpers@1.0.1(transitive)
- Removedcall-bound@1.0.3(transitive)
- Removedcamelcase@2.1.1(transitive)
- Removedchalk@1.1.3(transitive)
- Removedcli-width@1.1.1(transitive)
- Removedcliui@3.2.0(transitive)
- Removedcode-point-at@1.1.0(transitive)
- Removeddecamelize@1.2.0(transitive)
- Removeddefine-data-property@1.1.4(transitive)
- Removeddefine-properties@1.2.1(transitive)
- Removeddunder-proto@1.0.1(transitive)
- Removedes-define-property@1.0.1(transitive)
- Removedes-errors@1.3.0(transitive)
- Removedes-object-atoms@1.0.0(transitive)
- Removedescape-string-regexp@1.0.5(transitive)
- Removedfigures@1.7.0(transitive)
- Removedfunction-bind@1.1.2(transitive)
- Removedget-intrinsic@1.2.6(transitive)
- Removedgopd@1.2.0(transitive)
- Removedhas-ansi@2.0.0(transitive)
- Removedhas-property-descriptors@1.0.2(transitive)
- Removedhas-symbols@1.1.0(transitive)
- Removedhasown@2.0.2(transitive)
- Removedinherits@2.0.3(transitive)
- Removedinquirer@0.8.5(transitive)
- Removedinvert-kv@1.0.0(transitive)
- Removedis-fullwidth-code-point@1.0.0(transitive)
- Removedlcid@1.0.0(transitive)
- Removedlodash@3.10.1(transitive)
- Removedmath-intrinsics@1.1.0(transitive)
- Removedmute-stream@0.0.4(transitive)
- Removednumber-is-nan@1.0.1(transitive)
- Removedobject-assign@4.1.1(transitive)
- Removedobject-keys@1.1.1(transitive)
- Removedobject.assign@4.1.7(transitive)
- Removedos-locale@1.4.0(transitive)
- Removedpromise@7.3.1(transitive)
- Removedreadline2@0.1.1(transitive)
- Removedrx@2.5.3(transitive)
- Removedset-function-length@1.2.2(transitive)
- Removedstring-width@1.0.2(transitive)
- Removedstrip-ansi@2.0.13.0.1(transitive)
- Removedsupports-color@2.0.0(transitive)
- Removedthrough@2.3.8(transitive)
- Removedutil@0.10.4(transitive)
- Removedwindow-size@0.1.4(transitive)
- Removedwrap-ansi@2.1.0(transitive)
- Removedy18n@3.2.2(transitive)
- Removedyargs@3.32.0(transitive)