From f7405850be71c7c923c0c0fe2cfaf24f3498e3e9 Mon Sep 17 00:00:00 2001 From: Ashwin Kumar Subramanian Date: Mon, 12 Jul 2021 09:46:22 -0700 Subject: [PATCH] BREAKING CHANGE: Update and streamline SDKs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: Update and streamline SDKs This is a major release consisting of multiple usability improvements and additional features. We have aimed to streamline the SDK with the Smartcar API interfaces in a way that the objects returned are closer to the API interface documented in [API Docs](https://smartcar.com/docs/api#smartcar-api-reference). For ex. `vehicle.odometer()` will now return an object that looks like the [response in the documentation](https://smartcar.com/docs/api#get-odometer) and additionally the body will contain response headers [defined in the documentation](https://smartcar.com/docs/api#headers) as a part of a `meta` attribute. The methods to be used are broadly divided into three namespaces : - `AuthClient` - This class is used for all OAuth related operations - `Smartcar` - This class is used for all application level operations - `Vehicle` - This class is used for all vehicle operations/actions. **NOTE - According to the changes made to the terms of [nodejs versions support](https://github.com/smartcar/node-sdk#supported-nodejs-versions), NodeJS 6 and 8 are no longer supported.** - Environment variables - The SDK now supports usage of environment variables for client id (`SMARTCAR_CLIENT_ID`), client secret(`SMARTCAR_CLIENT_SECRET`) and redirect URL(`SMARTCAR_REDIRECT_URL`). These can be used instead of having to pass these as arguments. - `hashChallenge` - Additional utility method defined in `Smartcar` namespace to generate hash challenge for webhooks. - `verifyPayload` - Additional utility method defined in `Smartcar` namespace to verify the payload returned by webhooks. - `getApiVersion` - Method defined in `Smartcar` namespace to return the api version set globally. - `subscribe` - Additional method defined in `Vehicle` namespace to subscribe to a webhook. - `unsubscribe` - Additional method defined in `Vehicle` namespace to unsubscribe from a webhook. - Default API version to 2.0 - The default version for the APIs is now `2.0` instead of `1.0` . This can be overridden globally by using the `setApiVersion` method or by using optional arguments in different methods. Following are the improvements made to the interfaces by namespace. For in-depth details of the interface please refer to the [SDK documentation](https://github.com/smartcar/node-sdk/tree/master/doc). - `Constructor` - This only requires the set of parameters required by all of the functions defined in the class. Previously this was also taking in all the arguments used for generating auth URL. This has not been separated and streamlined. - `getAuthUrl` - Takes in scope as required argument and all the other optional arguments required to generate the Smartcar Connect URL as defined in the [docs](https://smartcar.com/docs/api?version=v2.0&language=cURL#smartcar-connect) - `exchangeCode` - Added additional support for optional flags parameter for future usage. - `exchangeRefreshToken` - Added additional support for optional flags parameter for future usage. - `getVehicles` - Renamed from `getVehicleIds` and changes in interface. - `getUser` - Moved and renamed from `Vehicle#getUserIds` and changes in interface. - `getCompatibility` - Moved and renamed from `AuthClient#isCompatible` and changes in interface. - `Constructor` - Updated to now support a version parameter. Look at the interface for more details. - `attributes` - Renamed from `info` . - `batch` - The return value of the method has been changed. This now returns a function for each attributes requested that either returns an object of the requested attribute OR throws an error if the attribute returned an error. All the errors have been converged to a single `SmartcarError` class. This class can now support the error fields returned by v2.0 and v1.0. For detailed breakdown of both the error types, refer to the to the [API Reference Errors section](https://smartcar.com/docs/api/#errors). --- .nycrc.json | 8 +- .travis.yml | 17 +- README.md | 73 +- doc/readme.md | 1241 ++++---- index.js | 207 +- lib/auth-client.js | 217 +- lib/config.json | 2 +- lib/errors.js | 259 -- lib/smartcar-error.js | 122 + lib/smartcar-service.js | 130 + lib/util.js | 98 +- lib/vehicle.js | 789 ++--- package-lock.json | 4848 +++++++++++------------------- package.json | 6 +- test/end-to-end/auth-client.js | 46 +- test/end-to-end/helpers/index.js | 19 +- test/end-to-end/index.js | 80 +- test/end-to-end/util.js | 99 + test/end-to-end/vehicle.js | 378 ++- test/unit/index.js | 154 +- test/unit/lib/auth-client.js | 463 +-- test/unit/lib/errors.js | 47 - test/unit/lib/util.js | 387 +-- test/unit/lib/vehicle.js | 650 +--- 24 files changed, 4270 insertions(+), 6070 deletions(-) delete mode 100644 lib/errors.js create mode 100644 lib/smartcar-error.js create mode 100644 lib/smartcar-service.js create mode 100644 test/end-to-end/util.js delete mode 100644 test/unit/lib/errors.js diff --git a/.nycrc.json b/.nycrc.json index 9d111171..f4941147 100644 --- a/.nycrc.json +++ b/.nycrc.json @@ -1,8 +1,8 @@ { - "lines": 98, - "branches": 98, - "functions": 98, - "statements": 98, + "lines": 95, + "branches": 95, + "functions": 95, + "statements": 95, "all" : false, "cache": true, "reporter": [ diff --git a/.travis.yml b/.travis.yml index 81895fe9..ef09d6ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,14 +10,14 @@ language: - node_js node_js: - - "10" - - "8" - - "6" + - '14' + - '12' + - '10' cache: directories: - - "$HOME/.npm" - - ".eslintcache" + - '$HOME/.npm' + - '.eslintcache' if: tag IS blank # do not build tags @@ -26,10 +26,6 @@ notifications: secure: "CHS39tAvw6WiIN8cYSyE3QT2PVeFdrHszT/00kU3pb1BH5Ec5JYx5U7bMrVf3yq3GQC/wxBhXs4E119LwZM0n04CGUOshShqSkLeUf9RfWYlqx2Qw2+tT8sOi+OXCzE+yaG3Yt+TWFqKyC5t0A9jZX6cdJbcBaKX2wJiOyI/HiTpXHXrJgeeflxRe03KDpIfpmWgpMjnouZ6rKMnP30H+CG4Ya5uouM/Sv5flgJ+1VnZo/kB89hQ4CELr3bBfxSW4lCS1Tmg/z8w059D2nsn7wiMols3Qgw4FJu773K03fyLGoV4JshxA9lvnLt/Vy+azDNEBP5drQeQ7l8GMrLAPIEN8oGbuH9+TyYoxj0P38Kx4hzlW3owGs1U2+wCuYCq2b58oGTYonKnynFV4Pi8f94uBWd6ziIJoKhwx6MsJzKIt/6T91QWjWozOpF9uGy81ZfR3WHU/gnIyWDTJsLnB7nFA5z9V3/K3Orj5tlVr7iZbCUhA9v6XMYTpyyxjoMtBjVad2IztaWXZIZ97Xx7WBkGS9lvFZIqgHMYERb/On/4bEEXdPlzyJxwwlPBNvPv7enVAsYjPJJ58CQ42fuYkMYZlNcTGfYz9Nw/K64ocMidfdMKvdFD1w6Cw/U1HkQ0SZssy6yEb1BpzdBfMbsUDnh0OJffUpeGp402XOwUNT4=" -before_install: - # npm@^7.0.0 requires Node.js >= 10 - - dpkg --compare-versions `npm -v` ge 6.0 || npm i -g npm@^6.0.0 - install: - npm ci - firefox -headless & @@ -40,8 +36,7 @@ script: - test -z "$(git diff --name-only | grep '^doc/readme.md$')" - npm run test:unit - # e2e tests use async/await - - if test "$TRAVIS_NODE_VERSION" -gt 6; then npm run test:e2e; fi + - npm run test:e2e - npm run cover after_success: diff --git a/README.md b/README.md index 12b850cb..d4ef12eb 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ not have access to the dashboard, please ### Flow - Create a new `AuthClient` object with your `clientId`, `clientSecret`, - `redirectUri`, and required `scope`. -- Redirect the user to Smartcar Connect using `getAuthUrl` or one + `redirectUri`. +- Redirect the user to Smartcar Connect using `getAuthUrl` with required `scope` or with one of our frontend SDKs. - The user will login, and then accept or deny your `scope`'s permissions. - Handle the get request to `redirectUri`. @@ -44,7 +44,7 @@ not have access to the dashboard, please to `"access_denied"`. - If you passed a state parameter to `getAuthUrl`, `req.query.state` will contain the state value. -- Get the user's vehicles with `getVehicleIds`. +- Get the user's vehicles with `getVehicles`. - Create a new `Vehicle` object using a `vehicleId` from the previous response, and the `access_token`. - Make requests to the Smartcar API. @@ -70,23 +70,22 @@ const app = express(); const port = 4000; const client = new smartcar.AuthClient({ - clientId: 'SMARTCAR_CLIENT_ID', - clientSecret: 'SMARTCAR_CLIENT_SECRET', - redirectUri: 'YOUR_CALLBACK_URI', - scope: ['read_vehicle_info'], + clientId: '', // fallback to SMARTCAR_CLIENT_ID ENV variable + clientSecret: '', // fallback to SMARTCAR_CLIENT_SECRET ENV variable + redirectUri: '', // fallback to SMARTCAR_REDIRECT_URI ENV variable testMode: true, // launch Smartcar Connect in test mode }); // Redirect to Smartcar Connect app.get('/login', function(req, res) { - const link = client.getAuthUrl(); + const link = client.getAuthUrl(['read_vehicle_info']); // redirect to the link res.redirect(link); }); // Handle Smartcar callback with auth code -app.get('/callback', function(req, res, next) { +app.get('/callback', async function(req, res, next) { let access; if (req.query.error) { @@ -95,32 +94,23 @@ app.get('/callback', function(req, res, next) { } // exchange auth code for access token - return client - .exchangeCode(req.query.code) - .then(function(_access) { - // in a production app you'll want to store this in some kind of persistent storage - access = _access; - // get the user's vehicles - return smartcar.getVehicleIds(access.accessToken); - }) - .then(function(res) { - // instantiate first vehicle in vehicle list - const vehicle = new smartcar.Vehicle(res.vehicles[0], access.accessToken); - // get identifying information about a vehicle - return vehicle.info(); - }) - .then(function(data) { - console.log(data); - // { - // "id": "36ab27d0-fd9d-4455-823a-ce30af709ffc", - // "make": "TESLA", - // "model": "Model S", - // "year": 2014 - // } - - // json response will be sent to the user - res.json(data); - }); + const tokens = await client.exchangeCode(req.query.code) + // get the user's vehicles + const vehicles = await smartcar.getVehicles(tokens.accessToken); + // instantiate first vehicle in vehicle list + const vehicle = new smartcar.Vehicle(vehicles.vehicles[0], tokens.accessToken); + // get identifying information about a vehicle + const attributes = await vehicle.attributes(); + console.log(attributes); + // { + // "id": "36ab27d0-fd9d-4455-823a-ce30af709ffc", + // "make": "TESLA", + // "model": "Model S", + // "year": 2014 + // "meta": { + // "requestId": "ada7207c-3c0a-4027-a47f-6215ce6f7b93" + // } + // } }); app.listen(port, () => console.log(`Listening on port ${port}`)); @@ -145,7 +135,20 @@ To test: npm run test ``` +Note: In order to run tests locally the following environment variables would have to be set : +- `E2E_SMARTCAR_CLIENT_ID` - Client ID to be used. +- `E2E_SMARTCAR_CLIENT_SECRET` - Client secret to be used. +- `E2E_SMARTCAR_REDIRECT_URI` - Redirect URI for the auth flow. +- `E2E_SMARTCAR_AMT` - AMT from dashboard for webhooks tests. +- `E2E_SMARTCAR_WEBHOOK_ID` - Webhook ID use in the webhook tests success case. + [ci-url]: https://travis-ci.com/smartcar/node-sdk [ci-image]: https://travis-ci.com/smartcar/node-sdk.svg?token=jMbuVtXPGeJMPdsn7RQ5&branch=master [npm-url]: https://badge.fury.io/js/smartcar [npm-image]: https://badge.fury.io/js/smartcar.svg + +## Supported Node.js Versions + +Smartcar aims to support the SDK on all Node.js versions that have a status of "Maintenance" or "Active LTS" as defined in the [Node.js Release schedule](https://github.com/nodejs/Release#release-schedule). + +In accordance with the Semantic Versioning specification, the addition of support for new Node.js versions would result in a MINOR version bump and the removal of support for Node.js versions would result in a MAJOR version bump. \ No newline at end of file diff --git a/doc/readme.md b/doc/readme.md index e70b5f18..34ad1a50 100644 --- a/doc/readme.md +++ b/doc/readme.md @@ -8,8 +8,6 @@ Smartcar Node SDK documentation.
smartcar
-
errors
-
## Classes @@ -19,15 +17,30 @@ Smartcar Node SDK documentation.
AuthClient
+
SmartcarError
+

Class to handle all errors from Smartcar API +Please see our error guides to see a list +of all the possible error types and codes of both v2.0 and v1.0 requests.

+
+
SmartcarService
+
Vehicle
-## Functions +## Constants
-
parseAge(response)Date | null
-
+
METHODS_MAP : object.<String, Object>
+

Every key here is the function name on vehicle +This map is used to generate the methods dynamically. Every value is an object of +the following fields :

+
    +
  • requestType: http request type, defaults to 'get' if not mentioned.
  • +
  • path: url path to hit, defaults to the method name
  • +
  • body: body for post requests.
  • +
+
## Typedefs @@ -35,27 +48,35 @@ Smartcar Node SDK documentation.
Access : Object
-
Info : Object
+
Permissions : Object
-
Location : Object
+
WebhookSubscription : Object
-
Odometer : Object
+
Batch : Object
-
EngineOil : Object
+
Meta : Object
-
TirePressure : Object
+
Vin : Object
-
Fuel : Object
+
Charge : Object
Battery : Object
BatteryCapacity : Object
-
Charge : Object
+
Fuel : Object
+
+
TirePressure : Object
-
ActionSuccess : Object
+
EngineOil : Object
-
Batch : Object
+
Odometer : Object
+
+
Location : Object
+
+
Attributes : Object
+
+
ActionResponse : Object
@@ -65,21 +86,26 @@ Smartcar Node SDK documentation. * [smartcar](#module_smartcar) * _static_ - * [.errors](#module_smartcar.errors) + * [.SmartcarError](#module_smartcar.SmartcarError) * [.Vehicle](#module_smartcar.Vehicle) * [.AuthClient](#module_smartcar.AuthClient) * [.setApiVersion(version)](#module_smartcar.setApiVersion) - * [.isExpired(expiration)](#module_smartcar.isExpired) ⇒ Boolean - * [.getVehicleIds(token, [paging])](#module_smartcar.getVehicleIds) ⇒ [Promise.<VehicleIds>](#module_smartcar..VehicleIds) - * [.getUserId(token)](#module_smartcar.getUserId) ⇒ Promise.<String> + * [.getApiVersion()](#module_smartcar.getApiVersion) ⇒ String + * [.getUser(accessToken)](#module_smartcar.getUser) ⇒ [User](#module_smartcar..User) + * [.getVehicles(accessToken, [paging])](#module_smartcar.getVehicles) ⇒ [VehicleIds](#module_smartcar..VehicleIds) + * [.getCompatibility(vin, scope, [country], [options])](#module_smartcar.getCompatibility) ⇒ [Compatibility](#module_smartcar..Compatibility) + * [.hashChallenge(amt, challenge)](#module_smartcar.hashChallenge) ⇒ String + * [.verifyPayload(amt, signature, body)](#module_smartcar.verifyPayload) ⇒ Boolean * _inner_ + * [~User](#module_smartcar..User) : Object * [~VehicleIds](#module_smartcar..VehicleIds) : Object + * [~Compatibility](#module_smartcar..Compatibility) : Object - + -### smartcar.errors +### smartcar.SmartcarError **Kind**: static property of [smartcar](#module_smartcar) -**See**: [errors](#module_errors) +**See**: [module:errors](module:errors) ### smartcar.Vehicle @@ -101,57 +127,128 @@ Sets the version of Smartcar API you are using | --- | --- | | version | String | - + + +### smartcar.getApiVersion() ⇒ String +Gets the version of Smartcar API that is set + +**Kind**: static method of [smartcar](#module_smartcar) +**Returns**: String - version + -### smartcar.isExpired(expiration) ⇒ Boolean -Check if a token has expired. +### smartcar.getUser(accessToken) ⇒ [User](#module_smartcar..User) +Return the user's id. **Kind**: static method of [smartcar](#module_smartcar) -**Returns**: Boolean - true if expired, false if not expired +**Throws**: + +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. + See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) + for all possible errors. + | Param | Type | Description | | --- | --- | --- | -| expiration | Date \| String | token expiration timestamp | +| accessToken | String | access token | - + -### smartcar.getVehicleIds(token, [paging]) ⇒ [Promise.<VehicleIds>](#module_smartcar..VehicleIds) +### smartcar.getVehicles(accessToken, [paging]) ⇒ [VehicleIds](#module_smartcar..VehicleIds) Return list of the user's vehicles ids. **Kind**: static method of [smartcar](#module_smartcar) -**Returns**: [Promise.<VehicleIds>](#module_smartcar..VehicleIds) - A promise with the vehicle ids. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. | Param | Type | Description | | --- | --- | --- | -| token | String | access token | +| accessToken | String | access token | | [paging] | Object | | | [paging.limit] | Number | number of vehicles to return | | [paging.offset] | Number | index to start vehicle list | - + -### smartcar.getUserId(token) ⇒ Promise.<String> -Return the user's id. +### smartcar.getCompatibility(vin, scope, [country], [options]) ⇒ [Compatibility](#module_smartcar..Compatibility) +Determine whether a vehicle is compatible with Smartcar. + +A compatible vehicle is a vehicle that: +1. has the hardware required for internet connectivity, +2. belongs to the makes and models Smartcar supports, and +3. supports the permissions. + +_To use this function, please contact us!_ **Kind**: static method of [smartcar](#module_smartcar) -**Returns**: Promise.<String> - the user id **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| vin | String | | the VIN of the vehicle | +| scope | Array.<String> | | list of permissions to check compatibility for | +| [country] | String | 'US' | an optional country code according to [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). | +| [options] | Object | | | +| [options.clientId] | String | | client ID to use for basic auth. | +| [options.clientSecret] | String | | client secret to use for basic auth. | +| [options.flags] | Object | | Object of flags where key is the name of the flag value is string or boolean value. | +| [options.version] | Object | | API version to use | + + + +### smartcar.hashChallenge(amt, challenge) ⇒ String +Generate hash challenege for webhooks. It does HMAC_SHA256(amt, challenge) + +**Kind**: static method of [smartcar](#module_smartcar) +**Returns**: String - String representing the hex digest + | Param | Type | Description | | --- | --- | --- | -| token | String | access token | +| amt | String | Application Management Token | +| challenge | String | Challenge string | + + +### smartcar.verifyPayload(amt, signature, body) ⇒ Boolean +Verify webhook payload with AMT and signature. + +**Kind**: static method of [smartcar](#module_smartcar) +**Returns**: Boolean - true if signature matches the hex digest of amt and body + +| Param | Type | Description | +| --- | --- | --- | +| amt | String | Application Management Token | +| signature | String | sc-signature header value | +| body | object | webhook response body | + + + +### smartcar~User : Object +**Kind**: inner typedef of [smartcar](#module_smartcar) +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| id | String | User Id | +| meta | module:smartcar.Vehicle.Meta | | + +**Example** +```js +{ + id: "e0514ef4-5226-11e8-8c13-8f6e8f02e27e", + meta: { + requestId: 'b9593682-8515-4f36-8190-bb56cde4c38a', + } +} +``` ### smartcar~VehicleIds : Object @@ -164,6 +261,7 @@ Return the user's id. | paging | Object | | | paging.count- | Number | The total number of vehicles. | | paging.offset | Number | The current start index of returned vehicle ids. | +| meta | module:smartcar.Vehicle.Meta | | **Example** ```js @@ -175,266 +273,32 @@ Return the user's id. paging: { count: 2, offset: 0, + }, + meta: { + requestId: 'b9593682-8515-4f36-8190-bb56cde4c38a', } } ``` - - -## errors - -* [errors](#module_errors) - * [.SmartcarErrorV2](#module_errors.SmartcarErrorV2) - * [new errors.SmartcarErrorV2(error)](#new_module_errors.SmartcarErrorV2_new) - * [.type](#module_errors.SmartcarErrorV2+type) : string - * [.code](#module_errors.SmartcarErrorV2+code) : string - * [.description](#module_errors.SmartcarErrorV2+description) : string - * [.statusCode](#module_errors.SmartcarErrorV2+statusCode) : number - * [.requestId](#module_errors.SmartcarErrorV2+requestId) : string - * [.resolution](#module_errors.SmartcarErrorV2+resolution) : string - * [.docURL](#module_errors.SmartcarErrorV2+docURL) : string - * [.detail](#module_errors.SmartcarErrorV2+detail) : Array.<object> - * [.SmartcarError(message)](#module_errors.SmartcarError) ⇐ Error - * [.ValidationError(message)](#module_errors.ValidationError) ⇐ SmartcarError - * [.AuthenticationError(message)](#module_errors.AuthenticationError) ⇐ SmartcarError - * [.PermissionError(message)](#module_errors.PermissionError) ⇐ SmartcarError - * [.ResourceNotFoundError(message)](#module_errors.ResourceNotFoundError) ⇐ SmartcarError - * [.VehicleStateError(message, code)](#module_errors.VehicleStateError) ⇐ SmartcarError - * [.RateLimitingError(message)](#module_errors.RateLimitingError) ⇐ SmartcarError - * [.MonthlyLimitExceeded(message)](#module_errors.MonthlyLimitExceeded) ⇐ SmartcarError - * [.ServerError(message)](#module_errors.ServerError) ⇐ SmartcarError - * [.VehicleNotCapableError(message)](#module_errors.VehicleNotCapableError) ⇐ SmartcarError - * [.SmartcarNotCapableError(message)](#module_errors.SmartcarNotCapableError) ⇐ SmartcarError - * [.GatewayTimeoutError(message)](#module_errors.GatewayTimeoutError) - - - -### errors.SmartcarErrorV2 -Enhanced errors from API v2.0 -Please see our [v2.0 error guides](https://smartcar.com/docs/errors/v2.0/billing) to see a list of all the possible error types and codes - -**Kind**: static class of [errors](#module_errors) - -* [.SmartcarErrorV2](#module_errors.SmartcarErrorV2) - * [new errors.SmartcarErrorV2(error)](#new_module_errors.SmartcarErrorV2_new) - * [.type](#module_errors.SmartcarErrorV2+type) : string - * [.code](#module_errors.SmartcarErrorV2+code) : string - * [.description](#module_errors.SmartcarErrorV2+description) : string - * [.statusCode](#module_errors.SmartcarErrorV2+statusCode) : number - * [.requestId](#module_errors.SmartcarErrorV2+requestId) : string - * [.resolution](#module_errors.SmartcarErrorV2+resolution) : string - * [.docURL](#module_errors.SmartcarErrorV2+docURL) : string - * [.detail](#module_errors.SmartcarErrorV2+detail) : Array.<object> - - - -#### new errors.SmartcarErrorV2(error) - -| Param | Type | Description | -| --- | --- | --- | -| error | Object \| String | response body from a v2.0 request | - - - -#### smartcarErrorV2.type : string -Type of error - -**Kind**: instance property of [SmartcarErrorV2](#module_errors.SmartcarErrorV2) -**Access**: public - - -#### smartcarErrorV2.code : string -Error code - -**Kind**: instance property of [SmartcarErrorV2](#module_errors.SmartcarErrorV2) -**Access**: public - - -#### smartcarErrorV2.description : string -Description of meaning of the error - -**Kind**: instance property of [SmartcarErrorV2](#module_errors.SmartcarErrorV2) -**Access**: public - - -#### smartcarErrorV2.statusCode : number -HTTP status code - -**Kind**: instance property of [SmartcarErrorV2](#module_errors.SmartcarErrorV2) -**Access**: public - - -#### smartcarErrorV2.requestId : string -Unique identifier for request - -**Kind**: instance property of [SmartcarErrorV2](#module_errors.SmartcarErrorV2) -**Access**: public - - -#### smartcarErrorV2.resolution : string -Possible resolution for fixing the error - -**Kind**: instance property of [SmartcarErrorV2](#module_errors.SmartcarErrorV2) -**Access**: public - - -#### smartcarErrorV2.docURL : string -Reference to Smartcar documentation - -**Kind**: instance property of [SmartcarErrorV2](#module_errors.SmartcarErrorV2) -**Access**: public - - -#### smartcarErrorV2.detail : Array.<object> -Further detail about the error - -**Kind**: instance property of [SmartcarErrorV2](#module_errors.SmartcarErrorV2) -**Access**: public - - -### errors.SmartcarError(message) ⇐ Error -Superclass for all sdk errors. - -**Kind**: static method of [errors](#module_errors) -**Extends**: Error - -| Param | Description | -| --- | --- | -| message | an error description to set | - - + -### errors.ValidationError(message) ⇐ SmartcarError -Error thrown by request validation. - -**Kind**: static method of [errors](#module_errors) -**Extends**: SmartcarError - -| Param | Description | -| --- | --- | -| message | an error description to set | - - - -### errors.AuthenticationError(message) ⇐ SmartcarError -Error thrown by an invalid parameter when authenticating. - -**Kind**: static method of [errors](#module_errors) -**Extends**: SmartcarError - -| Param | Description | -| --- | --- | -| message | an error description to set | - - - -### errors.PermissionError(message) ⇐ SmartcarError -Error thrown due to insufficient permissions. - -**Kind**: static method of [errors](#module_errors) -**Extends**: SmartcarError - -| Param | Description | -| --- | --- | -| message | an error description to set | - - - -### errors.ResourceNotFoundError(message) ⇐ SmartcarError -Error thrown when the requested resource is not found. - -**Kind**: static method of [errors](#module_errors) -**Extends**: SmartcarError - -| Param | Description | -| --- | --- | -| message | an error description to set | - - - -### errors.VehicleStateError(message, code) ⇐ SmartcarError -Error thrown when the vehicle is not capable of performing the request in -the current vehicle state. - -**Kind**: static method of [errors](#module_errors) -**Extends**: SmartcarError - -| Param | Description | -| --- | --- | -| message | an error description to set | -| code | a vehicle state error code (https://smartcar.com/docs/api#errors) | - - - -### errors.RateLimitingError(message) ⇐ SmartcarError -Error thrown when an application makes too many requests and is throttled. - -**Kind**: static method of [errors](#module_errors) -**Extends**: SmartcarError - -| Param | Description | -| --- | --- | -| message | an error description to set | - - - -### errors.MonthlyLimitExceeded(message) ⇐ SmartcarError -Error thrown when an application requests more resources than its allowed -limit, e.g., gone over their allotted monthly request limit. - -**Kind**: static method of [errors](#module_errors) -**Extends**: SmartcarError - -| Param | Description | -| --- | --- | -| message | an error description to set | - - - -### errors.ServerError(message) ⇐ SmartcarError -Error thrown when the server throws an unexpected error. - -**Kind**: static method of [errors](#module_errors) -**Extends**: SmartcarError - -| Param | Description | -| --- | --- | -| message | an error description to set | - - - -### errors.VehicleNotCapableError(message) ⇐ SmartcarError -Error thrown when vehicle is not capable of performing the request. - -**Kind**: static method of [errors](#module_errors) -**Extends**: SmartcarError - -| Param | Description | -| --- | --- | -| message | an error description to set | - - - -### errors.SmartcarNotCapableError(message) ⇐ SmartcarError -Error thrown when Smartcar is not capable of performing the request. - -**Kind**: static method of [errors](#module_errors) -**Extends**: SmartcarError - -| Param | Description | -| --- | --- | -| message | an error description to set | - - - -### errors.GatewayTimeoutError(message) -Error thrown when gateway to Smartcar times out - -**Kind**: static method of [errors](#module_errors) +### smartcar~Compatibility : Object +**Kind**: inner typedef of [smartcar](#module_smartcar) +**Properties** -| Param | Description | +| Name | Type | | --- | --- | -| message | an error description to set | +| compatible | Boolean | +| meta | module:smartcar.Vehicle.Meta | +**Example** +```js +{ + compatible: false, + meta: { + requestId: 'b9593682-8515-4f36-8190-bb56cde4c38a', + } +} +``` ## Promise @@ -447,10 +311,9 @@ Error thrown when gateway to Smartcar times out * [AuthClient](#AuthClient) * [new AuthClient(options)](#new_AuthClient_new) - * [.getAuthUrl([options])](#AuthClient+getAuthUrl) ⇒ String - * [.exchangeCode(code)](#AuthClient+exchangeCode) ⇒ [Promise.<Access>](#Access) - * [.exchangeRefreshToken(token)](#AuthClient+exchangeRefreshToken) ⇒ [Promise.<Access>](#Access) - * [.isCompatible(vin, scope, [country])](#AuthClient+isCompatible) ⇒ Promise.<Boolean> + * [.getAuthUrl([scope], [options])](#AuthClient+getAuthUrl) ⇒ String + * [.exchangeCode(code)](#AuthClient+exchangeCode) ⇒ [Access](#Access) + * [.exchangeRefreshToken(token)](#AuthClient+exchangeRefreshToken) ⇒ [Access](#Access) @@ -464,13 +327,11 @@ Create a Smartcar OAuth client for your application. | options.clientId | String | | Application client id obtained from [Smartcar Developer Portal](https://developer.smartcar.com). If you do not have access to the dashboard, please [request access](https://smartcar.com/subscribe). | | options.clientSecret | String | | The application's client secret. | | options.redirectUri | String | | Redirect URI registered in the [application settings](https://developer.smartcar.com/apps). The given URL must exactly match one of the registered URLs. | -| [options.scope] | Array.<String> | all | List of permissions your application requires. This will default to requiring all scopes. The valid permission names are found in the [API Reference](https://smartcar.com/docs#get-all-vehicles). | | [options.testMode] | Boolean | false | Launch Smartcar Connect in [test mode](https://smartcar.com/docs/guides/testing/). | -| [options.development] | Boolean | false | DEPRECATED: Launch Smartcar auth in development mode to enable mock vehicle brands. | -### authClient.getAuthUrl([options]) ⇒ String +### authClient.getAuthUrl([scope], [options]) ⇒ String Generate the Smartcar Connect URL. By default users are not shown the permission dialog if they have already @@ -480,21 +341,16 @@ approval_prompt to `force`. **Kind**: instance method of [AuthClient](#AuthClient) **Returns**: String - Smartcar Connect URL to direct user to. -**Throws**: - -- SmartcarError - an instance of SmartcarError. -See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) -for all possible errors. - -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| [options] | Object | | | -| [options.state] | String | | OAuth state parameter passed to the redirect uri. This parameter may be used for identifying the user who initiated the request. | -| [options.forcePrompt] | Boolean | false | Setting `forcePrompt` to `true` will show the permissions approval screen on every authentication attempt, even if the user has previously consented to the exact scope of permissions. | -| [options.vehicleInfo.make] | Object | | `vehicleInfo` is an object with an optional property `make`. An optional parameter that allows users to bypass the car brand selection screen. For a complete list of supported makes, please see our [API Reference](https://smartcar.com/docs/api#authorization) documentation. | -| [options.singleSelect] | Boolean \| Object | | An optional value that sets the behavior of the grant dialog displayed to the user. If set to `true`, `single_select` limits the user to selecting only one vehicle. If `single_select` is an object with the property `vin`, Smartcar will only authorize the vehicle with the specified VIN. See the [Single Select guide](https://smartcar.com/docs/guides/single-select/) for more information. | -| [options.flags] | Array.<String> | | List of feature flags that your application has early access to. | +| Param | Type | Description | +| --- | --- | --- | +| [scope] | Array.<String> | List of permissions your application requires. The valid permission names are found in the [API Reference](https://smartcar.com/docs/guides/scope/) | +| [options] | Object | | +| [options.forcePrompt] | Boolean | Setting `forcePrompt` to `true` will show the permissions approval screen on every authentication attempt, even if the user has previously consented to the exact scope of permissions. | +| [options.singleSelect] | Boolean \| Object | An optional value that sets the behavior of the grant dialog displayed to the user. Object can contain two keys : - enabled - Boolean value, if set to `true`, `single_select` limits the user to selecting only one vehicle. - vin - String vin, if set, Smartcar will only authorize the vehicle with the specified VIN. See the [Single Select guide](https://smartcar.com/docs/guides/single-select/) for more information. | +| [options.state] | String | OAuth state parameter passed to the redirect uri. This parameter may be used for identifying the user who initiated the request. | +| [options.makeBypass] | Object | An optional parameter that allows users to bypass the car brand selection screen. For a complete list of supported makes, please see our [API Reference](https://smartcar.com/docs/api#authorization) documentation. | +| [options.flags] | Object | Object of flags where key is the name of the flag value is string or boolean value. | **Example** ```js @@ -511,14 +367,14 @@ response_type=code ``` -### authClient.exchangeCode(code) ⇒ [Promise.<Access>](#Access) +### authClient.exchangeCode(code) ⇒ [Access](#Access) Exchange an authorization code for an access object. **Kind**: instance method of [AuthClient](#AuthClient) -**Returns**: [Promise.<Access>](#Access) - Access and Refresh tokens. +**Returns**: [Access](#Access) - New set of Access and Refresh tokens. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. @@ -526,17 +382,18 @@ for all possible errors. | Param | Type | Description | | --- | --- | --- | | code | String | Authorization code to exchange for a Smartcar access token and refresh token. | +| [options.flags] | Object | Object of flags where key is the name of the flag value is string or boolean value. | -### authClient.exchangeRefreshToken(token) ⇒ [Promise.<Access>](#Access) +### authClient.exchangeRefreshToken(token) ⇒ [Access](#Access) Exchange a refresh token for a new access object. **Kind**: instance method of [AuthClient](#AuthClient) -**Returns**: [Promise.<Access>](#Access) - New set of Access and Refresh tokens. +**Returns**: [Access](#Access) - New set of Access and Refresh tokens. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. @@ -544,34 +401,129 @@ for all possible errors. | Param | Type | Description | | --- | --- | --- | | token | String | Refresh token to exchange for a new set of Access and Refresh tokens. | +| [options.flags] | Object | Object of flags where key is the name of the flag value is string or boolean value. | - + -### authClient.isCompatible(vin, scope, [country]) ⇒ Promise.<Boolean> -Determine whether a vehicle is compatible with Smartcar. +## SmartcarError +Class to handle all errors from Smartcar API +Please see our [error guides](https://smartcar.com/docs) to see a list +of all the possible error types and codes of both v2.0 and v1.0 requests. -A compatible vehicle is a vehicle that: -1. has the hardware required for internet connectivity, -2. belongs to the makes and models Smartcar supports, and -3. supports the permissions. +**Kind**: global class -_To use this function, please contact us!_ +* [SmartcarError](#SmartcarError) + * [new SmartcarError(status, body, headers)](#new_SmartcarError_new) + * [.error](#SmartcarError.error) : string + * [.message](#SmartcarError.message) : string + * [.description](#SmartcarError.description) : string + * [.type](#SmartcarError.type) : string + * [.code](#SmartcarError.code) : string + * [.statusCode](#SmartcarError.statusCode) : number + * [.requestId](#SmartcarError.requestId) : string + * [.resolution](#SmartcarError.resolution) : [Resolution](#SmartcarError.Resolution) + * [.docURL](#SmartcarError.docURL) : string + * [.details](#SmartcarError.details) : Array.<object> + * [.Resolution](#SmartcarError.Resolution) : Object -**Kind**: instance method of [AuthClient](#AuthClient) -**Returns**: Promise.<Boolean> - false if the vehicle is not compatible. true if the - vehicle is likely compatible. -**Throws**: + -- SmartcarError - an instance of SmartcarError. - See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) - for all possible errors. +### new SmartcarError(status, body, headers) +| Param | Type | Description | +| --- | --- | --- | +| status | number | response status | +| body | object | response body | +| headers | object | response headers | -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| vin | String | | the VIN of the vehicle | -| scope | Array.<String> | | list of permissions to check compatibility for | -| [country] | String | 'US' | an optional country code according to [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). | + + +### SmartcarError.error : string +Legacy field from V1 error depicting a category/type/description +of the error. + +**Kind**: static property of [SmartcarError](#SmartcarError) + + +### SmartcarError.message : string +Error message field inherited from StandardError + +**Kind**: static property of [SmartcarError](#SmartcarError) + + +### SmartcarError.description : string +Description of meaning of the error. + +**Kind**: static property of [SmartcarError](#SmartcarError) + + +### SmartcarError.type : string +Type of error + +**Kind**: static property of [SmartcarError](#SmartcarError) + + +### SmartcarError.code : string +Error code + +**Kind**: static property of [SmartcarError](#SmartcarError) + + +### SmartcarError.statusCode : number +HTTP status code + +**Kind**: static property of [SmartcarError](#SmartcarError) + + +### SmartcarError.requestId : string +Unique identifier for request + +**Kind**: static property of [SmartcarError](#SmartcarError) + + +### SmartcarError.resolution : [Resolution](#SmartcarError.Resolution) +Possible resolution for fixing the error + +**Kind**: static property of [SmartcarError](#SmartcarError) + + +### SmartcarError.docURL : string +Reference to Smartcar documentation + +**Kind**: static property of [SmartcarError](#SmartcarError) + + +### SmartcarError.details : Array.<object> +Further detail about the error in form of array of objects + +**Kind**: static property of [SmartcarError](#SmartcarError) + + +### SmartcarError.Resolution : Object +**Kind**: static typedef of [SmartcarError](#SmartcarError) +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| type | String | Possible hint to fixing the issue | +| url | String | A URL to help resolve the issue or resume the operation | + + + +## SmartcarService +**Kind**: global class + + +### new SmartcarService([options]) +Initializes a new Service object to make requests to the Smartcar API. + + +| Param | Type | Description | +| --- | --- | --- | +| [options] | Object | | +| [options.baseUrl] | String | Host/Base URL for the requests | +| [options.auth] | Object | authorization options | +| [options.headers] | Object | headers to add | @@ -579,307 +531,323 @@ _To use this function, please contact us!_ **Kind**: global class * [Vehicle](#Vehicle) - * [new Vehicle(id, token, [unitSystem])](#new_Vehicle_new) - * [.setUnitSystem(unitSystem)](#Vehicle+setUnitSystem) - * [.disconnect()](#Vehicle+disconnect) ⇒ [Promise](#Promise) - * [.permissions()](#Vehicle+permissions) ⇒ Promise.<Array.<String>> - * [.hasPermissions(permissions)](#Vehicle+hasPermissions) ⇒ Promise.<Boolean> - * [.info()](#Vehicle+info) ⇒ [Promise.<Info>](#Info) - * [.location()](#Vehicle+location) ⇒ [Promise.<Location>](#Location) - * [.odometer()](#Vehicle+odometer) ⇒ [Promise.<Odometer>](#Odometer) - * [.oil()](#Vehicle+oil) ⇒ [Promise.<EngineOil>](#EngineOil) - * [.tirePressure()](#Vehicle+tirePressure) ⇒ [Promise.<TirePressure>](#TirePressure) - * [.fuel()](#Vehicle+fuel) ⇒ [Promise.<Fuel>](#Fuel) - * [.battery()](#Vehicle+battery) ⇒ [Promise.<Battery>](#Battery) - * [.batteryCapacity()](#Vehicle+batteryCapacity) ⇒ [Promise.<BatteryCapacity>](#BatteryCapacity) - * [.charge()](#Vehicle+charge) ⇒ [Promise.<Charge>](#Charge) - * [.vin()](#Vehicle+vin) ⇒ Promise.<String> - * [.lock()](#Vehicle+lock) ⇒ [Promise.<ActionSuccess>](#ActionSuccess) - * [.unlock()](#Vehicle+unlock) ⇒ [Promise.<ActionSuccess>](#ActionSuccess) - * [.startCharge()](#Vehicle+startCharge) ⇒ [Promise.<ActionSuccess>](#ActionSuccess) - * [.stopCharge()](#Vehicle+stopCharge) ⇒ [Promise.<ActionSuccess>](#ActionSuccess) - * [.batch(paths)](#Vehicle+batch) ⇒ [Promise.<Batch>](#Batch) + * [new Vehicle(id, token, [options])](#new_Vehicle_new) + * [.permissions([paging])](#Vehicle+permissions) ⇒ [Permissions](#Permissions) + * [.subscribe(webhookId)](#Vehicle+subscribe) ⇒ Object + * [.unsubscribe(amt, webhookId)](#Vehicle+unsubscribe) ⇒ [Meta](#Meta) + * [.batch(paths)](#Vehicle+batch) ⇒ [Batch](#Batch) + * [.vin()](#Vehicle+vin) ⇒ [Vin](#Vin) + * [.charge()](#Vehicle+charge) ⇒ [Charge](#Charge) + * [.battery()](#Vehicle+battery) ⇒ [Battery](#Battery) + * [.batteryCapacity()](#Vehicle+batteryCapacity) ⇒ [BatteryCapacity](#BatteryCapacity) + * [.fuel()](#Vehicle+fuel) ⇒ [Fuel](#Fuel) + * [.tirePressure()](#Vehicle+tirePressure) ⇒ [TirePressure](#TirePressure) + * [.engineOil()](#Vehicle+engineOil) ⇒ [EngineOil](#EngineOil) + * [.odometer()](#Vehicle+odometer) ⇒ [Odometer](#Odometer) + * [.location()](#Vehicle+location) ⇒ [Location](#Location) + * [.attributes()](#Vehicle+attributes) ⇒ [Attributes](#Attributes) + * [.lock()](#Vehicle+lock) ⇒ [ActionResponse](#ActionResponse) + * [.unlock()](#Vehicle+unlock) ⇒ [ActionResponse](#ActionResponse) + * [.startCharge()](#Vehicle+startCharge) ⇒ [ActionResponse](#ActionResponse) + * [.stopCharge()](#Vehicle+stopCharge) ⇒ [ActionResponse](#ActionResponse) + * [.disconnect()](#Vehicle+disconnect) ⇒ [ActionResponse](#ActionResponse) -### new Vehicle(id, token, [unitSystem]) +### new Vehicle(id, token, [options]) Initializes a new Vehicle to use for making requests to the Smartcar API. | Param | Type | Default | Description | | --- | --- | --- | --- | -| id | String | | The vehicle's unique identifier. Retrieve a user's vehicle id using [getVehicleIds](#module_smartcar.getVehicleIds). | +| id | String | | The vehicle's unique identifier. Retrieve a user's vehicle id using [getVehicles](#module_smartcar.getVehicles). | | token | String | | A valid access token | -| [unitSystem] | String | metric | The unit system to use for vehicle data , must be either `metric` or `imperial`. | +| [options] | Object | | | +| [options.unitSystem] | String | metric | The unit system to use for vehicle data must be either `metric` or `imperial`. | +| [options.version] | Object | | API version to use | - + -### vehicle.setUnitSystem(unitSystem) -Update the unit system to use in requests to the Smartcar API. +### vehicle.permissions([paging]) ⇒ [Permissions](#Permissions) +Fetch the list of permissions that this application has been granted **Kind**: instance method of [Vehicle](#Vehicle) +**Throws**: + +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. + See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) + for all possible errors. + | Param | Type | Description | | --- | --- | --- | -| unitSystem | String | The unit system to use, must be either `metric` or `imperial`. | +| [paging] | Object | | +| [paging.limit] | String | number of permissions to return | +| [options.offset] | Object | The current start index of the returned list of elements. | - + -### vehicle.disconnect() ⇒ [Promise](#Promise) -Disconnect this vehicle from the connected application. - -Note: Calling this method will invalidate your token's access to the vehicle. -You will have to reauthorize the user to your application again if you wish -to make requests to it again. +### vehicle.subscribe(webhookId) ⇒ Object +Subscribe the vehicle to given webhook Id **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise](#Promise) - A promise resolved on successful disconnect. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. - -### vehicle.permissions() ⇒ Promise.<Array.<String>> -Fetch the list of permissions that this application has been granted for -this vehicle. +| Param | Type | Description | +| --- | --- | --- | +| webhookId | String | Webhook Id to subscribe to. | + + + +### vehicle.unsubscribe(amt, webhookId) ⇒ [Meta](#Meta) +Unsubscribe the vehicle from given webhook Id **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: Promise.<Array.<String>> - An array of permissions names. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. -**Example** -```js -['read_vehicle_info', 'read_odometer', 'control_security'] -``` - -### vehicle.hasPermissions(permissions) ⇒ Promise.<Boolean> -Checks if permissions granted to a vehicle contain the specified permission(s). +| Param | Type | Description | +| --- | --- | --- | +| amt | String | Application management token to be used as authorization | +| webhookId | String | Webhook Id to unsubscribe from. | + + + +### vehicle.batch(paths) ⇒ [Batch](#Batch) +Make batch requests for supported items **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: Promise.<Boolean> - Whether the vehicle has the specified permission(s) +**Throws**: + +- [SmartcarError](#SmartcarError) - on unsuccessful request. An instance of SmartcarError. + See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) + for all possible errors. + +**See**: [Smartcar API Doc - Batch Request](https://smartcar.com/docs/api#post-batch-request) | Param | Type | Description | | --- | --- | --- | -| permissions | Array.<String> \| String | Permission(s) to check | +| paths | Array.<String> | A list of paths of endpoints to send requests to. | - + -### vehicle.info() ⇒ [Promise.<Info>](#Info) -GET Vehicle.info +### vehicle.vin() ⇒ [Vin](#Vin) +Returns the vehicle's manufacturer identifier (VIN). **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<Info>](#Info) - A promise for info on the vehicle's info **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. - +**See**: [Smartcar API Doc - VIN](https://smartcar.com/docs/api#get-vin) + -### vehicle.location() ⇒ [Promise.<Location>](#Location) -GET Vehicle.location +### vehicle.charge() ⇒ [Charge](#Charge) +Returns the current charge status of the vehicle. **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<Location>](#Location) - A promise for info on the vehicle's location. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. - +**See**: [Smartcar API Doc - EV charging status](https://smartcar.com/docs/api#get-ev-charging-status) + -### vehicle.odometer() ⇒ [Promise.<Odometer>](#Odometer) -GET Vehicle.odometer +### vehicle.battery() ⇒ [Battery](#Battery) +Returns the state of charge (SOC) and remaining range of an electric or +plug-in hybrid vehicle's battery. **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<Odometer>](#Odometer) - A promise for info on the vehicle's odometer. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. - +**See**: [Smartcar API Doc - EV battery level](https://smartcar.com/docs/api#get-ev-battery) + -### vehicle.oil() ⇒ [Promise.<EngineOil>](#EngineOil) -GET Vehicle.oil +### vehicle.batteryCapacity() ⇒ [BatteryCapacity](#BatteryCapacity) +Returns the capacity of an electric or plug-in hybrid vehicle's battery. **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<EngineOil>](#EngineOil) - A promise for info on the vehicle's engine oil. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. - +**See**: [Smartcar API Doc - EV battery capacity](https://smartcar.com/docs/api#get-ev-battery-capacity) + -### vehicle.tirePressure() ⇒ [Promise.<TirePressure>](#TirePressure) -GET Vehicle.tirePressure +### vehicle.fuel() ⇒ [Fuel](#Fuel) +Returns the status of the fuel remaining in the vehicle's gas tank. **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<TirePressure>](#TirePressure) - A promise for info on the vehicle's tire pressure. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. - +**See**: [Smartcar API Doc - Fuel tank](https://smartcar.com/docs/api#get-fuel-tank) + -### vehicle.fuel() ⇒ [Promise.<Fuel>](#Fuel) -GET Vehicle.fuel +### vehicle.tirePressure() ⇒ [TirePressure](#TirePressure) +Returns the air pressure of each of the vehicle's tires. **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<Fuel>](#Fuel) - A promise for info on the vehicle's fuel status. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. - +**See**: [Smartcar API Doc - Tire pressure](https://smartcar.com/docs/api#get-tire-pressure) + -### vehicle.battery() ⇒ [Promise.<Battery>](#Battery) -GET Vehicle.battery +### vehicle.engineOil() ⇒ [EngineOil](#EngineOil) +Returns the remaining life span of a vehicle's engine oil **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<Battery>](#Battery) - A promise for info on the vehicle's battery status. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. - +**See**: [Smartcar API Doc - Engine oil life](https://smartcar.com/docs/api#get-engine-oil-life) + -### vehicle.batteryCapacity() ⇒ [Promise.<BatteryCapacity>](#BatteryCapacity) -GET Vehicle.batteryCapacity +### vehicle.odometer() ⇒ [Odometer](#Odometer) +Returns the vehicle's last known odometer reading. **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<BatteryCapacity>](#BatteryCapacity) - A promise for info on the vehicle's battery capacity. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. - +**See**: [Smartcar API Doc - Odometer](https://smartcar.com/docs/api#get-odometer) + -### vehicle.charge() ⇒ [Promise.<Charge>](#Charge) -GET Vehicle.charge +### vehicle.location() ⇒ [Location](#Location) +Returns the last known location of the vehicle in geographic coordinates. **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<Charge>](#Charge) - A promise for info on the vehicle's charge status. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. - +**See**: [Smartcar API Doc - Location](https://smartcar.com/docs/api#get-location) + -### vehicle.vin() ⇒ Promise.<String> -GET Vehicle.vin +### vehicle.attributes() ⇒ [Attributes](#Attributes) +Returns make model year and id of the vehicle **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: Promise.<String> - A promise for info on the vehicle's vin. **Throws**: -- SmartcarError - an instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. +**See**: [Smartcar API Doc - Vehicle attributes](https://smartcar.com/docs/api#get-vehicle-attributes) -### vehicle.lock() ⇒ [Promise.<ActionSuccess>](#ActionSuccess) -POST Vehicle.lock +### vehicle.lock() ⇒ [ActionResponse](#ActionResponse) +Attempts to lock the vehicle. **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<ActionSuccess>](#ActionSuccess) - response on successful request **Throws**: -- SmartcarError - on unsuccessful request. An instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. +**See**: [Smartcar API Doc - Lock](https://smartcar.com/docs/api#post-lockunlock) -### vehicle.unlock() ⇒ [Promise.<ActionSuccess>](#ActionSuccess) -POST Vehicle.unlock +### vehicle.unlock() ⇒ [ActionResponse](#ActionResponse) +Attempts to lock the vehicle. **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<ActionSuccess>](#ActionSuccess) - response on successful request **Throws**: -- SmartcarError - on unsuccessful request. An instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. +**See**: [Smartcar API Doc - Unlock](https://smartcar.com/docs/api#post-lockunlock) -### vehicle.startCharge() ⇒ [Promise.<ActionSuccess>](#ActionSuccess) -POST Vehicle.startCharge +### vehicle.startCharge() ⇒ [ActionResponse](#ActionResponse) +Attempts to start charging the vehicle. **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<ActionSuccess>](#ActionSuccess) - response on successful request **Throws**: -- SmartcarError - on unsuccessful request. An instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. +**See**: [Smartcar API Doc - EV start charge](https://smartcar.com/docs/api#post-ev-startstop-charge) -### vehicle.stopCharge() ⇒ [Promise.<ActionSuccess>](#ActionSuccess) -POST Vehicle.stopCharge +### vehicle.stopCharge() ⇒ [ActionResponse](#ActionResponse) +Attempts to stop charging the vehicle. **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<ActionSuccess>](#ActionSuccess) - response on successful request **Throws**: -- SmartcarError - on unsuccessful request. An instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. - +**See**: [Smartcar API Doc - EV stop charge](https://smartcar.com/docs/api#post-ev-startstop-charge) + -### vehicle.batch(paths) ⇒ [Promise.<Batch>](#Batch) -POST Vehicle.batch +### vehicle.disconnect() ⇒ [ActionResponse](#ActionResponse) +Disconnect this vehicle from the connected application. +Note: Calling this method will invalidate your token's access to the vehicle. +You will have to reauthorize the user to your application again if you wish +to make requests to it again. **Kind**: instance method of [Vehicle](#Vehicle) -**Returns**: [Promise.<Batch>](#Batch) - response on successful request **Throws**: -- SmartcarError - on unsuccessful request. An instance of SmartcarError. +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) for all possible errors. +**See**: [Smartcar API Doc - Disconnect](https://smartcar.com/docs/api#delete-disconnect) + -| Param | Type | Description | -| --- | --- | --- | -| paths | Array.<String> | A list of paths of endpoints to send requests to. | - - - -## parseAge(response) ⇒ Date \| null -**Kind**: global function -**Returns**: Date \| null - A parsed age or null if no age exists - -| Param | Type | -| --- | --- | -| response | Object | +## METHODS\_MAP : object.<String, Object> +Every key here is the function name on vehicle +This map is used to generate the methods dynamically. Every value is an object of +the following fields : +- requestType: http request type, defaults to 'get' if not mentioned. +- path: url path to hit, defaults to the method name +- body: body for post requests. +**Kind**: global constant ## Access : Object @@ -902,149 +870,132 @@ POST Vehicle.batch refreshExpiration: new Date('2017-05-26T01:21:27.070Z'), } ``` - + -## Info : Object +## Permissions : Object **Kind**: global typedef **Properties** | Name | Type | Description | | --- | --- | --- | -| id | String | The vehicle's unique Smartcar identifier. | -| make | String | The brand of the vehicle. | -| model | String | The specific model of the vehicle. | -| year | Number | The model year of the vehicle. | +| permissions | Array.<String> | An array of permissions names. | +| [paging] | Object | | +| [paging.count] | Number | The total number of elements for the entire query (not just the given page). | +| [options.offset] | Number | The current start index of the returned list of elements. | +| meta | [Meta](#Meta) | | **Example** ```js { - id: '19c0cc8c-80e0-4182-9372-6ef903c7599c', - make: 'TESLA', - model: 'S', - year: 2017, + permissions: ['read_vehicle_info'], + paging: { + count: 25, + offset: 10 + }, + meta: { + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + } } ``` - + -## Location : Object +## WebhookSubscription : Object **Kind**: global typedef **Properties** | Name | Type | Description | | --- | --- | --- | -| data | Object | The returned vehicle data. | -| data.latitude | Number | The vehicle latitude (in degrees). | -| data.longitude | Number | The vehicle longitude (in degrees). | -| age | Date | The timestamp of when the data was recorded. | +| webhookId | String | Webhook Id that the vehicle was subscribed to | +| vehicleId | String | Current vehicle id that was subscribed to the webhook | +| meta | [Meta](#Meta) | | **Example** ```js { - data: { - latitude: 37.400880, - longitude: -122.057804, + webhookId: 'dd214915-0c26-13c5-8e42-7edfc2ab320a', + vehicleId: '19c0cc8c-80e0-4182-9372-6ef903c7599c', + meta: { + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', } - age: new Date('2018-05-04T07:20:50.844Z'), } ``` - + -## Odometer : Object +## Batch : Object **Kind**: global typedef **Properties** | Name | Type | Description | | --- | --- | --- | -| data | Object | The returned vehicle data. | -| data.distance | Number | The reading of the vehicle's odometer (in kms or miles). To set unit, see [setUnitSystem](#Vehicle+setUnitSystem). | -| age | Date | The timestamp of when the data was recorded. | -| unitSystem | String | The unit system of the returned odometer reading. `metric` signifies kilometers, `imperial` signifies miles. To set, see [setUnitSystem](#Vehicle+setUnitSystem). | +| ENDPOINT | function | The response object for a given ENDPOINT where ENDPOINT is a Smartcar endpoint (i.e. /odometer, /fuel) or throws SmartcarError if the endpoint resulted in an error. | **Example** ```js { - data: { - distance: 1234.12, - } - age: new Date('2018-05-04T07:20:50.844Z'), - unitSystem: 'imperial', + "odometer" : function() => returns odometer object or throws SmartcarError, + "location" : function() => returns odometer location or throws SmartcarError, } ``` - + -## EngineOil : Object +## Meta : Object **Kind**: global typedef **Properties** | Name | Type | Description | | --- | --- | --- | -| data | Object | The returned vehicle data. | -| data.lifeRemaining | Number | The engine oil's remaining life span (as a percentage). Oil life is based on the current quality of the oil. | -| age | Date | The timestamp of when the data was recorded. | +| dataAge | Date | The timestamp of when the data was recorded; returned if applicable. | +| requestId | String | The smartcar request ID for debugging | +| unitSystem | String | Unit system used, metric or imperial; returned if applicable. | **Example** ```js { - data: { - lifeRemaining: 0.86, - } - age: new Date('2018-05-04T07:20:50.844Z') + requestId: 'b9593682-8515-4f36-8190-bb56cde4c38a', + dataAge: new Date('2018-05-04T07:20:50.844Z'), + unitSystem: 'imperial', } ``` - + -## TirePressure : Object +## Vin : Object **Kind**: global typedef **Properties** | Name | Type | Description | | --- | --- | --- | -| data | Object | The returned vehicle data. | -| data.frontLeft | Number | The current air pressure of the front left tire | -| data.frontRight | Number | The current air pressure of the back right tire | -| data.backLeft | Number | The current air pressure of the back left tire | -| data.backRight | Number | The current air pressure of the back right tire | -| age | Date | The timestamp of when the data was recorded. | -| unitSystem | String | The unit system of the returned odometer reading. `metric` signifies kilopascals (kpa), `imperial` signifies pounds per square inch (psi). To set, see [setUnitSystem](#Vehicle+setUnitSystem). | +| vin | String | VIN of the vehicle | +| meta | [Meta](#Meta) | | **Example** ```js { - data: { - frontleft: 33, - frontRight: 34, - backLeft: 34, - backRight: 33 + vin: '12345678901234567', + meta: { + requestId: 'b9593682-8515-4f36-8190-bb56cde4c38a', } - age: new Date('2018-05-04T07:20:50.844Z'), - unitSystem: 'imperial' } ``` - + -## Fuel : Object +## Charge : Object **Kind**: global typedef **Properties** | Name | Type | Description | | --- | --- | --- | -| data | Object | The returned vehicle data. | -| data.range | Number | The estimated remaining distance the car can travel (in kms or miles). To set unit, see [setUnitSystem](#Vehicle+setUnitSystem). | -| data.percentRemaining | Number | The remaining level of fuel in the tank (in percent). | -| data.amountRemaining | Number | The amount of fuel in the tank (in liters or gallons (US)). To set unit, see [setUnitSystem](#Vehicle+setUnitSystem). | -| age | Date | The timestamp of when the data was recorded. | -| unitSystem | String | The unit system of the returned data. To set, see [setUnitSystem](#Vehicle+setUnitSystem). | +| isPluggedIn | Boolean | Indicates whether charging cable is plugged in. | +| state | String | Indicates the current state of the charge system. Can be `FULLY_CHARGED`, `CHARGING`, or `NOT_CHARGING`. | +| meta | [Meta](#Meta) | | **Example** ```js { - data: { - range: 40.5, - percentRemaining: 0.3, - amountRemaining: 40.5, + isPluggedIn: false, + state: "FULLY_CHARGED", + meta: { + dataAge: new Date('2018-05-04T07:20:50.844Z'), } - age: new Date('2018-05-04T07:20:50.844Z'), - unitSystem: 'imperial', } ``` @@ -1055,21 +1006,20 @@ POST Vehicle.batch | Name | Type | Description | | --- | --- | --- | -| data | Object | The returned vehicle data. | -| data.range | Number | The estimated remaining distance the car can travel (in kms or miles). To set unit, see [setUnitSystem](#Vehicle+setUnitSystem). | -| data.percentRemaining | Number | The remaining level of charge in the battery (in percent). | -| age | Date | The timestamp of when the data was recorded. | -| unitSystem | String | The unit system of the returned data. To set, see [setUnitSystem](#Vehicle+setUnitSystem). | +| range | Number | The estimated remaining distance the car can travel (in kms or miles). Unit is passed as a parameter in vehicle constructor. | +| percentRemaining | Number | The remaining level of charge in the battery (in percent). | +| meta | [Meta](#Meta) | | **Example** ```js { - data: { - range: 40.5, - percentRemaining: 0.3, + range: 40.5, + percentRemaining: 0.3, + meta: { + dataAge: new Date('2018-05-04T07:20:50.844Z'), + unitSystem: 'imperial', + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', } - age: new Date('2018-05-04T07:20:50.844Z'), - unitSystem: 'imperial', } ``` @@ -1080,96 +1030,185 @@ POST Vehicle.batch | Name | Type | Description | | --- | --- | --- | -| data | Object | The returned vehicle data. | -| data.capacity | Number | The total capacity of the vehicle's battery (in kilowatt-hours) | -| age | Date | The timestamp of when the data was recorded. | -| unitSystem | String | The unit system of the returned data. To set, see [setUnitSystem](#Vehicle+setUnitSystem). | +| capacity | Number | The total capacity of the vehicle's battery (in kilowatt-hours) | +| meta | [Meta](#Meta) | | **Example** ```js { - data: { - capacity: 24, + capacity: 24, + meta: { + dataAge: new Date('2018-05-04T07:20:50.844Z'), + unitSystem: 'imperial', + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', } - age: new Date('2018-05-04T07:20:50.844Z'), - unitSystem: 'metric', } ``` - + -## Charge : Object +## Fuel : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| range | Number | The estimated remaining distance the car can travel (in kms or miles). Unit is passed as a parameter in vehicle constructor. | +| percentRemaining | Number | The remaining level of fuel in the tank (in percent). | +| amountRemaining | Number | The amount of fuel in the tank (in liters or gallons (US)). Unit is passed as a parameter in vehicle constructor. | +| meta | [Meta](#Meta) | | + +**Example** +```js +{ + range: 40.5, + percentRemaining: 0.3, + amountRemaining: 40.5, + meta: { + dataAge: new Date('2018-05-04T07:20:50.844Z'), + unitSystem: 'imperial', + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + } +} +``` + + +## TirePressure : Object **Kind**: global typedef **Properties** | Name | Type | Description | | --- | --- | --- | -| data | Object | The returned vehicle data. | -| data.isPluggedIn | Number | Indicates whether charging cable is plugged in. | -| data.state | Number | Indicates the current state of the charge system. Can be `FULLY_CHARGED`, `CHARGING`, or `NOT_CHARGING`. | -| age | Date | The timestamp of when the data was recorded. | +| frontLeft | Number | The current air pressure of the front left tire | +| frontRight | Number | The current air pressure of the back right tire | +| backLeft | Number | The current air pressure of the back left tire | +| backRight | Number | The current air pressure of the back right tire | +| meta | [Meta](#Meta) | | **Example** ```js { - data: { - isPluggedIn: false, - state: "FULLY_CHARGED", + frontleft: 33, + frontRight: 34, + backLeft: 34, + backRight: 33 + meta: { + dataAge: new Date('2018-05-04T07:20:50.844Z'), + unitSystem: 'imperial', + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', } - age: new Date('2018-05-04T07:20:50.844Z'), } ``` - + -## ActionSuccess : Object +## EngineOil : Object **Kind**: global typedef **Properties** | Name | Type | Description | | --- | --- | --- | -| status | String | set to `success` on successful request | +| lifeRemaining | Number | The engine oil's remaining life span (as a percentage). Oil life is based on the current quality of the oil. | +| meta | [Meta](#Meta) | | **Example** ```js { - status: 'success', + lifeRemaining: 0.86, + meta: { + dataAge: new Date('2018-05-04T07:20:50.844Z'), + unitSystem: 'imperial', + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + } } ``` - + -## Batch : Object +## Odometer : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| distance | Number | The reading of the vehicle's odometer (in kms or miles). Unit is passed as a parameter in vehicle constructor. | +| meta | [Meta](#Meta) | | + +**Example** +```js +{ + distance: 1234.12, + meta: { + dataAge: new Date('2018-05-04T07:20:50.844Z'), + unitSystem: 'imperial', + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + } +} +``` + + +## Location : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| latitude | Number | The vehicle latitude (in degrees). | +| longitude | Number | The vehicle longitude (in degrees). | +| meta | [Meta](#Meta) | | + +**Example** +```js +{ + latitude: 37.400880, + longitude: -122.057804, + meta: { + dataAge: new Date('2018-05-04T07:20:50.844Z'), + unitSystem: 'imperial', + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + } +} +``` + + +## Attributes : Object **Kind**: global typedef **Properties** | Name | Type | Description | | --- | --- | --- | -| responses | Object | The object containing multiple HTTP responses. | -| data.ENDPOINT | Object | The HTTP response for a given endpoint. ENDPOINT is a Smartcar endpoint (i.e. /odometer, /fuel). | -| data.ENDPOINT.code | Number | The HTTP status code for this response. | -| data.ENDPOINT.headers | Object | The HTTP headers for this response. | -| data.ENDPOINT.body | Object | The body for this response. | +| id | String | The vehicle's unique Smartcar identifier. | +| make | String | The brand of the vehicle. | +| model | String | The specific model of the vehicle. | +| year | Number | The model year of the vehicle. | +| meta | [Meta](#Meta) | | **Example** ```js { - "/odometer" : { - "body": { - "distance": 37829 - }, - "code": 200, - "headers": { - "sc-data-age": "2019-10-24T00:43:46.000Z", - "sc-unit-system": "metric" - } - }, - "/location" : { - "body": { - "latitude": 37.4292, - "longitude": 122.1381 - }, - "code": 200, - "headers": { - "sc-data-age": "2019-10-24T00:43:46.000Z" - } - } + id: '19c0cc8c-80e0-4182-9372-6ef903c7599c', + make: 'TESLA', + model: 'S', + year: 2017, + meta: { + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + } +} +``` + + +## ActionResponse : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| status | String | set to `success` on successful request | +| meta | [Meta](#Meta) | | + +**Example** +```js +{ + status: 'success', + meta: { + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + } } ``` diff --git a/index.js b/index.js index 0a5fb9d6..47568ea4 100644 --- a/index.js +++ b/index.js @@ -1,18 +1,16 @@ 'use strict'; -const Promise = require('bluebird'); -const _ = require('lodash'); +const crypto = require('crypto'); +const SmartcarService = require('./lib/smartcar-service'); const util = require('./lib/util'); const config = require('./lib/config'); -// Tolerance for expiration measured in milliseconds -const TOLERANCE = 10 * 1000; /* eslint-disable global-require */ /** @exports smartcar */ const smartcar = { /** @see {@link module:errors} */ - errors: require('./lib/errors'), + SmartcarError: require('./lib/smartcar-error'), /** @see {@link Vehicle} */ Vehicle: require('./lib/vehicle'), /** @see {@link AuthClient}*/ @@ -20,6 +18,29 @@ const smartcar = { }; /* eslint-enable global-require */ +const buildQueryParams = function(vin, scope, country, options) { + const parameters = { + vin, + scope: scope.join(' '), + country, + }; + if (options.flags) { + parameters.flags = util.getFlagsString(options.flags); + } + + if (options.hasOwnProperty('testMode')) { + parameters.mode = options.testMode ? 'test' : 'live'; + } + + if (options.testModeCompatibilityLevel) { + // eslint-disable-next-line camelcase + parameters.test_mode_compatibility_level = + options.testModeCompatibilityLevel; + parameters.mode = 'test'; + } + + return parameters; +}; /** * Sets the version of Smartcar API you are using @@ -31,28 +52,46 @@ smartcar.setApiVersion = function(version) { }; /** - * Check if a token has expired. - * + * Gets the version of Smartcar API that is set * @method - * @param {Date|String} expiration - token expiration timestamp - * @return {Boolean} true if expired, false if not expired + * @return {String} version */ -smartcar.isExpired = function(expiration) { - const msg = '"expiration" argument must be a Date object or ISO date string'; - let epoch; - if (_.isDate(expiration)) { - epoch = expiration.getTime(); - } else if (_.isString(expiration)) { - epoch = Date.parse(expiration); - } else { - throw new TypeError(msg); - } +smartcar.getApiVersion = () => (config.version); - if (!Number.isFinite(epoch)) { // eslint-disable-next-line max-len - throw new TypeError(msg); - } +/** + * @type {Object} + * @typedef User + * @property {String} id - User Id + * @property {module:smartcar.Vehicle.Meta} meta + * + * @example + * { + * id: "e0514ef4-5226-11e8-8c13-8f6e8f02e27e", + * meta: { + * requestId: 'b9593682-8515-4f36-8190-bb56cde4c38a', + * } + * } + */ - return Date.now() > epoch - TOLERANCE; +/** + * Return the user's id. + * + * @method + * @param {String} accessToken - access token + * @return {module:smartcar~User} + * @throws {SmartcarError} - an instance of SmartcarError. + * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) + * for all possible errors. + */ +smartcar.getUser = async function(accessToken) { + const response = await new SmartcarService({ + baseUrl: util.getConfig('SMARTCAR_API_ORIGIN') || config.api, + auth: {bearer: accessToken}, + }).request( + 'get', + `/v${config.version}/user`, + ); + return response; }; /** @@ -63,6 +102,7 @@ smartcar.isExpired = function(expiration) { * @property {Number} paging.count- The total number of vehicles. * @property {Number} paging.offset - The current start index of returned * vehicle ids. + * @property {module:smartcar.Vehicle.Meta} meta * * @example * { @@ -73,6 +113,9 @@ smartcar.isExpired = function(expiration) { * paging: { * count: 2, * offset: 0, + * }, + * meta: { + * requestId: 'b9593682-8515-4f36-8190-bb56cde4c38a', * } * } */ @@ -81,53 +124,113 @@ smartcar.isExpired = function(expiration) { * Return list of the user's vehicles ids. * * @method - * @param {String} token - access token + * @param {String} accessToken - access token * @param {Object} [paging] * @param {Number} [paging.limit] - number of vehicles to return * @param {Number} [paging.offset] - index to start vehicle list - * @return {Promise.} A promise with the vehicle ids. + * @return {module:smartcar~VehicleIds} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -smartcar.getVehicleIds = Promise.method(function(token, paging) { - - if (!_.isString(token)) { - throw new TypeError('"token" argument must be a string'); - } - return util.request.get(util.getUrl(), { - auth: { - bearer: token, - }, +smartcar.getVehicles = async function(accessToken, paging = {}) { + const response = await new SmartcarService({ + baseUrl: util.getUrl(), + auth: {bearer: accessToken}, qs: paging, - }); + }).request('get', ''); + return response; +}; -}); +/** + * @type {Object} + * @typedef Compatibility + * @property {Boolean} compatible + * @property {module:smartcar.Vehicle.Meta} meta + * + * @example + * { + * compatible: false, + * meta: { + * requestId: 'b9593682-8515-4f36-8190-bb56cde4c38a', + * } + * } + */ /** - * Return the user's id. + * Determine whether a vehicle is compatible with Smartcar. * - * @method - * @param {String} token - access token - * @return {Promise.} the user id + * A compatible vehicle is a vehicle that: + * 1. has the hardware required for internet connectivity, + * 2. belongs to the makes and models Smartcar supports, and + * 3. supports the permissions. + * + * _To use this function, please contact us!_ + * + * @param {String} vin - the VIN of the vehicle + * @param {String[]} scope - list of permissions to check compatibility for + * @param {String} [country='US'] - an optional country code according to [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). + * @param {Object} [options] + * @param {String} [options.clientId] - client ID to use for basic auth. + * @param {String} [options.clientSecret] - client secret to use for basic auth. + * @param {Object} [options.flags] - Object of flags where key is the name of the flag + * value is string or boolean value. + * @param {Object} [options.version] - API version to use + * @return {module:smartcar~Compatibility} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -smartcar.getUserId = Promise.method(function(token) { - - if (!_.isString(token)) { - throw new TypeError('"token" argument must be a string'); - } - - return util.request.get(`${config.api}/v${config.version}/user`, { +smartcar.getCompatibility = async function( + vin, + scope, + country, + options = {}, +) { + country = country || 'US'; + const clientId = options.clientId + || util.getOrThrowConfig('SMARTCAR_CLIENT_ID'); + const clientSecret = options.clientSecret + || util.getOrThrowConfig('SMARTCAR_CLIENT_SECRET'); + + const response = await new SmartcarService({ + baseUrl: util.getConfig('SMARTCAR_API_ORIGIN') || config.api, auth: { - bearer: token, + user: clientId, + pass: clientSecret, }, - }).then(function(response) { - return response.id; - }); + qs: buildQueryParams(vin, scope, country, options), + }).request( + 'get', + `v${options.version || config.version}/compatibility`, + ); + return response; +}; + +/** + * Generate hash challenege for webhooks. It does HMAC_SHA256(amt, challenge) + * + * @method + * @param {String} amt - Application Management Token + * @param {String} challenge - Challenge string + * @return {String} String representing the hex digest + */ +smartcar.hashChallenge = function(amt, challenge) { + const hmac = crypto.createHmac('sha256', amt); + return hmac.update(challenge).digest('hex'); +}; -}); +/** + * Verify webhook payload with AMT and signature. + * + * @method + * @param {String} amt - Application Management Token + * @param {String} signature - sc-signature header value + * @param {object} body - webhook response body + * @return {Boolean} true if signature matches the hex digest of amt and body + */ +smartcar.verifyPayload = (amt, signature, body) => ( + smartcar.hashChallenge(amt, JSON.stringify(body)) === signature +); module.exports = smartcar; diff --git a/lib/auth-client.js b/lib/auth-client.js index 67191f22..3f03b0a8 100644 --- a/lib/auth-client.js +++ b/lib/auth-client.js @@ -1,8 +1,7 @@ 'use strict'; -const Joi = require('joi'); const qs = require('querystring'); - +const SmartcarService = require('./smartcar-service'); const util = require('./util'); const config = require('./config'); @@ -41,54 +40,21 @@ const config = require('./config'); * @param {String} options.redirectUri - Redirect URI registered in the * [application settings](https://developer.smartcar.com/apps). The given URL * must exactly match one of the registered URLs. - * @param {String[]} [options.scope=all] - List of permissions your application - * requires. This will default to requiring all scopes. The valid permission - * names are found in the - * [API Reference](https://smartcar.com/docs#get-all-vehicles). * @param {Boolean} [options.testMode=false] - Launch Smartcar Connect in * [test mode](https://smartcar.com/docs/guides/testing/). - * @param {Boolean} [options.development=false] - DEPRECATED: Launch Smartcar auth in - * development mode to enable mock vehicle brands. */ -function AuthClient(options) { - const schema = Joi.object().keys({ - clientId: Joi.string() - .guid({ - version: ['uuidv4'], - }) - .required(), - clientSecret: Joi.string() - .guid({ - version: ['uuidv4'], - }) - .required(), - redirectUri: Joi.string() - .uri() - .required(), - scope: Joi.array().items(Joi.string()), - development: Joi.boolean(), - testMode: Joi.boolean(), - }); - - Joi.assert(options, schema); - - this.clientId = options.clientId; - this.clientSecret = options.clientSecret; - this.redirectUri = options.redirectUri; - this.scope = options.scope; - - if (options.development !== undefined) { - /* eslint-disable-next-line no-console */ - console.warn(`DeprecationWarning: development flag is deprecated. - This is discouraged and will be removed in the next major release. - Use testMode instead`); - this.development = options.development; - } +function AuthClient(options = {}) { + this.clientId = options.clientId + || util.getOrThrowConfig('SMARTCAR_CLIENT_ID'); + this.clientSecret = options.clientSecret + || util.getOrThrowConfig('SMARTCAR_CLIENT_SECRET'); + this.redirectUri = options.redirectUri + || util.getOrThrowConfig('SMARTCAR_REDIRECT_URI'); this.testMode = options.testMode === true; - this.request = util.request.defaults({ - baseUrl: config.auth, + this.service = new SmartcarService({ + baseUrl: util.getConfig('SMARTCAR_AUTH_ORIGIN') || config.auth, auth: { user: this.clientId, pass: this.clientSecret, @@ -103,33 +69,30 @@ function AuthClient(options) { * approved the set of scopes for this application. The application can elect * to always display the permissions dialog to the user by setting * approval_prompt to `force`. - * + * @param {String[]} [scope] - List of permissions your application + * requires. The valid permission names are found in the [API Reference](https://smartcar.com/docs/guides/scope/) * @param {Object} [options] - * @param {String} [options.state] - OAuth state parameter passed to the - * redirect uri. This parameter may be used for identifying the user who - * initiated the request. - * @param {Boolean} [options.forcePrompt=false] - Setting `forcePrompt` to + * @param {Boolean} [options.forcePrompt] - Setting `forcePrompt` to * `true` will show the permissions approval screen on every authentication * attempt, even if the user has previously consented to the exact scope of * permissions. - * @param {Object} [options.vehicleInfo.make] - `vehicleInfo` is an - * object with an optional property `make`. An optional parameter that allows + * @param {Boolean|Object} [options.singleSelect] - An optional value that sets the + * behavior of the grant dialog displayed to the user. Object can contain two keys : + * - enabled - Boolean value, if set to `true`, `single_select` limits the user to + * selecting only one vehicle. + * - vin - String vin, if set, Smartcar will only authorize the vehicle with the specified VIN. + * See the [Single Select guide](https://smartcar.com/docs/guides/single-select/) for more information. + * @param {String} [options.state] - OAuth state parameter passed to the + * redirect uri. This parameter may be used for identifying the user who + * initiated the request. + * @param {Object} [options.makeBypass] - An optional parameter that allows * users to bypass the car brand selection screen. * For a complete list of supported makes, please see our * [API Reference](https://smartcar.com/docs/api#authorization) documentation. - * @param {Boolean|Object} [options.singleSelect] - An optional value that sets the - * behavior of the grant dialog displayed to the user. If set to `true`, - * `single_select` limits the user to selecting only one vehicle. If `single_select` - * is an object with the property `vin`, Smartcar will only authorize the vehicle - * with the specified VIN. See the - * [Single Select guide](https://smartcar.com/docs/guides/single-select/) - * for more information. - * @param {String[]} [options.flags] - List of feature flags that your application - * has early access to. + * @param {Object} [options.flags] - Object of flags where key is the name of the flag + * value is string or boolean value. + * * @return {String} Smartcar Connect URL to direct user to. - * @throws {SmartcarError} - an instance of SmartcarError. - * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) - * for all possible errors. * @example * https://connect.smartcar.com/oauth/authorize? * response_type=code @@ -142,59 +105,42 @@ function AuthClient(options) { * &single_select_vin=5YJSA1E14FF101307 * &flags=country:DE color:00819D */ -AuthClient.prototype.getAuthUrl = function(options) { - options = options || {}; - const forcePrompt = options.forcePrompt === true; - +AuthClient.prototype.getAuthUrl = function(scope, options = {}) { /* eslint-disable camelcase */ const parameters = { response_type: 'code', client_id: this.clientId, redirect_uri: this.redirectUri, - approval_prompt: forcePrompt ? 'force' : 'auto', + approval_prompt: options.forcePrompt === true ? 'force' : 'auto', }; /* eslint-enable camelcase */ - if (this.scope) { - parameters.scope = this.scope.join(' '); - } + parameters.scope = scope.join(' '); if (options.state) { parameters.state = options.state; } - if (options.singleSelect !== undefined && options.singleSelect !== null) { - if (typeof options.singleSelect === 'object') { - const availableParams = ['vin']; - /* eslint-disable camelcase */ - parameters.single_select = false; - for (const param of availableParams) { - if (param in options.singleSelect) { - parameters['single_select_' + param] = options.singleSelect[param]; - parameters.single_select = true; - } - } - } else { - parameters.single_select = options.singleSelect === true; - /* eslint-enable camelcase*/ + if (options.singleSelect) { + /* eslint-disable camelcase */ + if (options.singleSelect.vin) { + parameters.single_select = true; + parameters.single_select_vin = options.singleSelect.vin; + } else if ([true, false].includes(options.singleSelect.enabled)) { + parameters.single_select = options.singleSelect.enabled; } + /* eslint-enable camelcase */ } - if (options.vehicleInfo) { - const availableParams = ['make']; - for (const param of availableParams) { - if (param in options.vehicleInfo) { - parameters[param] = options.vehicleInfo[param]; - } - } + if (options.makeBypass) { + parameters.make = options.makeBypass; } if (options.flags) { - parameters.flags = options.flags.join(' '); + parameters.flags = util.getFlagsString(options.flags); } - const mode = this.development || this.testMode; - parameters.mode = mode ? 'test' : 'live'; + parameters.mode = this.testMode ? 'test' : 'live'; const query = qs.stringify(parameters); @@ -206,12 +152,19 @@ AuthClient.prototype.getAuthUrl = function(options) { * * @param {String} code - Authorization code to exchange for a Smartcar * access token and refresh token. - * @return {Promise.} Access and Refresh tokens. + * @param {Object} [options.flags] - Object of flags where key is the name of the flag + * value is string or boolean value. + * @return {Access} New set of Access and Refresh tokens. * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -AuthClient.prototype.exchangeCode = function(code) { +AuthClient.prototype.exchangeCode = async function(code, options = {}) { + const qs = {}; + if (options.flags) { + qs.flags = util.getFlagsString(options.flags); + } + /* eslint-disable camelcase */ const form = { code, @@ -220,9 +173,13 @@ AuthClient.prototype.exchangeCode = function(code) { }; /* eslint-enable camelcase */ - return util - .wrap(this.request.post('/oauth/token', {form})) - .then(util.formatAccess); + const response = await this.service.request( + 'post', + '/oauth/token', + {form}, + {qs}, + ); + return util.formatAccess(response); }; /** @@ -230,12 +187,22 @@ AuthClient.prototype.exchangeCode = function(code) { * * @param {String} token - Refresh token to exchange for a new set of Access and * Refresh tokens. - * @return {Promise.} New set of Access and Refresh tokens. + * @param {Object} [options.flags] - Object of flags where key is the name of the flag + * value is string or boolean value. + * @return {Access} New set of Access and Refresh tokens. * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -AuthClient.prototype.exchangeRefreshToken = function(token) { +AuthClient.prototype.exchangeRefreshToken = async function( + token, + options = {}, +) { + const qs = {}; + if (options.flags) { + qs.flags = util.getFlagsString(options.flags); + } + /* eslint-disable camelcase */ const form = { grant_type: 'refresh_token', @@ -243,45 +210,13 @@ AuthClient.prototype.exchangeRefreshToken = function(token) { }; /* eslint-enable camelcase */ - return util - .wrap(this.request.post('/oauth/token', {form})) - .then(util.formatAccess); -}; - -/** - * Determine whether a vehicle is compatible with Smartcar. - * - * A compatible vehicle is a vehicle that: - * 1. has the hardware required for internet connectivity, - * 2. belongs to the makes and models Smartcar supports, and - * 3. supports the permissions. - * - * _To use this function, please contact us!_ - * - * @param {String} vin - the VIN of the vehicle - * @param {String[]} scope - list of permissions to check compatibility for - * @param {String} [country='US'] - an optional country code according to [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). - * @return {Promise.} false if the vehicle is not compatible. true if the - * vehicle is likely compatible. - * @throws {SmartcarError} - an instance of SmartcarError. - * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) - * for all possible errors. - */ -AuthClient.prototype.isCompatible = function(vin, scope, country = 'US') { - const qs = { - vin, - scope: scope.join(' '), - country, - }; - - return util.wrap(this.request.get({ - baseUrl: config.api, - url: `v${config.version}/compatibility`, - qs, - })) - .then(function(response) { - return response.compatible; - }); + const response = await this.service.request( + 'post', + '/oauth/token', + {form}, + {qs}, + ); + return util.formatAccess(response); }; module.exports = AuthClient; diff --git a/lib/config.json b/lib/config.json index be86d4a0..d21d4b36 100644 --- a/lib/config.json +++ b/lib/config.json @@ -3,5 +3,5 @@ "api": "https://api.smartcar.com", "connect": "https://connect.smartcar.com", "timeout": 310000, - "version": "1.0" + "version": "2.0" } diff --git a/lib/errors.js b/lib/errors.js deleted file mode 100644 index 9f6c072c..00000000 --- a/lib/errors.js +++ /dev/null @@ -1,259 +0,0 @@ -'use strict'; - -const util = require('util'); - -const append = function(message) { - return message ? `: ${message}` : ''; -}; - -/** @exports errors */ -const errors = {}; - -/** - * Superclass for all sdk errors. - * - * @extends Error - * @param message - an error description to set - */ -errors.SmartcarError = function(message) { - this.name = 'smartcar_error'; - this.message = message ? String(message) : 'Unexpected server error'; - Error.captureStackTrace(this, this.constructor); -}; -util.inherits(errors.SmartcarError, Error); - -/** - * Error thrown by request validation. - * - * @extends SmartcarError - * @param message - an error description to set - */ -errors.ValidationError = function(message) { - this.name = 'validation_error'; - this.statusCode = 400; - /* istanbul ignore next */ - this.message = message || 'Invalid or missing request parameters'; - Error.captureStackTrace(this, this.constructor); -}; -util.inherits(errors.ValidationError, errors.SmartcarError); - -/** - * Error thrown by an invalid parameter when authenticating. - * - * @extends SmartcarError - * @param message - an error description to set - */ -errors.AuthenticationError = function(message) { - this.name = 'authentication_error'; - this.statusCode = 401; - this.message = message; - Error.captureStackTrace(this, this.constructor); -}; -util.inherits(errors.AuthenticationError, errors.SmartcarError); - -/** - * Error thrown due to insufficient permissions. - * - * @extends SmartcarError - * @param message - an error description to set - */ -errors.PermissionError = function(message) { - this.name = 'permission_error'; - this.statusCode = 403; - this.message = 'Insufficient permissions to access requested resource' + - append(message); - Error.captureStackTrace(this, this.constructor); -}; -util.inherits(errors.PermissionError, errors.SmartcarError); - -/** - * Error thrown when the requested resource is not found. - * - * @extends SmartcarError - * @param message - an error description to set - */ -errors.ResourceNotFoundError = function(message) { - this.name = 'resource_not_found_error'; - this.statusCode = 404; - this.message = 'The requested resource was not found' + - append(message); - Error.captureStackTrace(this, this.constructor); -}; -util.inherits(errors.ResourceNotFoundError, errors.SmartcarError); - -/** - * Error thrown when the vehicle is not capable of performing the request in - * the current vehicle state. - * - * @extends SmartcarError - * @param message - an error description to set - * @param code - a vehicle state error code (https://smartcar.com/docs/api#errors) - */ -errors.VehicleStateError = function(message, code) { - this.name = 'vehicle_state_error'; - this.statusCode = 409; - this.message = message; - this.code = code; - Error.captureStackTrace(this, this.constructor); -}; -util.inherits(errors.VehicleStateError, errors.SmartcarError); - -/** - * Error thrown when an application makes too many requests and is throttled. - * - * @extends SmartcarError - * @param message - an error description to set - */ -errors.RateLimitingError = function(message) { - this.name = 'rate_limiting_error'; - this.statusCode = 429; - this.message = 'The application has sent too many requests ' + - "and cannot be served due to the application's " + - 'rate limit being exhausted' + append(message); - Error.captureStackTrace(this, this.constructor); -}; -util.inherits(errors.RateLimitingError, errors.SmartcarError); - -/** - * Error thrown when an application requests more resources than its allowed - * limit, e.g., gone over their allotted monthly request limit. - * - * @extends SmartcarError - * @param message - an error description to set - */ -errors.MonthlyLimitExceeded = function(message) { - this.name = 'monthly_limit_exceeded'; - this.statusCode = 430; - this.message = 'The application has exceeded its monthly limit. ' + - 'Please upgrade the billing plan on the account ' + - 'dashboard' + append(message); - Error.captureStackTrace(this, this.constructor); -}; -util.inherits(errors.MonthlyLimitExceeded, errors.SmartcarError); - -/** - * Error thrown when the server throws an unexpected error. - * - * @extends SmartcarError - * @param message - an error description to set - */ -errors.ServerError = function(message) { - this.name = 'server_error'; - this.statusCode = 500; - this.message = 'Unexpected server error' + append(message); - Error.captureStackTrace(this, this.constructor); -}; -util.inherits(errors.ServerError, errors.SmartcarError); - -/** - * Error thrown when vehicle is not capable of performing the request. - * - * @extends SmartcarError - * @param message - an error description to set - */ -errors.VehicleNotCapableError = function(message) { - this.name = 'vehicle_not_capable_error'; - this.statusCode = 501; - this.message = - 'Vehicle is not capable of performing request' + append(message); - Error.captureStackTrace(this, this.constructor); -}; -util.inherits(errors.VehicleNotCapableError, errors.SmartcarError); - -/** - * Error thrown when Smartcar is not capable of performing the request. - * - * @extends SmartcarError - * @param message - an error description to set - */ -errors.SmartcarNotCapableError = function(message) { - this.name = 'smartcar_not_capable_error'; - this.statusCode = 501; - this.message = message; - Error.captureStackTrace(this, this.constructor); -}; -util.inherits(errors.SmartcarNotCapableError, errors.SmartcarError); - -/** - * Error thrown when gateway to Smartcar times out - * - * @param message - an error description to set - */ -errors.GatewayTimeoutError = function(message) { - this.name = 'smartcar_gateway_timeout_error'; - /* istanbul ignore next */ - this.message = message || 'ELB threw a 504.'; - Error.captureStackTrace(this, this.constructor); -}; -util.inherits(errors.GatewayTimeoutError, errors.SmartcarError); - -/** - * Enhanced errors from API v2.0 - * Please see our [v2.0 error guides]{@link https://smartcar.com/docs/errors/v2.0/billing} to see a list of all the possible error types and codes - * - * @param {Object|String} error - response body from a v2.0 request - */ -errors.SmartcarErrorV2 = class extends errors.SmartcarError { - constructor(error) { - if (typeof error === 'string') { - super(error); - this.description = error; - this.name = 'SmartcarErrorV2'; - return; - } else { - super(`${error.type}:${error.code} - ${error.description}`); - } - this.name = 'SmartcarErrorV2'; - - /** - * Type of error - * @type {string} - * @public - */ - this.type = error.type; - /** - * Error code - * @type {string} - * @public - */ - this.code = error.code; - /** - * Description of meaning of the error - * @type {string} - * @public - */ - this.description = error.description; - /** - * HTTP status code - * @type {number} - * @public - */ - this.statusCode = error.statusCode; - /** - * Unique identifier for request - * @type {string} - * @public - */ - this.requestId = error.requestId; - /** - * Possible resolution for fixing the error - * @type {string} - * @public - */ - this.resolution = error.resolution; - /** - * Reference to Smartcar documentation - * @type {string} - * @public - */ - this.docURL = error.docURL; - /** - * Further detail about the error - * @type {object[]} - * @public - */ - this.detail = error.detail; - } -}; - -module.exports = errors; diff --git a/lib/smartcar-error.js b/lib/smartcar-error.js new file mode 100644 index 00000000..45a96d8b --- /dev/null +++ b/lib/smartcar-error.js @@ -0,0 +1,122 @@ +'use strict'; + +/** @exports SmartcarError */ + +/** + * Class to handle all errors from Smartcar API + * Please see our [error guides]{@link https://smartcar.com/docs} to see a list + * of all the possible error types and codes of both v2.0 and v1.0 requests. + * */ +class SmartcarError extends Error { + + /** + * @param {number} status - response status + * @param {object} body - response body + * @param {object} headers - response headers + */ + constructor(status, body, headers) { + const fields = ['type', 'code', 'description', 'docURL', 'detail']; + if (body.error) { + body.type = body.error; + } + + if (!body.description) { + // `error_description` is for handling oauth. + if (body.error_description) { + body.description = body.error_description; + } else if (body.message) { + body.description = body.message; + } else if (typeof body !== 'string') { + body.description = 'Unknown error'; + } + } + + if (typeof body === 'string') { + super(body); + } else { + super(`${body.type}:${body.code} - ${body.description}`); + } + + this.statusCode = status; + this.requestId = body.requestId || headers['sc-request-id']; + if (typeof body.resolution === 'string') { + this.resolution = { + type: body.resolution, + }; + } else if (body.resolution !== null + && typeof body.resolution === 'object') { + this.resolution = body.resolution; + } + + // Now dynamically set the remaining ones if passed + fields.forEach((item) => { + if (body[item]) { + this[item] = body[item]; + } + }); + + this.name = 'SmartcarError'; + } +} + +/** + * Legacy field from V1 error depicting a category/type/description + * of the error. + * @var {string} SmartcarError.error + */ + +/** + * Error message field inherited from StandardError + * @var {string} SmartcarError.message + */ + +/** + * Description of meaning of the error. + * @var {string} SmartcarError.description + */ + +/** + * Type of error + * @var {string} SmartcarError.type + */ + +/** + * Error code + * @var {string} SmartcarError.code + */ + +/** + * HTTP status code + * @var {number} SmartcarError.statusCode + */ + +/** + * Unique identifier for request + * @var {string} SmartcarError.requestId + */ + +/** + * @type {Object} + * @typedef SmartcarError.Resolution + * @property {String} type - Possible hint to fixing the issue + * @property {String} url - A URL to help resolve the issue or resume the operation + */ + +/** + * Possible resolution for fixing the error + * @var {SmartcarError.Resolution} SmartcarError.resolution + */ + +/** + * Reference to Smartcar documentation + * @var {string} SmartcarError.docURL + */ + +/** + * Further detail about the error in form of array of objects + * @memberof SmartcarError + * + * @var {object[]} SmartcarError.details + */ + +module.exports = SmartcarError; diff --git a/lib/smartcar-service.js b/lib/smartcar-service.js new file mode 100644 index 00000000..ed864096 --- /dev/null +++ b/lib/smartcar-service.js @@ -0,0 +1,130 @@ + +'use strict'; + +const _ = require('lodash'); +const requestPromise = require('request-promise'); +const config = require('./config'); +const util = require('./util'); +const HEADER_TO_META_KEYS = { + 'sc-data-age': 'dataAge', + 'sc-unit-system': 'unitSystem', + 'sc-request-id': 'requestId', +}; + + +const buildMeta = (headers) => { + const lowerCaseHeaders = _.mapKeys( + headers, + (_, key) => key.toLocaleLowerCase() + ); + const meta = {}; + Object.entries(HEADER_TO_META_KEYS).forEach(([headerName, key]) => { + if (lowerCaseHeaders[headerName]) { + meta[key] = lowerCaseHeaders[headerName]; + } + }); + if (meta.dataAge) { + meta.dataAge = new Date(meta.dataAge); + } + + return meta; +}; + +const getNameFromPath = (path) => { + // Using this constant just for the ones with nested path. + const BATCH_PATH_TO_ATTRIBUTE = { + '/battery/capacity': 'batteryCapacity', + '/engine/oil': 'engineOil', + '/tires/pressure': 'tirePressure', + '/': 'attributes', + }; + if (BATCH_PATH_TO_ATTRIBUTE[path]) { + return BATCH_PATH_TO_ATTRIBUTE[path]; + } + + // For non nested path, it is just everything after '/' + return path.replace('/', ''); +}; +const buildBatchResponse = (body, headers) => { + const batchResponse = {}; + body.responses.forEach((response) => { + const attributeName = getNameFromPath(response.path); + if ([200, 204].includes(response.code)) { + batchResponse[attributeName] = () => { + return { + ...(response.body || {}), + meta: buildMeta({ + ...headers, + ...response.headers, + }), + }; + }; + } else { + batchResponse[attributeName] = () => { + util.handleError({ + statusCode: response.code, + response: { + body: response.body, + headers: { + ...headers, + ...response.headers, + }, + }, + }); + }; + } + }); + return batchResponse; +}; +/** + * Initializes a new Service object to make requests to the Smartcar API. + * + * @constructor + * @param {Object} [options] + * @param {String} [options.baseUrl] - Host/Base URL for the requests + * @param {Object} [options.auth] - authorization options + * @param {Object} [options.headers] - headers to add + */ +function SmartcarService(options = {}) { + const defaultOptions = { + json: true, + headers: { + 'User-Agent': util.USER_AGENT, + }, + timeout: config.timeout, + }; + this.requestObject = requestPromise.defaults( + _.merge(defaultOptions, options), + ); +} + +SmartcarService.prototype.request = async function( + type, + path, + body = {}, + options = {}, +) { + body.resolveWithFullResponse = true; + const response = await util.wrap( + this.requestObject.defaults(options)[type](path, body), + ); + + return { + ...(response.body || {}), + meta: buildMeta(response.headers), + }; +}; + +SmartcarService.prototype.batchRequest = async function(paths) { + const requests = paths.map((path) => ({path})); + const response = await util.wrap( + this.requestObject.post('batch', { + body: {requests}, + resolveWithFullResponse: true, + }), + ); + + return buildBatchResponse(response.body, response.headers); +}; + +module.exports = SmartcarService; diff --git a/lib/util.js b/lib/util.js index f1eb8280..9f41187c 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,13 +1,13 @@ 'use strict'; const _ = require('lodash'); -const request = require('request-promise'); const {format} = require('util'); const {StatusCodeError} = require('request-promise/errors'); const config = require('./config'); -const errors = require('./errors'); +const SmartcarError = require('./smartcar-error'); const {version} = require('../package.json'); +const {env} = require('process'); const util = {}; @@ -16,7 +16,7 @@ util.USER_AGENT = format( version, process.platform, process.arch, - process.version + process.version, ); /** @@ -45,8 +45,9 @@ util.formatAccess = function(access) { * @param {String} endpoint API endpoint * @return {String} API request URI */ -util.getUrl = function(id, endpoint) { - let url = `${config.api}/v${config.version}/vehicles`; +util.getUrl = function(id, endpoint, version = config.version) { + const origin = util.getConfig('SMARTCAR_API_ORIGIN') || config.api; + let url = `${origin}/v${version}/vehicles`; if (id) { url += `/${id}`; @@ -59,56 +60,55 @@ util.getUrl = function(id, endpoint) { return url; }; -util.request = request.defaults({ - json: true, - headers: { - 'User-Agent': util.USER_AGENT, - }, - timeout: config.timeout, -}); - util.wrap = function(promise) { - return promise.catch(StatusCodeError, util.catch); + return promise.catch(StatusCodeError, util.handleError); +}; + +util.getOrThrowConfig = function(configName) { + if (env[configName]) { + return env[configName]; + } + + throw new Error( + `${configName} not set or passed as arguments`, + ); }; -util.catch = function(caught) { - const options = caught.options; - const body = _.get(caught, 'response.body', {}); +util.getConfig = function(configName) { + return env[configName]; +}; + +util.getFlagsString = function(flags) { + return Object.entries(flags) + .map(([key, value]) => `${key}:${value}`).join(' '); +}; + +util.handleError = function(caught) { + const body = _.get(caught, 'response.body', ''); + const headers = _.get(caught, 'response.headers', {}); + + const contentType = String(headers['content-type']); + if (!contentType.toLowerCase().includes('application/json')) { + // body would be a string in this case + throw new SmartcarError(caught.statusCode, body, headers); + } - if (caught.response.request.uri.href.includes('/v2.0/')) { - throw new errors.SmartcarErrorV2(body); + if (typeof body === 'string') { + throw new SmartcarError( + caught.statusCode, + {message: body, type: 'SDK_ERROR'}, + headers, + ); } - switch (caught.statusCode) { - case 400: - throw new errors.ValidationError(body.error_description || body.message); - case 401: - throw new errors.AuthenticationError( - body.error_description || body.message - ); - case 403: - throw new errors.PermissionError(options.uri); - case 404: - throw new errors.ResourceNotFoundError(options.uri); - case 409: - throw new errors.VehicleStateError(body.message, body.code); - case 429: - throw new errors.RateLimitingError(); - case 430: - throw new errors.MonthlyLimitExceeded(); - case 500: - throw new errors.ServerError(); - case 501: - switch (body.error) { - case 'smartcar_not_capable_error': - throw new errors.SmartcarNotCapableError(body.message); - default: - throw new errors.VehicleNotCapableError(options.uri); - } - default: - const e = new errors.SmartcarError(caught.message); - e.original = caught; - throw e; + if (body.error || body.type) { + throw new SmartcarError(caught.statusCode, body, headers); + } else { + throw new SmartcarError( + caught.statusCode, + {body, type: 'SDK_ERROR'}, + headers, + ); } }; diff --git a/lib/vehicle.js b/lib/vehicle.js index d98e1a81..6275a6be 100644 --- a/lib/vehicle.js +++ b/lib/vehicle.js @@ -3,610 +3,615 @@ const util = require('./util'); const _ = require('lodash'); -/** @exports Vehicle */ - -/** - * @param {Object} response - * - * @return {Date|null} A parsed age or null if no age exists - */ -const parseAge = function(response) { - const age = _.get(response, 'headers.sc-data-age', null); - return age ? new Date(age) : null; +const SmartcarService = require('./smartcar-service'); +const config = require('./config'); + +/** + * @const {object} - Every key here is the function name on vehicle + * This map is used to generate the methods dynamically. Every value is an object of + * the following fields : + * - requestType: http request type, defaults to 'get' if not mentioned. + * - path: url path to hit, defaults to the method name + * - body: body for post requests. + */ +const METHODS_MAP = { + vin: {}, + charge: {}, + battery: {}, + batteryCapacity: {path: 'battery/capacity'}, + fuel: {}, + tirePressure: {path: 'tires/pressure'}, + engineOil: {path: 'engine/oil'}, + odometer: {}, + location: {}, + attributes: {path: '/'}, + permissions: {}, + lock: {requestType: 'post', path: 'security', body: {action: 'LOCK'}}, + unlock: {requestType: 'post', path: 'security', body: {action: 'UNLOCK'}}, + startCharge: {requestType: 'post', path: 'charge', body: {action: 'START'}}, + stopCharge: {requestType: 'post', path: 'charge', body: {action: 'STOP'}}, + disconnect: {requestType: 'delete', path: 'application'}, }; +/** @exports Vehicle */ /** * Initializes a new Vehicle to use for making requests to the Smartcar API. * * @constructor * @param {String} id - The vehicle's unique identifier. Retrieve a user's - * vehicle id using {@link module:smartcar.getVehicleIds}. + * vehicle id using {@link module:smartcar.getVehicles}. * @param {String} token - A valid access token - * @param {String} [unitSystem=metric] - The unit system to use for vehicle data - * , must be either `metric` or `imperial`. - */ -function Vehicle(id, token, unitSystem) { - if (!(this instanceof Vehicle)) { - // eslint-disable-next-line max-len - throw new TypeError( - "Class constructor Vehicle cannot be invoked without 'new'" - ); - } - + * @param {Object} [options] + * @param {String} [options.unitSystem=metric] - The unit system to use for vehicle data + * must be either `metric` or `imperial`. + * @param {Object} [options.version] - API version to use + */ +function Vehicle(id, token, options = {}) { this.id = id; this.token = token; - this.request = util.request.defaults({ - baseUrl: util.getUrl(this.id), + this.unitSystem = options.unitSystem || 'metric'; + this.version = options.version || config.version; + this.service = new SmartcarService({ + baseUrl: util.getUrl(this.id, '', this.version), auth: { bearer: this.token, }, + headers: { + 'sc-unit-system': this.unitSystem, + }, }); - this.setUnitSystem(unitSystem || 'metric'); } +/* NOTES : + - We only generate the methods where there is no parameter for calling the method thats + the majority. For all the ones that require parameters, write them separately. + Ex. permissions, subscribe, unsubscribe + - The following snippet generates methods dynamically , but if we are adding a new item, + make sure we also add the JSDOC for it. These are at the end of the file in a section. +*/ + +_.forEach(METHODS_MAP, (attributes, methodName) => { + Vehicle.prototype[methodName] = async function() { + const bodyObject = {}; + if (attributes.body) { + bodyObject.body = attributes.body; + } + const response = await this.service.request( + attributes.requestType || 'get', + attributes.path || methodName, + bodyObject, + ); + return response; + }; +}); + /** - * Update the unit system to use in requests to the Smartcar API. + * @type {Object} + * @typedef Permissions + * @property {String[]} permissions - An array of permissions names. + * @property {Object} [paging] + * @property {Number} [paging.count] - The total number of elements for the entire query + * (not just the given page). + * @property {Number} [options.offset] - The current start index of the returned list of elements. + * @property {Meta} meta * - * @param {String} unitSystem - The unit system to use, must be either `metric` - * or `imperial`. + * @example + * { + * permissions: ['read_vehicle_info'], + * paging: { + * count: 25, + * offset: 10 + * }, + * meta: { + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + * } + * } */ -Vehicle.prototype.setUnitSystem = function(unitSystem) { - if (['imperial', 'metric'].indexOf(unitSystem) < 0) { - throw new TypeError("unit system must be one of: 'imperial', 'metric'"); - } - - this.unitSystem = unitSystem; - this.request = this.request.defaults({ - headers: { - 'sc-unit-system': this.unitSystem, - }, - }); -}; /** - * Disconnect this vehicle from the connected application. - * - * Note: Calling this method will invalidate your token's access to the vehicle. - * You will have to reauthorize the user to your application again if you wish - * to make requests to it again. + * Fetch the list of permissions that this application has been granted * - * @return {Promise} A promise resolved on successful disconnect. + * @method + * @param {Object} [paging] + * @param {String} [paging.limit] - number of permissions to return + * @param {Object} [options.offset] - The current start index of the returned list of elements. + * @return {Permissions} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.disconnect = function() { - return util.wrap(this.request.delete('application')); +Vehicle.prototype.permissions = async function(paging = {}) { + const response = await this.service.request( + 'get', + 'permissions', + {}, + {qs: paging}, + ); + return response; }; /** - * Fetch the list of permissions that this application has been granted for - * this vehicle. + * @type {Object} + * @typedef WebhookSubscription + * @property {String} webhookId - Webhook Id that the vehicle was subscribed to + * @property {String} vehicleId - Current vehicle id that was subscribed to the webhook + * @property {Meta} meta + * + * @example + * { + * webhookId: 'dd214915-0c26-13c5-8e42-7edfc2ab320a', + * vehicleId: '19c0cc8c-80e0-4182-9372-6ef903c7599c', + * meta: { + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + * } + * } + */ +/** + * Subscribe the vehicle to given webhook Id * - * @return {Promise.} An array of permissions names. + * @method + * @param {String} webhookId - Webhook Id to subscribe to. + * @return {Object} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. - * @example - * ['read_vehicle_info', 'read_odometer', 'control_security'] */ -Vehicle.prototype.permissions = function() { - return util.wrap(this.request.get('permissions')).then(function(response) { - return response.permissions; - }); +Vehicle.prototype.subscribe = async function(webhookId) { + const response = await this.service.request('post', `webhooks/${webhookId}`); + return response; }; /** - * Checks if permissions granted to a vehicle contain the specified permission(s). - * - * @param {String[]|String} permissions Permission(s) to check + * Unsubscribe the vehicle from given webhook Id * - * @return {Promise.} Whether the vehicle has the specified permission(s) - */ -Vehicle.prototype.hasPermissions = function(permissions) { - return this.permissions().then(function(vehiclePermissions) { - if (_.isArray(permissions)) { - const strippedPermissions = _.map(permissions, (permission) => - permission.replace(/^required:/, '') - ); - - return _.difference(strippedPermissions, vehiclePermissions).length === 0; - } else { - permissions = permissions.replace(/^required:/, ''); - return vehiclePermissions.includes(permissions); - } - }); + * @method + * @param {String} amt - Application management token to be used as authorization + * @param {String} webhookId - Webhook Id to unsubscribe from. + * @return {Meta} + * @throws {SmartcarError} - an instance of SmartcarError. + * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) + * for all possible errors. + */ +Vehicle.prototype.unsubscribe = async function(amt, webhookId) { + const response = await this.service.request( + 'delete', + `webhooks/${webhookId}`, + {}, + {auth: {bearer: amt}}, + ); + return response; }; -/* VEHICLE API METHODS */ /** * @type {Object} - * @typedef Info - * @property {String} id - The vehicle's unique Smartcar identifier. - * @property {String} make - The brand of the vehicle. - * @property {String} model - The specific model of the vehicle. - * @property {Number} year - The model year of the vehicle. + * @typedef Batch + * @property { function(): Object} ENDPOINT - The response object for a given ENDPOINT where + * ENDPOINT is a Smartcar endpoint (i.e. /odometer, /fuel) or throws SmartcarError + * if the endpoint resulted in an error. * * @example * { - * id: '19c0cc8c-80e0-4182-9372-6ef903c7599c', - * make: 'TESLA', - * model: 'S', - * year: 2017, + * "odometer" : function() => returns odometer object or throws SmartcarError, + * "location" : function() => returns odometer location or throws SmartcarError, * } */ /** - * GET Vehicle.info + * Make batch requests for supported items + * @see {@link https://smartcar.com/docs/api#post-batch-request|Smartcar API Doc - Batch Request} + * @param {String[]} paths - A list of paths of endpoints to send requests to. + * @return {Batch} * - * @return {Promise.} A promise for info on the vehicle's info - * @throws {SmartcarError} - an instance of SmartcarError. + * @throws {SmartcarError} - on unsuccessful request. An instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.info = function() { - return util.wrap(this.request.get('/')); +Vehicle.prototype.batch = async function(paths) { + const response = await this.service.batchRequest(paths); + return response; }; +/* JSDOC for dynamically generated methods */ /** * @type {Object} - * @typedef Location - * @property {Object} data - The returned vehicle data. - * @property {Number} data.latitude - The vehicle latitude (in degrees). - * @property {Number} data.longitude - The vehicle longitude (in degrees). - * @property {Date} age - The timestamp of when the data was recorded. + * @typedef Meta + * @property {Date} dataAge - The timestamp of when the data was recorded; returned if applicable. + * @property {String} requestId - The smartcar request ID for debugging + * @property {String} unitSystem - Unit system used, metric or imperial; returned if applicable. * * @example * { - * data: { - * latitude: 37.400880, - * longitude: -122.057804, - * } - * age: new Date('2018-05-04T07:20:50.844Z'), + * requestId: 'b9593682-8515-4f36-8190-bb56cde4c38a', + * dataAge: new Date('2018-05-04T07:20:50.844Z'), + * unitSystem: 'imperial', * } */ /** - * GET Vehicle.location + * @type {Object} + * @typedef Vin + * @property {String} vin - VIN of the vehicle + * @property {Meta} meta * - * @return {Promise.} A promise for info on the vehicle's location. + * @example + * { + * vin: '12345678901234567', + * meta: { + * requestId: 'b9593682-8515-4f36-8190-bb56cde4c38a', + * } + * } + */ +/** + * @name Vehicle#vin + * @function + * @memberof Vehicle + * @description Returns the vehicle's manufacturer identifier (VIN). + * @see {@link https://smartcar.com/docs/api#get-vin|Smartcar API Doc - VIN} + * @return {Vin} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.location = function() { - const req = this.request.get('location', {resolveWithFullResponse: true}); - return util.wrap(req).then(function(response) { - return { - data: response.body, - age: parseAge(response), - }; - }); -}; + /** * @type {Object} - * @typedef Odometer - * @property {Object} data - The returned vehicle data. - * @property {Number} data.distance - The reading of the vehicle's odometer (in - * kms or miles). To set unit, see {@link Vehicle#setUnitSystem}. - * @property {Date} age - The timestamp of when the data was recorded. - * @property {String} unitSystem - The unit system of the returned odometer - * reading. `metric` signifies kilometers, `imperial` signifies miles. - * To set, see {@link Vehicle#setUnitSystem}. + * @typedef Charge + * @property {Boolean} isPluggedIn - Indicates whether charging cable is + * plugged in. + * @property {String} state - Indicates the current state of the charge + * system. Can be `FULLY_CHARGED`, `CHARGING`, or `NOT_CHARGING`. + * @property {Meta} meta * * @example * { - * data: { - * distance: 1234.12, + * isPluggedIn: false, + * state: "FULLY_CHARGED", + * meta: { + * dataAge: new Date('2018-05-04T07:20:50.844Z'), * } - * age: new Date('2018-05-04T07:20:50.844Z'), - * unitSystem: 'imperial', * } */ - /** - * GET Vehicle.odometer - * - * @return {Promise.} A promise for info on the vehicle's odometer. + * @name Vehicle#charge + * @function + * @memberof Vehicle + * @description Returns the current charge status of the vehicle. + * @see {@link https://smartcar.com/docs/api#get-ev-charging-status|Smartcar API Doc - EV charging status} + * @return {Charge} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.odometer = function() { - const req = this.request.get('odometer', {resolveWithFullResponse: true}); - return util.wrap(req).then(function(response) { - return { - data: response.body, - age: parseAge(response), - unitSystem: response.headers['sc-unit-system'], - }; - }); -}; /** * @type {Object} - * @typedef EngineOil - * @property {Object} data - The returned vehicle data. - * @property {Number} data.lifeRemaining - The engine oil's remaining life span - * (as a percentage). Oil life is based on the current quality of the oil. - * @property {Date} age - The timestamp of when the data was recorded. + * @typedef Battery + * @property {Number} range - The estimated remaining distance the car can + * travel (in kms or miles). Unit is passed as a parameter in vehicle constructor. + * @property {Number} percentRemaining - The remaining level of charge in + * the battery (in percent). + * @property {Meta} meta * * @example * { - * data: { - * lifeRemaining: 0.86, + * range: 40.5, + * percentRemaining: 0.3, + * meta: { + * dataAge: new Date('2018-05-04T07:20:50.844Z'), + * unitSystem: 'imperial', + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', * } - * age: new Date('2018-05-04T07:20:50.844Z') * } */ - /** - * GET Vehicle.oil - * - * @return {Promise.} A promise for info on the vehicle's engine oil. + * @name Vehicle#battery + * @function + * @memberof Vehicle + * @description Returns the state of charge (SOC) and remaining range of an electric or + * plug-in hybrid vehicle's battery. + * @see {@link https://smartcar.com/docs/api#get-ev-battery|Smartcar API Doc - EV battery level} + * @return {Battery} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.oil = function() { - const req = this.request.get('engine/oil', {resolveWithFullResponse: true}); - return util.wrap(req).then(function(response) { - return { - data: response.body, - age: parseAge(response), - }; - }); -}; /** * @type {Object} - * @typedef TirePressure - * @property {Object} data - The returned vehicle data. - * @property {Number} data.frontLeft - The current air pressure of the front left tire - * @property {Number} data.frontRight - The current air pressure of the back right tire - * @property {Number} data.backLeft - The current air pressure of the back left tire - * @property {Number} data.backRight - The current air pressure of the back right tire - * @property {Date} age - The timestamp of when the data was recorded. - * @property {String} unitSystem - The unit system of the returned odometer - * reading. `metric` signifies kilopascals (kpa), `imperial` signifies pounds per square inch (psi). - * To set, see {@link Vehicle#setUnitSystem}. + * @typedef BatteryCapacity + * @property {Number} capacity - The total capacity of the vehicle's battery + * (in kilowatt-hours) + * @property {Meta} meta + * * @example * { - * data: { - * frontleft: 33, - * frontRight: 34, - * backLeft: 34, - * backRight: 33 + * capacity: 24, + * meta: { + * dataAge: new Date('2018-05-04T07:20:50.844Z'), + * unitSystem: 'imperial', + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', * } - * age: new Date('2018-05-04T07:20:50.844Z'), - * unitSystem: 'imperial' * } */ - /** - * GET Vehicle.tirePressure - * - * @return {Promise.} A promise for info on the vehicle's tire pressure. + * @name Vehicle#batteryCapacity + * @function + * @memberof Vehicle + * @description Returns the capacity of an electric or plug-in hybrid vehicle's battery. + * @see {@link https://smartcar.com/docs/api#get-ev-battery-capacity|Smartcar API Doc - EV battery capacity} + * @return {BatteryCapacity} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.tirePressure = function() { - const req = this.request.get('tires/pressure', { - resolveWithFullResponse: true, - }); - return util.wrap(req).then(function(response) { - return { - data: { - tires: response.body, - }, - age: parseAge(response), - unitSystem: response.headers['sc-unit-system'], - }; - }); -}; /** * @type {Object} * @typedef Fuel - * @property {Object} data - The returned vehicle data. - * @property {Number} data.range - The estimated remaining distance the car can - * travel (in kms or miles). To set unit, see {@link Vehicle#setUnitSystem}. - * @property {Number} data.percentRemaining - The remaining level of fuel in + * @property {Number} range - The estimated remaining distance the car can + * travel (in kms or miles). Unit is passed as a parameter in vehicle constructor. + * @property {Number} percentRemaining - The remaining level of fuel in * the tank (in percent). - * @property {Number} data.amountRemaining - The amount of fuel in the tank (in - * liters or gallons (US)). To set unit, see {@link Vehicle#setUnitSystem}. - * @property {Date} age - The timestamp of when the data was recorded. - * @property {String} unitSystem - The unit system of the returned data. - * To set, see {@link Vehicle#setUnitSystem}. + * @property {Number} amountRemaining - The amount of fuel in the tank (in + * liters or gallons (US)). Unit is passed as a parameter in vehicle constructor. + * @property {Meta} meta * * @example * { - * data: { - * range: 40.5, - * percentRemaining: 0.3, - * amountRemaining: 40.5, + * range: 40.5, + * percentRemaining: 0.3, + * amountRemaining: 40.5, + * meta: { + * dataAge: new Date('2018-05-04T07:20:50.844Z'), + * unitSystem: 'imperial', + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', * } - * age: new Date('2018-05-04T07:20:50.844Z'), - * unitSystem: 'imperial', * } */ - /** - * GET Vehicle.fuel - * - * @return {Promise.} A promise for info on the vehicle's fuel status. + * @name Vehicle#fuel + * @function + * @memberof Vehicle + * @description Returns the status of the fuel remaining in the vehicle's gas tank. + * @see {@link https://smartcar.com/docs/api#get-fuel-tank|Smartcar API Doc - Fuel tank} + * @return {Fuel} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.fuel = function() { - const req = this.request.get('fuel', {resolveWithFullResponse: true}); - return util.wrap(req).then(function(response) { - return { - data: response.body, - age: parseAge(response), - unitSystem: response.headers['sc-unit-system'], - }; - }); -}; /** * @type {Object} - * @typedef Battery - * @property {Object} data - The returned vehicle data. - * @property {Number} data.range - The estimated remaining distance the car can - * travel (in kms or miles). To set unit, see {@link Vehicle#setUnitSystem}. - * @property {Number} data.percentRemaining - The remaining level of charge in - * the battery (in percent). - * @property {Date} age - The timestamp of when the data was recorded. - * @property {String} unitSystem - The unit system of the returned data. - * To set, see {@link Vehicle#setUnitSystem}. + * @typedef TirePressure + * @property {Number} frontLeft - The current air pressure of the front left tire + * @property {Number} frontRight - The current air pressure of the back right tire + * @property {Number} backLeft - The current air pressure of the back left tire + * @property {Number} backRight - The current air pressure of the back right tire + * @property {Meta} meta * * @example * { - * data: { - * range: 40.5, - * percentRemaining: 0.3, + * frontleft: 33, + * frontRight: 34, + * backLeft: 34, + * backRight: 33 + * meta: { + * dataAge: new Date('2018-05-04T07:20:50.844Z'), + * unitSystem: 'imperial', + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', * } - * age: new Date('2018-05-04T07:20:50.844Z'), - * unitSystem: 'imperial', * } */ - /** - * GET Vehicle.battery - * - * @return {Promise.} A promise for info on the vehicle's battery status. + * @name Vehicle#tirePressure + * @function + * @memberof Vehicle + * @description Returns the air pressure of each of the vehicle's tires. + * @see {@link https://smartcar.com/docs/api#get-tire-pressure|Smartcar API Doc - Tire pressure} + * @return {TirePressure} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.battery = function() { - const req = this.request.get('battery', {resolveWithFullResponse: true}); - return util.wrap(req).then(function(response) { - return { - data: response.body, - age: parseAge(response), - unitSystem: response.headers['sc-unit-system'], - }; - }); -}; /** * @type {Object} - * @typedef BatteryCapacity - * @property {Object} data - The returned vehicle data. - * @property {Number} data.capacity - The total capacity of the - * vehicle's battery (in kilowatt-hours) - * @property {Date} age - The timestamp of when the data was recorded. - * @property {String} unitSystem - The unit system of the returned data. - * To set, see {@link Vehicle#setUnitSystem}. + * @typedef EngineOil + * @property {Number} lifeRemaining - The engine oil's remaining life span + * (as a percentage). Oil life is based on the current quality of the oil. + * @property {Meta} meta * * @example * { - * data: { - * capacity: 24, + * lifeRemaining: 0.86, + * meta: { + * dataAge: new Date('2018-05-04T07:20:50.844Z'), + * unitSystem: 'imperial', + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', * } - * age: new Date('2018-05-04T07:20:50.844Z'), - * unitSystem: 'metric', * } */ - /** - * GET Vehicle.batteryCapacity - * - * @return {Promise.} A promise for info on the vehicle's battery capacity. + * @name Vehicle#engineOil + * @function + * @memberof Vehicle + * @description Returns the remaining life span of a vehicle's engine oil + * @see {@link https://smartcar.com/docs/api#get-engine-oil-life|Smartcar API Doc - Engine oil life} + * @return {EngineOil} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.batteryCapacity = function() { - const req = this.request.get('battery/capacity', {resolveWithFullResponse: true}); - return util.wrap(req).then(function(response) { - return { - data: response.body, - age: parseAge(response), - unitSystem: response.headers['sc-unit-system'], - }; - }); -}; /** * @type {Object} - * @typedef Charge - * @property {Object} data - The returned vehicle data. - * @property {Number} data.isPluggedIn - Indicates whether charging cable is - * plugged in. - * @property {Number} data.state - Indicates the current state of the charge - * system. Can be `FULLY_CHARGED`, `CHARGING`, or `NOT_CHARGING`. - * @property {Date} age - The timestamp of when the data was recorded. + * @typedef Odometer + * @property {Number} distance - The reading of the vehicle's odometer (in + * kms or miles). Unit is passed as a parameter in vehicle constructor. + * @property {Meta} meta * * @example * { - * data: { - * isPluggedIn: false, - * state: "FULLY_CHARGED", + * distance: 1234.12, + * meta: { + * dataAge: new Date('2018-05-04T07:20:50.844Z'), + * unitSystem: 'imperial', + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', * } - * age: new Date('2018-05-04T07:20:50.844Z'), * } */ +/** + * @name Vehicle#odometer + * @function + * @memberof Vehicle + * @description Returns the vehicle's last known odometer reading. + * @see {@link https://smartcar.com/docs/api#get-odometer|Smartcar API Doc - Odometer} + * @return {Odometer} + * @throws {SmartcarError} - an instance of SmartcarError. + * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) + * for all possible errors. + */ /** - * GET Vehicle.charge + * @type {Object} + * @typedef Location + * @property {Number} latitude - The vehicle latitude (in degrees). + * @property {Number} longitude - The vehicle longitude (in degrees). + * @property {Meta} meta * - * @return {Promise.} A promise for info on the vehicle's charge status. + * @example + * { + * latitude: 37.400880, + * longitude: -122.057804, + * meta: { + * dataAge: new Date('2018-05-04T07:20:50.844Z'), + * unitSystem: 'imperial', + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + * } + * } + */ +/** + * @name Vehicle#location + * @function + * @memberof Vehicle + * @description Returns the last known location of the vehicle in geographic coordinates. + * @see {@link https://smartcar.com/docs/api#get-location|Smartcar API Doc - Location} + * @return {Location} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.charge = function() { - const req = this.request.get('charge', {resolveWithFullResponse: true}); - return util.wrap(req).then(function(response) { - return { - data: response.body, - age: parseAge(response), - }; - }); -}; /** - * GET Vehicle.vin + * @type {Object} + * @typedef Attributes + * @property {String} id - The vehicle's unique Smartcar identifier. + * @property {String} make - The brand of the vehicle. + * @property {String} model - The specific model of the vehicle. + * @property {Number} year - The model year of the vehicle. + * @property {Meta} meta * - * @return {Promise.} A promise for info on the vehicle's vin. + * @example + * { + * id: '19c0cc8c-80e0-4182-9372-6ef903c7599c', + * make: 'TESLA', + * model: 'S', + * year: 2017, + * meta: { + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + * } + * } + */ +/** + * @name Vehicle#attributes + * @function + * @memberof Vehicle + * @description Returns make model year and id of the vehicle + * @see {@link https://smartcar.com/docs/api#get-vehicle-attributes|Smartcar API Doc - Vehicle attributes} + * @return {Attributes} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.vin = function() { - return util.wrap(this.request.get('vin')).then(function(response) { - return response.vin; - }); -}; /** * @type {Object} - * @typedef ActionSuccess + * @typedef ActionResponse * @property {String} status - set to `success` on successful request + * @property {Meta} meta * * @example * { * status: 'success', + * meta: { + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + * } * } */ /** - * POST Vehicle.lock - * - * @return {Promise.} response on successful request - * @throws {SmartcarError} - on unsuccessful request. An instance of SmartcarError. + * @name Vehicle#lock + * @function + * @memberof Vehicle + * @description Attempts to lock the vehicle. + * @see {@link https://smartcar.com/docs/api#post-lockunlock|Smartcar API Doc - Lock} + * @return {ActionResponse} + * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.lock = function() { - const req = this.request.post('security', {body: {action: 'LOCK'}}); - return util.wrap(req).then(({status}) => ({status})); -}; /** - * POST Vehicle.unlock - * - * @return {Promise.} response on successful request - * @throws {SmartcarError} - on unsuccessful request. An instance of SmartcarError. + * @name Vehicle#unlock + * @function + * @memberof Vehicle + * @description Attempts to lock the vehicle. + * @see {@link https://smartcar.com/docs/api#post-lockunlock|Smartcar API Doc - Unlock} + * @return {ActionResponse} + * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.unlock = function() { - const req = this.request.post('security', {body: {action: 'UNLOCK'}}); - return util.wrap(req).then(({status}) => ({status})); -}; /** - * POST Vehicle.startCharge - * - * @return {Promise.} response on successful request - * @throws {SmartcarError} - on unsuccessful request. An instance of SmartcarError. + * @name Vehicle#startCharge + * @function + * @memberof Vehicle + * @description Attempts to start charging the vehicle. + * @see {@link https://smartcar.com/docs/api#post-ev-startstop-charge|Smartcar API Doc - EV start charge} + * @return {ActionResponse} + * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.startCharge = function() { - const req = this.request.post('charge', {body: {action: 'START'}}); - return util.wrap(req).then(({status}) => ({status})); -}; /** - * POST Vehicle.stopCharge - * - * @return {Promise.} response on successful request - * @throws {SmartcarError} - on unsuccessful request. An instance of SmartcarError. + * @name Vehicle#stopCharge + * @function + * @memberof Vehicle + * @description Attempts to stop charging the vehicle. + * @see {@link https://smartcar.com/docs/api#post-ev-startstop-charge|Smartcar API Doc - EV stop charge} + * @return {ActionResponse} + * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.stopCharge = function() { - const req = this.request.post('charge', {body: {action: 'STOP'}}); - return util.wrap(req).then(({status}) => ({status})); -}; - -/** - * @type {Object} - * @typedef Batch - * @property {Object} responses - The object containing multiple HTTP responses. - * @property {Object} data.ENDPOINT - The HTTP response for a given endpoint. - * ENDPOINT is a Smartcar endpoint (i.e. /odometer, /fuel). - * @property {Number} data.ENDPOINT.code - The HTTP status code for this response. - * @property {Object} data.ENDPOINT.headers - The HTTP headers for this response. - * @property {Object} data.ENDPOINT.body - The body for this response. - * - * @example - * { - * "/odometer" : { - * "body": { - * "distance": 37829 - * }, - * "code": 200, - * "headers": { - * "sc-data-age": "2019-10-24T00:43:46.000Z", - * "sc-unit-system": "metric" - * } - * }, - * "/location" : { - * "body": { - * "latitude": 37.4292, - * "longitude": 122.1381 - * }, - * "code": 200, - * "headers": { - * "sc-data-age": "2019-10-24T00:43:46.000Z" - * } - * } - * } - */ /** - * POST Vehicle.batch - * - * @param {String[]} paths - A list of paths of endpoints to send requests to. - * @return {Promise} response on successful request - * - * @throws {SmartcarError} - on unsuccessful request. An instance of SmartcarError. + * @name Vehicle#disconnect + * @function + * @memberof Vehicle + * @description Disconnect this vehicle from the connected application. + * Note: Calling this method will invalidate your token's access to the vehicle. + * You will have to reauthorize the user to your application again if you wish + * to make requests to it again. + * @see {@link https://smartcar.com/docs/api#delete-disconnect|Smartcar API Doc - Disconnect} + * @return {ActionResponse} + * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. */ -Vehicle.prototype.batch = function(paths) { - const requests = paths.map((path) => ({path})); - const req = this.request.post('batch', {body: {requests}}); - - return util.wrap(req).then(({responses}) => { - return _.transform( - responses, - (result, item) => { - result[item.path] = _.pick(item, ['body', 'code', 'headers']); - }, - {} - ); - }); -}; module.exports = Vehicle; diff --git a/package-lock.json b/package-lock.json index 5e2ca56e..cd0b9f09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,286 +47,307 @@ } }, "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", "dev": true, "requires": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.14.5" } }, + "@babel/compat-data": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz", + "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==", + "dev": true + }, "@babel/core": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.1.tgz", - "integrity": "sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.11.0", - "@babel/helper-module-transforms": "^7.11.0", - "@babel/helpers": "^7.10.4", - "@babel/parser": "^7.11.1", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.11.0", - "@babel/types": "^7.11.0", + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.6.tgz", + "integrity": "sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.5", + "@babel/helper-compilation-targets": "^7.14.5", + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helpers": "^7.14.6", + "@babel/parser": "^7.14.6", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", + "gensync": "^1.0.0-beta.2", "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", + "semver": "^6.3.0", "source-map": "^0.5.0" } }, "@babel/generator": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz", - "integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz", + "integrity": "sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==", "dev": true, "requires": { - "@babel/types": "^7.11.0", + "@babel/types": "^7.14.5", "jsesc": "^2.5.1", "source-map": "^0.5.0" } }, "@babel/helper-annotate-as-pure": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", - "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz", + "integrity": "sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.14.5" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", - "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz", + "integrity": "sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz", + "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/compat-data": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", + "semver": "^6.3.0" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz", - "integrity": "sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", + "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-regex": "^7.10.4", - "regexpu-core": "^4.7.0" + "@babel/helper-annotate-as-pure": "^7.14.5", + "regexpu-core": "^4.7.1" } }, "@babel/helper-explode-assignable-expression": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz", - "integrity": "sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz", + "integrity": "sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ==", "dev": true, "requires": { - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/types": "^7.14.5" } }, "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", - "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", + "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-get-function-arity": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", - "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", + "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", + "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.14.5" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz", - "integrity": "sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz", + "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==", "dev": true, "requires": { - "@babel/types": "^7.11.0" + "@babel/types": "^7.14.5" } }, "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", - "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", + "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.14.5" } }, "@babel/helper-module-transforms": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", - "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.5.tgz", + "integrity": "sha512-iXpX4KW8LVODuAieD7MzhNjmM6dzYY5tfRqT+R9HDXWl0jPn/djKmA+G9s/2C2T9zggw5tK1QNqZ70USfedOwA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/template": "^7.10.4", - "@babel/types": "^7.11.0", - "lodash": "^4.17.19" + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-simple-access": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", + "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.14.5" } }, "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", "dev": true }, - "@babel/helper-regex": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", - "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", - "dev": true, - "requires": { - "lodash": "^4.17.19" - } - }, "@babel/helper-remap-async-to-generator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz", - "integrity": "sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz", + "integrity": "sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-wrap-function": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-wrap-function": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/helper-replace-supers": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", - "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz", + "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-member-expression-to-functions": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/helper-simple-access": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", - "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz", + "integrity": "sha512-nfBN9xvmCt6nrMZjfhkl7i0oTV3yxR4/FztsbOASyTvVcoYd0TRHh7eMLdlEcCqobydC0LAF3LtC92Iwxo0wyw==", "dev": true, "requires": { - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/types": "^7.14.5" } }, "@babel/helper-split-export-declaration": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", - "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", + "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", "dev": true, "requires": { - "@babel/types": "^7.11.0" + "@babel/types": "^7.14.5" } }, "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", "dev": true }, "@babel/helper-wrap-function": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz", - "integrity": "sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz", + "integrity": "sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-function-name": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/helpers": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", - "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.6.tgz", + "integrity": "sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==", "dev": true, "requires": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.11.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.2.tgz", - "integrity": "sha512-Vuj/+7vLo6l1Vi7uuO+1ngCDNeVmNbTngcJFKCR/oEtz8tKz0CJxZEGmPt9KcIloZhOZ3Zit6xbpXT2MDlS9Vw==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz", + "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==", "dev": true }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz", - "integrity": "sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz", + "integrity": "sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.10.4", - "@babel/plugin-syntax-async-generators": "^7.8.0" + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.14.5", + "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz", - "integrity": "sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz", + "integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.10.4" + "@babel/compat-data": "^7.14.7", + "@babel/helper-compilation-targets": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.14.5" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz", - "integrity": "sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", + "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-syntax-async-generators": { @@ -357,94 +378,92 @@ } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz", - "integrity": "sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", + "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.10.4" + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.14.5" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz", - "integrity": "sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz", + "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz", - "integrity": "sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", + "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz", - "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.5.tgz", + "integrity": "sha512-en8GfBtgnydoao2PS+87mKyw62k02k7kJ9ltbKe0fXTHrQmG6QZZflYuGI1VVG7sVpx4E1n7KBpNlPb8m78J+A==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-simple-access": "^7.14.5", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-parameters": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz", - "integrity": "sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz", + "integrity": "sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", - "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", + "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/traverse": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz", - "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.11.0", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.11.0", - "@babel/types": "^7.11.0", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.7.tgz", + "integrity": "sha512-9vDr5NzHu27wgwejuKL7kIOm4bwEtaPQ4Z6cpCmjSuaRqpH/7xc4qcGEscwMqlkwgcXl6MvqoAjZkQ24uSdIZQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/parser": "^7.14.7", + "@babel/types": "^7.14.5", "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", - "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", + "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", + "@babel/helper-validator-identifier": "^7.14.5", "to-fast-properties": "^2.0.0" } }, @@ -458,61 +477,62 @@ } }, "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.3", + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", + "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.3", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "@octokit/auth-token": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.3.tgz", - "integrity": "sha512-fdGoOQ3kQJh+hrilc0Plg50xSfaCKOeYN9t6dpJKXN9BxhhfquL0OzoQXg3spLYymL5rm29uPeI3KEXRaZQ9zg==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz", + "integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==", "dev": true, "requires": { - "@octokit/types": "^5.0.0" + "@octokit/types": "^6.0.3" } }, "@octokit/core": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.2.1.tgz", - "integrity": "sha512-XfFSDDwv6tclUenS0EmB6iA7u+4aOHBT1Lz4PtQNQQg3hBbNaR/+Uv5URU+egeIuuGAiMRiDyY92G4GBOWOqDA==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz", + "integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==", "dev": true, "requires": { - "@octokit/auth-token": "^2.4.0", - "@octokit/graphql": "^4.3.1", - "@octokit/request": "^5.4.0", - "@octokit/types": "^5.0.0", - "before-after-hook": "^2.1.0", + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.6.0", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" } }, "@octokit/endpoint": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.9.tgz", - "integrity": "sha512-3VPLbcCuqji4IFTclNUtGdp9v7g+nspWdiCUbK3+iPMjJCZ6LEhn1ts626bWLOn0GiDb6j+uqGvPpqLnY7pBgw==", + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", + "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", "dev": true, "requires": { - "@octokit/types": "^5.0.0", + "@octokit/types": "^6.0.3", "is-plain-object": "^5.0.0", "universal-user-agent": "^6.0.0" }, @@ -526,54 +546,58 @@ } }, "@octokit/graphql": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.5.7.tgz", - "integrity": "sha512-Gk0AR+DcwIK/lK/GX+OQ99UqtenQhcbrhHHfOYlrCQe17ADnX3EKAOKRsAZ9qZvpi5MuwWm/Nm+9aO2kTDSdyA==", + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.4.tgz", + "integrity": "sha512-SWTdXsVheRmlotWNjKzPOb6Js6tjSqA2a8z9+glDJng0Aqjzti8MEWOtuT8ZSu6wHnci7LZNuarE87+WJBG4vg==", "dev": true, "requires": { - "@octokit/request": "^5.3.0", - "@octokit/types": "^5.0.0", + "@octokit/request": "^5.6.0", + "@octokit/types": "^6.0.3", "universal-user-agent": "^6.0.0" } }, + "@octokit/openapi-types": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.3.3.tgz", + "integrity": "sha512-/tpvcWCjYUHtvdc/t/bX6pxaOoeYPhfPCyvUaSWP29YkRcdZmlhRaMsXudZhvXm8GBPBxmCOsf1Ye/FpkszOHw==", + "dev": true + }, "@octokit/plugin-paginate-rest": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.6.0.tgz", - "integrity": "sha512-o+O8c1PqsC5++BHXfMZabRRsBIVb34tXPWyQLyp2IXq5MmkxdipS7TXM4Y9ldL1PzY9CTrCsn/lzFFJGM3oRRA==", + "version": "2.13.5", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.5.tgz", + "integrity": "sha512-3WSAKBLa1RaR/7GG+LQR/tAZ9fp9H9waE9aPXallidyci9oZsfgsLn5M836d3LuDC6Fcym+2idRTBpssHZePVg==", "dev": true, "requires": { - "@octokit/types": "^5.5.0" + "@octokit/types": "^6.13.0" } }, "@octokit/plugin-request-log": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.2.tgz", - "integrity": "sha512-oTJSNAmBqyDR41uSMunLQKMX0jmEXbwD1fpz8FG27lScV3RhtGfBa1/BBLym+PxcC16IBlF7KH9vP1BUYxA+Eg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", "dev": true }, "@octokit/plugin-rest-endpoint-methods": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.2.1.tgz", - "integrity": "sha512-QyFr4Bv807Pt1DXZOC5a7L5aFdrwz71UHTYoHVajYV5hsqffWm8FUl9+O7nxRu5PDMtB/IKrhFqTmdBTK5cx+A==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.3.2.tgz", + "integrity": "sha512-vwsdLUC4TUohbHAqD0f/BjUw/kfKmNs1f0+Fkldzr7GKqMXjNku5U0jzZCmVUI6GcH7b/KcXd9WtbpVpofDehQ==", "dev": true, "requires": { - "@octokit/types": "^5.5.0", + "@octokit/types": "^6.16.5", "deprecation": "^2.3.1" } }, "@octokit/request": { - "version": "5.4.10", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.10.tgz", - "integrity": "sha512-egA49HkqEORVGDZGav1mh+VD+7uLgOxtn5oODj6guJk0HCy+YBSYapFkSLFgeYj3Fr18ZULKGURkjyhkAChylw==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.0.tgz", + "integrity": "sha512-4cPp/N+NqmaGQwbh3vUsYqokQIzt7VjsgTYVXiwpUP2pxd5YiZB2XuTedbb0SPtv9XS7nzAKjAuQxmY8/aZkiA==", "dev": true, "requires": { "@octokit/endpoint": "^6.0.1", - "@octokit/request-error": "^2.0.0", - "@octokit/types": "^5.0.0", - "deprecation": "^2.0.0", + "@octokit/request-error": "^2.1.0", + "@octokit/types": "^6.16.1", "is-plain-object": "^5.0.0", "node-fetch": "^2.6.1", - "once": "^1.4.0", "universal-user-agent": "^6.0.0" }, "dependencies": { @@ -586,35 +610,35 @@ } }, "@octokit/request-error": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.3.tgz", - "integrity": "sha512-GgD5z8Btm301i2zfvJLk/mkhvGCdjQ7wT8xF9ov5noQY8WbKZDH9cOBqXzoeKd1mLr1xH2FwbtGso135zGBgTA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", + "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", "dev": true, "requires": { - "@octokit/types": "^5.0.1", + "@octokit/types": "^6.0.3", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "@octokit/rest": { - "version": "18.0.9", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.0.9.tgz", - "integrity": "sha512-CC5+cIx974Ygx9lQNfUn7/oXDQ9kqGiKUC6j1A9bAVZZ7aoTF8K6yxu0pQhQrLBwSl92J6Z3iVDhGhGFgISCZg==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.6.1.tgz", + "integrity": "sha512-4NUr0sr8ZohvYoDVDT/P7lmamzeGrFjdfVxIuxW9Nz3xMp//MBmIKYxHhzMuMWGa8MHs69VT2HKsNYRJMCYyWA==", "dev": true, "requires": { - "@octokit/core": "^3.0.0", - "@octokit/plugin-paginate-rest": "^2.2.0", - "@octokit/plugin-request-log": "^1.0.0", - "@octokit/plugin-rest-endpoint-methods": "4.2.1" + "@octokit/core": "^3.5.0", + "@octokit/plugin-paginate-rest": "^2.6.2", + "@octokit/plugin-request-log": "^1.0.2", + "@octokit/plugin-rest-endpoint-methods": "5.3.2" } }, "@octokit/types": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz", - "integrity": "sha512-UZ1pErDue6bZNjYOotCNveTXArOMZQFG6hKJfOnGnulVCMcVVi7YIIuuR4WfBhjo7zgpmzn/BkPDnUXtNx+PcQ==", + "version": "6.16.5", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.16.5.tgz", + "integrity": "sha512-2v30UzgezzVZNCZlEryr8ujqaFW0EEH0fyuNxz5QdE3rlkCG2SXz8RTCT1V4q7inEI2kd2xTcROlq9OkEvY0TQ==", "dev": true, "requires": { - "@types/node": ">= 8" + "@octokit/openapi-types": "^7.3.3" } }, "@semantic-release/commit-analyzer": { @@ -657,13 +681,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "to-regex-range": { @@ -684,9 +708,9 @@ "dev": true }, "@semantic-release/github": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-7.2.0.tgz", - "integrity": "sha512-tMRnWiiWb43whRHvbDGXq4DGEbKRi56glDpXDJZit4PIiwDPX7Kx3QzmwRtDOcG+8lcpGjpdPabYZ9NBxoI2mw==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-7.2.3.tgz", + "integrity": "sha512-lWjIVDLal+EQBzy697ayUNN8MoBpp+jYIyW2luOdqn5XBH4d9bQGfTnjuLyzARZBHejqh932HVjiH/j4+R7VHw==", "dev": true, "requires": { "@octokit/rest": "^18.0.0", @@ -695,7 +719,7 @@ "bottleneck": "^2.18.1", "debug": "^4.0.0", "dir-glob": "^3.0.0", - "fs-extra": "^9.0.0", + "fs-extra": "^10.0.0", "globby": "^11.0.0", "http-proxy-agent": "^4.0.0", "https-proxy-agent": "^5.0.0", @@ -732,9 +756,9 @@ } }, "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", "dev": true, "requires": { "array-union": "^2.1.0", @@ -776,19 +800,19 @@ } }, "@semantic-release/npm": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-7.0.8.tgz", - "integrity": "sha512-8c1TLwKB/xT5E1FNs5l4GFtaNTznHesJk7tw3pGSlVxRqDXa1EZI+DfziZlO58Wk3PpS2ecu661kvBdz9aMgYQ==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-7.1.3.tgz", + "integrity": "sha512-x52kQ/jR09WjuWdaTEHgQCvZYMOTx68WnS+TZ4fya5ZAJw4oRtJETtrvUw10FdfM28d/keInQdc66R1Gw5+OEQ==", "dev": true, "requires": { "@semantic-release/error": "^2.2.0", "aggregate-error": "^3.0.0", - "execa": "^4.0.0", - "fs-extra": "^9.0.0", + "execa": "^5.0.0", + "fs-extra": "^10.0.0", "lodash": "^4.17.15", "nerf-dart": "^1.0.0", - "normalize-url": "^5.0.0", - "npm": "^6.14.8", + "normalize-url": "^6.0.0", + "npm": "^7.0.0", "rc": "^1.2.8", "read-pkg": "^5.0.0", "registry-auth-token": "^4.0.0", @@ -808,30 +832,27 @@ } }, "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true }, "is-stream": { "version": "2.0.0", @@ -839,6 +860,15 @@ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -864,9 +894,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -903,10 +933,13 @@ } }, "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "shebang-command": { "version": "2.0.0", @@ -937,13 +970,19 @@ "requires": { "isexe": "^2.0.0" } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } }, "@semantic-release/release-notes-generator": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-9.0.1.tgz", - "integrity": "sha512-bOoTiH6SiiR0x2uywSNR7uZcRDl22IpZhj+Q5Bn0v+98MFtOMhCxFhbrKQjhbYoZw7vps1mvMRmFkp/g6R9cvQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-9.0.3.tgz", + "integrity": "sha512-hMZyddr0u99OvM2SxVOIelHzly+PP3sYtJ8XOLHdMp8mrluN5/lpeTnIO27oeCYdupY/ndoGfvrqDjHqkSyhVg==", "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", @@ -951,9 +990,9 @@ "conventional-commits-filter": "^2.0.0", "conventional-commits-parser": "^3.0.0", "debug": "^4.0.0", - "get-stream": "^5.0.0", + "get-stream": "^6.0.0", "import-from": "^3.0.0", - "into-stream": "^5.0.0", + "into-stream": "^6.0.0", "lodash": "^4.17.4", "read-pkg-up": "^7.0.0" }, @@ -969,13 +1008,10 @@ } }, "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true }, "locate-path": { "version": "5.0.0", @@ -996,9 +1032,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -1069,9 +1105,9 @@ } }, "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", "dev": true }, "@types/minimist": { @@ -1081,9 +1117,9 @@ "dev": true }, "@types/node": { - "version": "14.0.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz", - "integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==", + "version": "15.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.4.tgz", + "integrity": "sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA==", "dev": true }, "@types/normalize-package-data": { @@ -1115,15 +1151,15 @@ } }, "acorn": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", - "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", "dev": true }, "acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", "dev": true }, "adm-zip": { @@ -1160,9 +1196,9 @@ } }, "ajv": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", - "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1396,12 +1432,6 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -1503,9 +1533,9 @@ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", - "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==" + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "babel-plugin-dynamic-import-node": { "version": "2.3.3", @@ -1538,9 +1568,9 @@ "dev": true }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "base": { @@ -1607,9 +1637,9 @@ } }, "before-after-hook": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", - "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", + "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", "dev": true }, "binary-extensions": { @@ -1693,6 +1723,19 @@ } } }, + "browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + } + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -1739,6 +1782,16 @@ "write-file-atomic": "^2.4.2" } }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "call-matcher": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/call-matcher/-/call-matcher-1.1.0.tgz", @@ -1780,6 +1833,12 @@ "quick-lru": "^1.0.0" } }, + "caniuse-lite": { + "version": "1.0.30001239", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001239.tgz", + "integrity": "sha512-cyBkXJDMeI4wthy8xJ2FvDU6+0dtcZSJW3voUF8+e9f1bBeuvyZfc3PNbkOETyhbR+dGCPzn9E7MA3iwzusOhQ==", + "dev": true + }, "capture-stack-trace": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", @@ -1811,16 +1870,16 @@ } }, "chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", "dev": true, "requires": { "assertion-error": "^1.1.0", "check-error": "^1.0.2", "deep-eql": "^3.0.1", "get-func-name": "^2.0.0", - "pathval": "^1.1.0", + "pathval": "^1.1.1", "type-detect": "^4.0.5" } }, @@ -1953,15 +2012,15 @@ } }, "cli-spinners": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.4.0.tgz", - "integrity": "sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz", + "integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==", "dev": true }, "cli-table": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", - "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.6.tgz", + "integrity": "sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==", "dev": true, "requires": { "colors": "1.0.3" @@ -2023,9 +2082,9 @@ } }, "collect-all": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-1.0.3.tgz", - "integrity": "sha512-0y0rBgoX8IzIjBAUnO73SEtSb4Mhk3IoceWJq5zZSxb9mWORhWH8xLYo4EDSOE1jRBk1LhmfjqWFFt10h/+MEA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-1.0.4.tgz", + "integrity": "sha512-RKZhRwJtJEP5FWul+gkSMEnaK6H3AGPTTWOiRimCcs+rc/OmQE3Yhy1Q7A7KsdkG3ZXVdZq68Y6ONSdvkeEcKA==", "dev": true, "requires": { "stream-connect": "^1.0.2", @@ -2057,6 +2116,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, "colors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", @@ -2196,6 +2261,14 @@ "md5-hex": "^2.0.0", "semver": "^5.5.1", "well-known-symbols": "^2.0.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "config-master": { @@ -2216,12 +2289,12 @@ } }, "configstore": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.5.tgz", + "integrity": "sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==", "dev": true, "requires": { - "dot-prop": "^4.1.0", + "dot-prop": "^4.2.1", "graceful-fs": "^4.1.2", "make-dir": "^1.0.0", "unique-string": "^1.0.0", @@ -2257,9 +2330,9 @@ } }, "conventional-changelog-writer": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.18.tgz", - "integrity": "sha512-mAQDCKyB9HsE8Ko5cCM1Jn1AWxXPYV0v8dFPabZRkvsiWUul2YyAqbIaoMKF88Zf2ffnOPSvKhboLf3fnjo5/A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.1.0.tgz", + "integrity": "sha512-WwKcUp7WyXYGQmkLsX4QmU42AZ1lqlvRW9mqoyiQzdD+rJWbTepdWoKJuwXTS+yq79XKnQNa93/roViPQrAQgw==", "dev": true, "requires": { "compare-func": "^2.0.0", @@ -2302,9 +2375,9 @@ } }, "hosted-git-info": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.7.tgz", - "integrity": "sha512-fWqc0IcuXs+BmE9orLDyVykAG9GJtGLGuZAAqgcckPgv5xad4AcXGIv8galtQvlwutxSlaMcdw7BUtq2EIvqCQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -2335,15 +2408,15 @@ } }, "map-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", - "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", + "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", "dev": true }, "meow": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.0.0.tgz", - "integrity": "sha512-nbsTRz2fwniJBFgUkcdISq8y/q9n9VbiHYbfwklFh5V4V2uAcxtKQkDc0yCLPM/kP0d+inZBewn3zJqewHE7kg==", + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", "dev": true, "requires": { "@types/minimist": "^1.2.0", @@ -2371,22 +2444,25 @@ } }, "normalize-package-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.0.tgz", - "integrity": "sha512-6lUjEI0d3v6kFrtgA/lOx4zHCWULXsFNIjHolnZCKCTLA6m/G625cdn3O7eNmT0iD3jfo6HZ9cdImGZwf21prw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", + "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", "dev": true, "requires": { - "hosted-git-info": "^3.0.6", - "resolve": "^1.17.0", - "semver": "^7.3.2", + "hosted-git-info": "^4.0.1", + "resolve": "^1.20.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" }, "dependencies": { "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, @@ -2400,9 +2476,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -2436,9 +2512,9 @@ }, "dependencies": { "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "normalize-package-data": { @@ -2496,12 +2572,6 @@ "strip-indent": "^3.0.0" } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, "strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -2512,9 +2582,9 @@ } }, "trim-newlines": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", - "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, "type-fest": { @@ -2530,9 +2600,9 @@ "dev": true }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true } } @@ -2548,16 +2618,16 @@ } }, "conventional-commits-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.0.tgz", - "integrity": "sha512-XmJiXPxsF0JhAKyfA2Nn+rZwYKJ60nanlbSWwwkGwLQFbugsc0gv1rzc7VbbUWAzJfR1qR87/pNgv9NgmxtBMQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz", + "integrity": "sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA==", "dev": true, "requires": { "JSONStream": "^1.0.4", "is-text-path": "^1.0.1", "lodash": "^4.17.15", "meow": "^8.0.0", - "split2": "^2.0.0", + "split2": "^3.0.0", "through2": "^4.0.0", "trim-off-newlines": "^1.0.0" }, @@ -2590,9 +2660,9 @@ } }, "hosted-git-info": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.7.tgz", - "integrity": "sha512-fWqc0IcuXs+BmE9orLDyVykAG9GJtGLGuZAAqgcckPgv5xad4AcXGIv8galtQvlwutxSlaMcdw7BUtq2EIvqCQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -2623,15 +2693,15 @@ } }, "map-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", - "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", + "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", "dev": true }, "meow": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.0.0.tgz", - "integrity": "sha512-nbsTRz2fwniJBFgUkcdISq8y/q9n9VbiHYbfwklFh5V4V2uAcxtKQkDc0yCLPM/kP0d+inZBewn3zJqewHE7kg==", + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", "dev": true, "requires": { "@types/minimist": "^1.2.0", @@ -2659,14 +2729,14 @@ } }, "normalize-package-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.0.tgz", - "integrity": "sha512-6lUjEI0d3v6kFrtgA/lOx4zHCWULXsFNIjHolnZCKCTLA6m/G625cdn3O7eNmT0iD3jfo6HZ9cdImGZwf21prw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", + "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", "dev": true, "requires": { - "hosted-git-info": "^3.0.6", - "resolve": "^1.17.0", - "semver": "^7.3.2", + "hosted-git-info": "^4.0.1", + "resolve": "^1.20.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" } }, @@ -2680,9 +2750,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -2716,9 +2786,9 @@ }, "dependencies": { "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "normalize-package-data": { @@ -2777,10 +2847,13 @@ } }, "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "strip-indent": { "version": "3.0.0", @@ -2792,9 +2865,9 @@ } }, "trim-newlines": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", - "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, "type-fest": { @@ -2810,17 +2883,17 @@ "dev": true }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true } } }, "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "dev": true, "requires": { "safe-buffer": "~5.1.1" @@ -2847,9 +2920,9 @@ "dev": true }, "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", "dev": true }, "core-util-is": { @@ -2858,22 +2931,22 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", "dev": true, "requires": { "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", + "import-fresh": "^3.2.1", "parse-json": "^5.0.0", "path-type": "^4.0.0", - "yaml": "^1.7.2" + "yaml": "^1.10.0" }, "dependencies": { "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -2933,6 +3006,12 @@ "shebang-command": "^1.2.0", "which": "^1.2.9" } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true } } }, @@ -2986,12 +3065,20 @@ "dev": true }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, "decamelize": { @@ -3247,6 +3334,12 @@ "safer-buffer": "^2.1.0" } }, + "electron-to-chromium": { + "version": "1.3.756", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.756.tgz", + "integrity": "sha512-WsmJym1TMeHVndjPjczTFbnRR/c4sbzg8fBFtuhlb2Sru3i/S1VGpzDSrv/It8ctMU2bj8G7g7/O3FzYMGw6eA==", + "dev": true + }, "emittery": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.4.1.tgz", @@ -3325,6 +3418,12 @@ "pump": "^3.0.0" } }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -3402,36 +3501,6 @@ "is-arrayish": "^0.2.1" } }, - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, "es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -3453,6 +3522,12 @@ "es6-promise": "^4.0.3" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -3522,6 +3597,12 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -3609,29 +3690,37 @@ } }, "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { "estraverse": "^5.1.0" }, "dependencies": { "estraverse": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", - "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", "dev": true } } }, "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "requires": { - "estraverse": "^4.1.0" + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } } }, "estraverse": { @@ -3830,9 +3919,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -3862,9 +3951,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -3877,13 +3966,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "to-regex-range": { @@ -3909,9 +3998,9 @@ "dev": true }, "fastq": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz", - "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -4013,12 +4102,12 @@ } }, "find-versions": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", - "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", + "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", "dev": true, "requires": { - "semver-regex": "^2.0.0" + "semver-regex": "^3.1.2" } }, "flat-cache": { @@ -4112,15 +4201,14 @@ } }, "fs-extra": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", - "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", "dev": true, "requires": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", - "universalify": "^1.0.0" + "universalify": "^2.0.0" } }, "fs-minipass": { @@ -4234,9 +4322,9 @@ } }, "gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true }, "get-caller-file": { @@ -4251,6 +4339,17 @@ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "get-port": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz", @@ -4313,9 +4412,9 @@ } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -4410,15 +4509,15 @@ } }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", "dev": true }, "handlebars": { - "version": "4.7.6", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", - "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, "requires": { "minimist": "^1.2.5", @@ -4472,9 +4571,9 @@ "dev": true }, "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, "has-value": { @@ -4518,11 +4617,6 @@ "is-stream": "^1.0.1" } }, - "hoek": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", - "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" - }, "hook-std": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz", @@ -4530,9 +4624,9 @@ "dev": true }, "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "html-escaper": { @@ -4584,9 +4678,9 @@ }, "dependencies": { "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" @@ -4595,9 +4689,9 @@ } }, "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "iconv-lite": { @@ -4628,9 +4722,9 @@ "dev": true }, "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -4707,9 +4801,9 @@ "dev": true }, "ini": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", - "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, "inquirer": { @@ -4734,9 +4828,9 @@ } }, "into-stream": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-5.1.1.tgz", - "integrity": "sha512-krrAJ7McQxGGmvaYbB7Q1mcA+cRwg9Ij2RfWIeVesNBgVDZmzY/Fa4IpZUT3bmdRzMzdf/mzltCG2Dq99IZGBA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", + "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", "dev": true, "requires": { "from2": "^2.3.0", @@ -4770,10 +4864,13 @@ } }, "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", + "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0" + } }, "is-arrayish": { "version": "0.2.1", @@ -4796,12 +4893,6 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", - "dev": true - }, "is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -4811,6 +4902,15 @@ "ci-info": "^2.0.0" } }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", @@ -4832,9 +4932,9 @@ } }, "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", "dev": true }, "is-descriptor": { @@ -5003,12 +5103,13 @@ "dev": true }, "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" } }, "is-retry-allowed": { @@ -5023,15 +5124,6 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, "is-text-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", @@ -5070,14 +5162,6 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, - "isemail": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", - "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", - "requires": { - "punycode": "2.x.x" - } - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5136,14 +5220,6 @@ "@babel/types": "^7.4.0", "istanbul-lib-coverage": "^2.0.5", "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==", - "dev": true - } } }, "istanbul-lib-report": { @@ -5193,16 +5269,6 @@ "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", "dev": true }, - "joi": { - "version": "14.3.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", - "integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==", - "requires": { - "hoek": "6.x.x", - "isemail": "3.x.x", - "topo": "3.x.x" - } - }, "js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -5216,9 +5282,9 @@ "dev": true }, "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -5353,9 +5419,9 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, "requires": { "minimist": "^1.2.5" @@ -5369,14 +5435,6 @@ "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" - }, - "dependencies": { - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } } }, "jsonparse": { @@ -5397,9 +5455,9 @@ } }, "jszip": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.5.0.tgz", - "integrity": "sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.6.0.tgz", + "integrity": "sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ==", "dev": true, "requires": { "lie": "~3.3.0", @@ -5488,9 +5546,9 @@ } }, "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.camelcase": { "version": "4.3.0", @@ -5655,6 +5713,14 @@ "requires": { "pify": "^4.0.1", "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "map-cache": { @@ -5685,26 +5751,26 @@ "dev": true }, "marked-terminal": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.1.0.tgz", - "integrity": "sha512-5KllfAOW02WS6hLRQ7cNvGOxvKW1BKuXELH4EtbWfyWgxQhROoMxEvuQ/3fTgkNjledR0J48F4HbapvYp1zWkQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.1.1.tgz", + "integrity": "sha512-t7Mdf6T3PvOEyN01c3tYxDzhyKZ8xnkp8Rs6Fohno63L/0pFTJ5Qtwto2AQVuDtbQiWzD+4E5AAu1Z2iLc8miQ==", "dev": true, "requires": { "ansi-escapes": "^4.3.1", "cardinal": "^2.1.1", - "chalk": "^4.0.0", + "chalk": "^4.1.0", "cli-table": "^0.3.1", "node-emoji": "^1.10.0", "supports-hyperlinks": "^2.1.0" }, "dependencies": { "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "type-fest": "^0.11.0" + "type-fest": "^0.21.3" } }, "ansi-styles": { @@ -5717,9 +5783,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5757,9 +5823,9 @@ } }, "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true } } @@ -5856,22 +5922,22 @@ } }, "mime": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", - "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", "dev": true }, "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" }, "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", "requires": { - "mime-db": "1.44.0" + "mime-db": "1.48.0" } }, "mimic-fn": { @@ -5981,9 +6047,9 @@ "dev": true }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "multimatch": { @@ -6005,9 +6071,9 @@ "dev": true }, "nan": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", "dev": true, "optional": true }, @@ -6075,6 +6141,14 @@ "propagate": "^1.0.0", "qs": "^6.5.1", "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "node-emoji": { @@ -6092,6 +6166,12 @@ "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", "dev": true }, + "node-releases": { + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", + "dev": true + }, "node-status-codes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz", @@ -6108,6 +6188,14 @@ "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "normalize-path": { @@ -6117,189 +6205,276 @@ "dev": true }, "normalize-url": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-5.3.0.tgz", - "integrity": "sha512-9/nOVLYYe/dO/eJeQUNaGUF4m4Z5E7cb9oNTKabH+bNf19mqj60txTcveQxL0GlcWLXCxkOu2/LwL8oW0idIDA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", "dev": true }, "npm": { - "version": "6.14.8", - "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.8.tgz", - "integrity": "sha512-HBZVBMYs5blsj94GTeQZel7s9odVuuSUHy1+AlZh7rPVux1os2ashvEGLy/STNK7vUjbrCg5Kq9/GXisJgdf6A==", + "version": "7.18.1", + "resolved": "https://registry.npmjs.org/npm/-/npm-7.18.1.tgz", + "integrity": "sha512-fu7rMtc4ZaDnFlZsiLhqwWWs6KixOcBGiBLoJH+AbuaznwtT8mYQnq5nGNN14Jib+E9OjkjNRgg+X45Ia9xtKQ==", "dev": true, "requires": { - "JSONStream": "^1.3.5", + "@npmcli/arborist": "^2.6.3", + "@npmcli/ci-detect": "^1.2.0", + "@npmcli/config": "^2.2.0", + "@npmcli/run-script": "^1.8.5", "abbrev": "~1.1.1", "ansicolors": "~0.3.2", "ansistyles": "~0.1.3", - "aproba": "^2.0.0", "archy": "~1.0.0", - "bin-links": "^1.1.8", - "bluebird": "^3.5.5", - "byte-size": "^5.0.1", - "cacache": "^12.0.3", - "call-limit": "^1.1.1", - "chownr": "^1.1.4", - "ci-info": "^2.0.0", + "byte-size": "^7.0.1", + "cacache": "^15.2.0", + "chalk": "^4.1.0", + "chownr": "^2.0.0", "cli-columns": "^3.1.2", - "cli-table3": "^0.5.1", - "cmd-shim": "^3.0.3", + "cli-table3": "^0.6.0", "columnify": "~1.5.4", - "config-chain": "^1.1.12", - "debuglog": "*", - "detect-indent": "~5.0.0", - "detect-newline": "^2.1.0", - "dezalgo": "~1.0.3", - "editor": "~1.0.0", - "figgy-pudding": "^3.5.1", - "find-npm-prefix": "^1.0.2", - "fs-vacuum": "~1.2.10", - "fs-write-stream-atomic": "~1.0.10", - "gentle-fs": "^2.3.1", - "glob": "^7.1.6", - "graceful-fs": "^4.2.4", - "has-unicode": "~2.0.1", - "hosted-git-info": "^2.8.8", - "iferr": "^1.0.2", - "imurmurhash": "*", - "infer-owner": "^1.0.4", - "inflight": "~1.0.6", - "inherits": "^2.0.4", - "ini": "^1.3.5", - "init-package-json": "^1.10.3", - "is-cidr": "^3.0.0", - "json-parse-better-errors": "^1.0.2", - "lazy-property": "~1.0.0", - "libcipm": "^4.0.8", - "libnpm": "^3.0.1", - "libnpmaccess": "^3.0.2", - "libnpmhook": "^5.0.3", - "libnpmorg": "^1.0.1", - "libnpmsearch": "^2.0.2", - "libnpmteam": "^1.0.2", - "libnpx": "^10.2.4", - "lock-verify": "^2.1.0", - "lockfile": "^1.0.4", - "lodash._baseindexof": "*", - "lodash._baseuniq": "~4.6.0", - "lodash._bindcallback": "*", - "lodash._cacheindexof": "*", - "lodash._createcache": "*", - "lodash._getnative": "*", - "lodash.clonedeep": "~4.5.0", - "lodash.restparam": "*", - "lodash.union": "~4.6.0", - "lodash.uniq": "~4.5.0", - "lodash.without": "~4.4.0", - "lru-cache": "^5.1.1", - "meant": "^1.0.2", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.5", - "move-concurrently": "^1.0.1", - "node-gyp": "^5.1.0", - "nopt": "^4.0.3", - "normalize-package-data": "^2.5.0", - "npm-audit-report": "^1.3.3", - "npm-cache-filename": "~1.0.2", - "npm-install-checks": "^3.0.2", - "npm-lifecycle": "^3.1.5", - "npm-package-arg": "^6.1.1", - "npm-packlist": "^1.4.8", - "npm-pick-manifest": "^3.0.2", - "npm-profile": "^4.0.4", - "npm-registry-fetch": "^4.0.7", - "npm-user-validate": "~1.0.0", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "hosted-git-info": "^4.0.2", + "ini": "^2.0.0", + "init-package-json": "^2.0.3", + "is-cidr": "^4.0.2", + "json-parse-even-better-errors": "^2.3.1", + "leven": "^3.1.0", + "libnpmaccess": "^4.0.2", + "libnpmdiff": "^2.0.4", + "libnpmexec": "^2.0.0", + "libnpmfund": "^1.1.0", + "libnpmhook": "^6.0.2", + "libnpmorg": "^2.0.2", + "libnpmpack": "^2.0.1", + "libnpmpublish": "^4.0.1", + "libnpmsearch": "^3.1.1", + "libnpmteam": "^2.0.3", + "libnpmversion": "^1.2.1", + "make-fetch-happen": "^9.0.3", + "minipass": "^3.1.3", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "ms": "^2.1.2", + "node-gyp": "^7.1.2", + "nopt": "^5.0.0", + "npm-audit-report": "^2.1.5", + "npm-package-arg": "^8.1.5", + "npm-pick-manifest": "^6.1.1", + "npm-profile": "^5.0.3", + "npm-registry-fetch": "^11.0.0", + "npm-user-validate": "^1.0.1", "npmlog": "~4.1.2", - "once": "~1.4.0", - "opener": "^1.5.1", - "osenv": "^0.1.5", - "pacote": "^9.5.12", - "path-is-inside": "~1.0.2", - "promise-inflight": "~1.0.1", + "opener": "^1.5.2", + "pacote": "^11.3.3", + "parse-conflict-json": "^1.1.1", "qrcode-terminal": "^0.12.0", - "query-string": "^6.8.2", - "qw": "~1.0.1", "read": "~1.0.7", - "read-cmd-shim": "^1.0.5", - "read-installed": "~4.0.3", - "read-package-json": "^2.1.1", - "read-package-tree": "^5.3.1", - "readable-stream": "^3.6.0", + "read-package-json": "^3.0.1", + "read-package-json-fast": "^2.0.2", "readdir-scoped-modules": "^1.1.0", - "request": "^2.88.0", - "retry": "^0.12.0", - "rimraf": "^2.7.1", - "safe-buffer": "^5.1.2", - "semver": "^5.7.1", - "sha": "^3.0.0", - "slide": "~1.1.6", - "sorted-object": "~2.0.1", - "sorted-union-stream": "~2.1.3", - "ssri": "^6.0.1", - "stringify-package": "^1.0.1", - "tar": "^4.4.13", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "ssri": "^8.0.1", + "tar": "^6.1.0", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", - "uid-number": "0.0.6", - "umask": "~1.1.0", - "unique-filename": "^1.1.1", - "unpipe": "~1.0.0", - "update-notifier": "^2.5.0", - "uuid": "^3.3.3", - "validate-npm-package-license": "^3.0.4", + "treeverse": "^1.0.4", "validate-npm-package-name": "~3.0.0", - "which": "^1.3.1", - "worker-farm": "^1.7.0", - "write-file-atomic": "^2.4.3" + "which": "^2.0.2", + "write-file-atomic": "^3.0.3" }, "dependencies": { - "JSONStream": { - "version": "1.3.5", + "@npmcli/arborist": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/map-workspaces": "^1.0.2", + "@npmcli/metavuln-calculator": "^1.1.0", + "@npmcli/move-file": "^1.1.0", + "@npmcli/name-from-folder": "^1.0.1", + "@npmcli/node-gyp": "^1.0.1", + "@npmcli/run-script": "^1.8.2", + "bin-links": "^2.2.1", + "cacache": "^15.0.3", + "common-ancestor-path": "^1.0.1", + "json-parse-even-better-errors": "^2.3.1", + "json-stringify-nice": "^1.1.4", + "mkdirp-infer-owner": "^2.0.0", + "npm-install-checks": "^4.0.0", + "npm-package-arg": "^8.1.0", + "npm-pick-manifest": "^6.1.0", + "npm-registry-fetch": "^11.0.0", + "pacote": "^11.2.6", + "parse-conflict-json": "^1.1.1", + "proc-log": "^1.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.1", + "read-package-json-fast": "^2.0.2", + "readdir-scoped-modules": "^1.1.0", + "semver": "^7.3.5", + "tar": "^6.1.0", + "treeverse": "^1.0.4", + "walk-up-path": "^1.0.0" + } + }, + "@npmcli/ci-detect": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "@npmcli/config": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "ini": "^2.0.0", + "mkdirp-infer-owner": "^2.0.0", + "nopt": "^5.0.0", + "semver": "^7.3.4", + "walk-up-path": "^1.0.0" + } + }, + "@npmcli/disparity-colors": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^4.3.0" + } + }, + "@npmcli/git": { + "version": "2.0.9", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^6.0.0", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^6.1.1", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + } + }, + "@npmcli/installed-package-contents": { + "version": "1.0.7", + "bundled": true, + "dev": true, + "requires": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "@npmcli/map-workspaces": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/name-from-folder": "^1.0.1", + "glob": "^7.1.6", + "minimatch": "^3.0.4", + "read-package-json-fast": "^2.0.1" + } + }, + "@npmcli/metavuln-calculator": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "cacache": "^15.0.5", + "pacote": "^11.1.11", + "semver": "^7.3.2" + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/name-from-folder": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "@npmcli/node-gyp": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "1.3.2", + "bundled": true, + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@npmcli/run-script": { + "version": "1.8.5", "bundled": true, "dev": true, "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" + "@npmcli/node-gyp": "^1.0.2", + "@npmcli/promise-spawn": "^1.3.2", + "infer-owner": "^1.0.4", + "node-gyp": "^7.1.0", + "read-package-json-fast": "^2.0.1" } }, + "@tootallnate/once": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, "abbrev": { "version": "1.1.1", "bundled": true, "dev": true }, "agent-base": { - "version": "4.3.0", + "version": "6.0.2", "bundled": true, "dev": true, "requires": { - "es6-promisify": "^5.0.0" + "debug": "4" } }, "agentkeepalive": { - "version": "3.5.2", + "version": "4.1.4", "bundled": true, "dev": true, "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", "humanize-ms": "^1.2.1" } }, - "ajv": { - "version": "5.5.2", + "aggregate-error": { + "version": "3.1.0", "bundled": true, "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" + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" } }, - "ansi-align": { - "version": "2.0.0", + "ajv": { + "version": "6.12.6", "bundled": true, "dev": true, "requires": { - "string-width": "^2.0.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "ansi-regex": { @@ -6308,11 +6483,11 @@ "dev": true }, "ansi-styles": { - "version": "3.2.1", + "version": "4.3.0", "bundled": true, "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" } }, "ansicolors": { @@ -6336,36 +6511,12 @@ "dev": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": 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" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } } }, "asap": { @@ -6397,12 +6548,12 @@ "dev": true }, "aws4": { - "version": "1.8.0", + "version": "1.11.0", "bundled": true, "dev": true }, "balanced-match": { - "version": "1.0.0", + "version": "1.0.2", "bundled": true, "dev": true }, @@ -6410,43 +6561,28 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "tweetnacl": "^0.14.3" } }, "bin-links": { - "version": "1.1.8", + "version": "2.2.1", "bundled": true, "dev": true, "requires": { - "bluebird": "^3.5.3", - "cmd-shim": "^3.0.0", - "gentle-fs": "^2.3.0", - "graceful-fs": "^4.1.15", + "cmd-shim": "^4.0.1", + "mkdirp": "^1.0.3", "npm-normalize-package-bin": "^1.0.0", - "write-file-atomic": "^2.3.0" + "read-cmd-shim": "^2.0.0", + "rimraf": "^3.0.0", + "write-file-atomic": "^3.0.3" } }, - "bluebird": { - "version": "3.5.5", + "binary-extensions": { + "version": "2.2.0", "bundled": true, "dev": true }, - "boxen": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - } - }, "brace-expansion": { "version": "1.1.11", "bundled": true, @@ -6456,98 +6592,69 @@ "concat-map": "0.0.1" } }, - "buffer-from": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, "builtins": { "version": "1.0.3", "bundled": true, "dev": true }, - "byline": { - "version": "5.0.0", - "bundled": true, - "dev": true - }, "byte-size": { - "version": "5.0.1", + "version": "7.0.1", "bundled": true, "dev": true }, "cacache": { - "version": "12.0.3", + "version": "15.2.0", "bundled": true, "dev": true, "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" } }, - "call-limit": { - "version": "1.1.1", - "bundled": true, - "dev": true - }, - "camelcase": { - "version": "4.1.0", - "bundled": true, - "dev": true - }, - "capture-stack-trace": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, "caseless": { "version": "0.12.0", "bundled": true, "dev": true }, "chalk": { - "version": "2.4.1", + "version": "4.1.1", "bundled": true, "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, "chownr": { - "version": "1.1.4", - "bundled": true, - "dev": true - }, - "ci-info": { "version": "2.0.0", "bundled": true, "dev": true }, "cidr-regex": { - "version": "2.0.10", + "version": "3.1.1", "bundled": true, "dev": true, "requires": { - "ip-regex": "^2.1.0" + "ip-regex": "^4.1.0" } }, - "cli-boxes": { - "version": "1.0.0", + "clean-stack": { + "version": "2.2.0", "bundled": true, "dev": true }, @@ -6561,51 +6668,41 @@ } }, "cli-table3": { - "version": "0.5.1", + "version": "0.6.0", "bundled": true, "dev": true, "requires": { "colors": "^1.1.2", "object-assign": "^4.1.0", - "string-width": "^2.1.1" - } - }, - "cliui": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" + "string-width": "^4.2.0" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", + "version": "5.0.0", "bundled": true, "dev": true }, "is-fullwidth-code-point": { - "version": "2.0.0", + "version": "3.0.0", "bundled": true, "dev": true }, "string-width": { - "version": "3.1.0", + "version": "4.2.2", "bundled": true, "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" } }, "strip-ansi": { - "version": "5.2.0", + "version": "6.0.0", "bundled": true, "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.0" } } } @@ -6616,39 +6713,33 @@ "dev": true }, "cmd-shim": { - "version": "3.0.3", + "version": "4.1.0", "bundled": true, "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "mkdirp": "~0.5.0" + "mkdirp-infer-owner": "^2.0.0" } }, - "co": { - "version": "4.6.0", - "bundled": true, - "dev": true - }, "code-point-at": { "version": "1.1.0", "bundled": true, "dev": true }, "color-convert": { - "version": "1.9.1", + "version": "2.0.1", "bundled": true, "dev": true, "requires": { - "color-name": "^1.1.1" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", + "version": "1.1.4", "bundled": true, "dev": true }, "colors": { - "version": "1.3.3", + "version": "1.4.0", "bundled": true, "dev": true, "optional": true @@ -6663,156 +6754,35 @@ } }, "combined-stream": { - "version": "1.0.6", + "version": "1.0.8", "bundled": true, "dev": true, "requires": { "delayed-stream": "~1.0.0" } }, + "common-ancestor-path": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, "concat-map": { "version": "0.0.1", "bundled": true, "dev": true }, - "concat-stream": { - "version": "1.6.2", - "bundled": true, - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": 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" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "config-chain": { - "version": "1.1.12", - "bundled": true, - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "configstore": { - "version": "3.1.5", - "bundled": true, - "dev": true, - "requires": { - "dot-prop": "^4.2.1", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "copy-concurrently": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "iferr": { - "version": "0.1.5", - "bundled": true, - "dev": true - } - } - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "create-error-class": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "capture-stack-trace": "^1.0.0" - } - }, - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "bundled": true, - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "bundled": true, - "dev": true - } - } - }, - "crypto-random-string": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "cyclist": { - "version": "0.2.2", - "bundled": true, - "dev": true - }, - "dashdash": { - "version": "1.14.1", + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "dashdash": { + "version": "1.14.1", "bundled": true, "dev": true, "requires": { @@ -6820,15 +6790,15 @@ } }, "debug": { - "version": "3.1.0", + "version": "4.3.1", "bundled": true, "dev": true, "requires": { - "ms": "2.0.0" + "ms": "2.1.2" }, "dependencies": { "ms": { - "version": "2.0.0", + "version": "2.1.2", "bundled": true, "dev": true } @@ -6839,21 +6809,6 @@ "bundled": true, "dev": true }, - "decamelize": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "bundled": true, - "dev": true - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true - }, "defaults": { "version": "1.0.3", "bundled": true, @@ -6862,14 +6817,6 @@ "clone": "^1.0.2" } }, - "define-properties": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, "delayed-stream": { "version": "1.0.0", "bundled": true, @@ -6880,13 +6827,8 @@ "bundled": true, "dev": true }, - "detect-indent": { - "version": "5.0.0", - "bundled": true, - "dev": true - }, - "detect-newline": { - "version": "2.1.0", + "depd": { + "version": "1.1.2", "bundled": true, "dev": true }, @@ -6899,166 +6841,44 @@ "wrappy": "1" } }, - "dotenv": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "duplexer3": { - "version": "0.1.4", + "diff": { + "version": "5.0.0", "bundled": true, "dev": true }, - "duplexify": { - "version": "3.6.0", - "bundled": true, - "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": 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" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, "ecc-jsbn": { "version": "0.1.2", "bundled": true, "dev": true, - "optional": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, - "editor": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, "emoji-regex": { - "version": "7.0.3", + "version": "8.0.0", "bundled": true, "dev": true }, "encoding": { - "version": "0.1.12", - "bundled": true, - "dev": true, - "requires": { - "iconv-lite": "~0.4.13" - } - }, - "end-of-stream": { - "version": "1.4.1", + "version": "0.1.13", "bundled": true, "dev": true, + "optional": true, "requires": { - "once": "^1.4.0" + "iconv-lite": "^0.6.2" } }, "env-paths": { - "version": "2.2.0", + "version": "2.2.1", "bundled": true, "dev": true }, "err-code": { - "version": "1.1.2", - "bundled": true, - "dev": true - }, - "errno": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "requires": { - "prr": "~1.0.1" - } - }, - "es-abstract": { - "version": "1.12.0", - "bundled": true, - "dev": true, - "requires": { - "es-to-primitive": "^1.1.1", - "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-promise": { - "version": "4.2.8", - "bundled": true, - "dev": true - }, - "es6-promisify": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escape-string-regexp": { - "version": "1.0.5", + "version": "2.0.3", "bundled": true, "dev": true }, - "execa": { - "version": "0.7.0", - "bundled": true, - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.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" - }, - "dependencies": { - "get-stream": { - "version": "3.0.0", - "bundled": true, - "dev": true - } - } - }, "extend": { "version": "3.0.2", "bundled": true, @@ -7070,173 +6890,26 @@ "dev": true }, "fast-deep-equal": { - "version": "1.1.0", + "version": "3.1.3", "bundled": true, "dev": true }, "fast-json-stable-stringify": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "figgy-pudding": { - "version": "3.5.1", - "bundled": true, - "dev": true - }, - "find-npm-prefix": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "flush-write-stream": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": 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" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "forever-agent": { - "version": "0.6.1", + "version": "2.1.0", "bundled": true, "dev": true }, - "form-data": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" - } - }, - "from2": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": 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" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "fs-minipass": { - "version": "1.2.7", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^2.6.0" - }, - "dependencies": { - "minipass": { - "version": "2.9.0", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - } - } - }, - "fs-vacuum": { - "version": "1.2.10", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "path-is-inside": "^1.0.1", - "rimraf": "^2.5.2" - } + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true }, - "fs-write-stream-atomic": { - "version": "1.0.10", + "fs-minipass": { + "version": "2.1.0", "bundled": true, "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - }, - "dependencies": { - "iferr": { - "version": "0.1.5", - "bundled": true, - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": 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" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "minipass": "^3.0.0" } }, "fs.realpath": { @@ -7269,6 +6942,14 @@ "bundled": true, "dev": true }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, "string-width": { "version": "1.0.2", "bundled": true, @@ -7281,54 +6962,6 @@ } } }, - "genfun": { - "version": "5.0.0", - "bundled": true, - "dev": true - }, - "gentle-fs": { - "version": "2.3.1", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^1.1.2", - "chownr": "^1.1.2", - "cmd-shim": "^3.0.3", - "fs-vacuum": "^1.2.10", - "graceful-fs": "^4.1.11", - "iferr": "^0.1.5", - "infer-owner": "^1.0.4", - "mkdirp": "^0.5.1", - "path-is-inside": "^1.0.2", - "read-cmd-shim": "^1.0.1", - "slide": "^1.1.6" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "iferr": { - "version": "0.1.5", - "bundled": true, - "dev": true - } - } - }, - "get-caller-file": { - "version": "2.0.5", - "bundled": true, - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, "getpass": { "version": "0.1.7", "bundled": true, @@ -7338,7 +6971,7 @@ } }, "glob": { - "version": "7.1.6", + "version": "7.1.7", "bundled": true, "dev": true, "requires": { @@ -7350,41 +6983,8 @@ "path-is-absolute": "^1.0.0" } }, - "global-dirs": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "requires": { - "ini": "^1.3.4" - } - }, - "got": { - "version": "6.7.1", - "bundled": true, - "dev": true, - "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - }, - "dependencies": { - "get-stream": { - "version": "3.0.0", - "bundled": true, - "dev": true - } - } - }, "graceful-fs": { - "version": "4.2.4", + "version": "4.2.6", "bundled": true, "dev": true }, @@ -7394,11 +6994,11 @@ "dev": true }, "har-validator": { - "version": "5.1.0", + "version": "5.1.5", "bundled": true, "dev": true, "requires": { - "ajv": "^5.3.0", + "ajv": "^6.12.3", "har-schema": "^2.0.0" } }, @@ -7411,12 +7011,7 @@ } }, "has-flag": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "has-symbols": { - "version": "1.0.0", + "version": "4.0.0", "bundled": true, "dev": true }, @@ -7426,22 +7021,26 @@ "dev": true }, "hosted-git-info": { - "version": "2.8.8", + "version": "4.0.2", "bundled": true, - "dev": true + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "http-cache-semantics": { - "version": "3.8.1", + "version": "4.1.0", "bundled": true, "dev": true }, "http-proxy-agent": { - "version": "2.1.0", + "version": "4.0.1", "bundled": true, "dev": true, "requires": { - "agent-base": "4", - "debug": "3.1.0" + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" } }, "http-signature": { @@ -7455,12 +7054,12 @@ } }, "https-proxy-agent": { - "version": "2.2.4", + "version": "5.0.0", "bundled": true, "dev": true, "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" + "agent-base": "6", + "debug": "4" } }, "humanize-ms": { @@ -7472,33 +7071,29 @@ } }, "iconv-lite": { - "version": "0.4.23", + "version": "0.6.3", "bundled": true, "dev": true, + "optional": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" } }, - "iferr": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, "ignore-walk": { - "version": "3.0.3", + "version": "3.0.4", "bundled": true, "dev": true, "requires": { "minimatch": "^3.0.4" } }, - "import-lazy": { - "version": "2.1.0", + "imurmurhash": { + "version": "0.1.4", "bundled": true, "dev": true }, - "imurmurhash": { - "version": "0.1.4", + "indent-string": { + "version": "4.0.0", "bundled": true, "dev": true }, @@ -7521,18 +7116,23 @@ "bundled": true, "dev": true }, + "ini": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, "init-package-json": { - "version": "1.10.3", + "version": "2.0.3", "bundled": true, "dev": true, "requires": { "glob": "^7.1.1", - "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", + "npm-package-arg": "^8.1.2", "promzard": "^0.3.0", "read": "~1.0.1", - "read-package-json": "1 || 2", - "semver": "2.x || 3.x || 4 || 5", - "validate-npm-package-license": "^3.0.1", + "read-package-json": "^3.0.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^3.0.0" } }, @@ -7542,108 +7142,36 @@ "dev": true }, "ip-regex": { - "version": "2.1.0", - "bundled": true, - "dev": true - }, - "is-callable": { - "version": "1.1.4", + "version": "4.3.0", "bundled": true, "dev": true }, - "is-ci": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "requires": { - "ci-info": "^1.5.0" - }, - "dependencies": { - "ci-info": { - "version": "1.6.0", - "bundled": true, - "dev": true - } - } - }, "is-cidr": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "cidr-regex": "^2.0.10" - } - }, - "is-date-object": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", + "version": "4.0.2", "bundled": true, "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "cidr-regex": "^3.1.1" } }, - "is-installed-globally": { - "version": "0.1.0", + "is-core-module": { + "version": "2.4.0", "bundled": true, "dev": true, "requires": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" + "has": "^1.0.3" } }, - "is-npm": { - "version": "1.0.0", + "is-fullwidth-code-point": { + "version": "2.0.0", "bundled": true, "dev": true }, - "is-obj": { - "version": "1.0.1", - "bundled": true - }, - "is-path-inside": { + "is-lambda": { "version": "1.0.1", "bundled": true, - "dev": true, - "requires": { - "path-is-inside": "^1.0.1" - } - }, - "is-redirect": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "is-regex": { - "version": "1.0.4", - "bundled": true, - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-retry-allowed": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "bundled": true, "dev": true }, - "is-symbol": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "has-symbols": "^1.0.0" - } - }, "is-typedarray": { "version": "1.0.0", "bundled": true, @@ -7667,11 +7195,10 @@ "jsbn": { "version": "0.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, - "json-parse-better-errors": { - "version": "1.0.2", + "json-parse-even-better-errors": { + "version": "2.3.1", "bundled": true, "dev": true }, @@ -7681,7 +7208,12 @@ "dev": true }, "json-schema-traverse": { - "version": "0.3.1", + "version": "0.4.1", + "bundled": true, + "dev": true + }, + "json-stringify-nice": { + "version": "1.1.4", "bundled": true, "dev": true }, @@ -7706,628 +7238,413 @@ "verror": "1.10.0" } }, - "latest-version": { - "version": "3.1.0", + "just-diff": { + "version": "3.1.1", "bundled": true, - "dev": true, - "requires": { - "package-json": "^4.0.0" - } + "dev": true }, - "lazy-property": { - "version": "1.0.0", + "just-diff-apply": { + "version": "3.0.0", "bundled": true, "dev": true }, - "libcipm": { - "version": "4.0.8", + "leven": { + "version": "3.1.0", "bundled": true, - "dev": true, - "requires": { - "bin-links": "^1.1.2", - "bluebird": "^3.5.1", - "figgy-pudding": "^3.5.1", - "find-npm-prefix": "^1.0.2", - "graceful-fs": "^4.1.11", - "ini": "^1.3.5", - "lock-verify": "^2.1.0", - "mkdirp": "^0.5.1", - "npm-lifecycle": "^3.0.0", - "npm-logical-tree": "^1.2.1", - "npm-package-arg": "^6.1.0", - "pacote": "^9.1.0", - "read-package-json": "^2.0.13", - "rimraf": "^2.6.2", - "worker-farm": "^1.6.0" - } + "dev": true }, - "libnpm": { - "version": "3.0.1", + "libnpmaccess": { + "version": "4.0.3", "bundled": true, "dev": true, "requires": { - "bin-links": "^1.1.2", - "bluebird": "^3.5.3", - "find-npm-prefix": "^1.0.2", - "libnpmaccess": "^3.0.2", - "libnpmconfig": "^1.2.1", - "libnpmhook": "^5.0.3", - "libnpmorg": "^1.0.1", - "libnpmpublish": "^1.1.2", - "libnpmsearch": "^2.0.2", - "libnpmteam": "^1.0.2", - "lock-verify": "^2.0.2", - "npm-lifecycle": "^3.0.0", - "npm-logical-tree": "^1.2.1", - "npm-package-arg": "^6.1.0", - "npm-profile": "^4.0.2", - "npm-registry-fetch": "^4.0.0", - "npmlog": "^4.1.2", - "pacote": "^9.5.3", - "read-package-json": "^2.0.13", - "stringify-package": "^1.0.0" + "aproba": "^2.0.0", + "minipass": "^3.1.1", + "npm-package-arg": "^8.1.2", + "npm-registry-fetch": "^11.0.0" } }, - "libnpmaccess": { - "version": "3.0.2", + "libnpmdiff": { + "version": "2.0.4", "bundled": true, "dev": true, "requires": { - "aproba": "^2.0.0", - "get-stream": "^4.0.0", - "npm-package-arg": "^6.1.0", - "npm-registry-fetch": "^4.0.0" + "@npmcli/disparity-colors": "^1.0.1", + "@npmcli/installed-package-contents": "^1.0.7", + "binary-extensions": "^2.2.0", + "diff": "^5.0.0", + "minimatch": "^3.0.4", + "npm-package-arg": "^8.1.4", + "pacote": "^11.3.4", + "tar": "^6.1.0" } }, - "libnpmconfig": { - "version": "1.2.1", + "libnpmexec": { + "version": "2.0.0", "bundled": true, "dev": true, "requires": { - "figgy-pudding": "^3.5.1", - "find-up": "^3.0.0", - "ini": "^1.3.5" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.0", - "bundled": true, - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "bundled": true, - "dev": true - } + "@npmcli/arborist": "^2.3.0", + "@npmcli/ci-detect": "^1.3.0", + "@npmcli/run-script": "^1.8.4", + "chalk": "^4.1.0", + "mkdirp-infer-owner": "^2.0.0", + "npm-package-arg": "^8.1.2", + "pacote": "^11.3.1", + "proc-log": "^1.0.0", + "read": "^1.0.7", + "read-package-json-fast": "^2.0.2", + "walk-up-path": "^1.0.0" + } + }, + "libnpmfund": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/arborist": "^2.5.0" } }, "libnpmhook": { - "version": "5.0.3", + "version": "6.0.3", "bundled": true, "dev": true, "requires": { "aproba": "^2.0.0", - "figgy-pudding": "^3.4.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" + "npm-registry-fetch": "^11.0.0" } }, "libnpmorg": { - "version": "1.0.1", + "version": "2.0.3", "bundled": true, "dev": true, "requires": { "aproba": "^2.0.0", - "figgy-pudding": "^3.4.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" + "npm-registry-fetch": "^11.0.0" + } + }, + "libnpmpack": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/run-script": "^1.8.3", + "npm-package-arg": "^8.1.0", + "pacote": "^11.2.6" } }, "libnpmpublish": { - "version": "1.1.2", + "version": "4.0.2", "bundled": true, "dev": true, "requires": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.5.1", - "get-stream": "^4.0.0", - "lodash.clonedeep": "^4.5.0", - "normalize-package-data": "^2.4.0", - "npm-package-arg": "^6.1.0", - "npm-registry-fetch": "^4.0.0", - "semver": "^5.5.1", - "ssri": "^6.0.1" + "normalize-package-data": "^3.0.2", + "npm-package-arg": "^8.1.2", + "npm-registry-fetch": "^11.0.0", + "semver": "^7.1.3", + "ssri": "^8.0.1" } }, "libnpmsearch": { - "version": "2.0.2", + "version": "3.1.2", "bundled": true, "dev": true, "requires": { - "figgy-pudding": "^3.5.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" + "npm-registry-fetch": "^11.0.0" } }, "libnpmteam": { - "version": "1.0.2", + "version": "2.0.4", "bundled": true, "dev": true, "requires": { "aproba": "^2.0.0", - "figgy-pudding": "^3.4.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" + "npm-registry-fetch": "^11.0.0" } }, - "libnpx": { - "version": "10.2.4", + "libnpmversion": { + "version": "1.2.1", "bundled": true, "dev": true, "requires": { - "dotenv": "^5.0.1", - "npm-package-arg": "^6.0.0", - "rimraf": "^2.6.2", - "safe-buffer": "^5.1.0", - "update-notifier": "^2.3.0", - "which": "^1.3.0", - "y18n": "^4.0.0", - "yargs": "^14.2.3" + "@npmcli/git": "^2.0.7", + "@npmcli/run-script": "^1.8.4", + "json-parse-even-better-errors": "^2.3.1", + "semver": "^7.3.5", + "stringify-package": "^1.0.1" } }, - "lock-verify": { - "version": "2.1.0", + "lru-cache": { + "version": "6.0.0", "bundled": true, "dev": true, "requires": { - "npm-package-arg": "^6.1.0", - "semver": "^5.4.1" + "yallist": "^4.0.0" } }, - "lockfile": { - "version": "1.0.4", + "make-fetch-happen": { + "version": "9.0.3", "bundled": true, "dev": true, "requires": { - "signal-exit": "^3.0.2" + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^5.0.0", + "ssri": "^8.0.0" } }, - "lodash._baseindexof": { - "version": "3.1.0", + "mime-db": { + "version": "1.48.0", "bundled": true, "dev": true }, - "lodash._baseuniq": { - "version": "4.6.0", + "mime-types": { + "version": "2.1.31", "bundled": true, "dev": true, "requires": { - "lodash._createset": "~4.0.0", - "lodash._root": "~3.0.0" + "mime-db": "1.48.0" } }, - "lodash._bindcallback": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "lodash._cacheindexof": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "lodash._createcache": { - "version": "3.1.2", + "minimatch": { + "version": "3.0.4", "bundled": true, "dev": true, "requires": { - "lodash._getnative": "^3.0.0" + "brace-expansion": "^1.1.7" } }, - "lodash._createset": { - "version": "4.0.3", - "bundled": true, - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "bundled": true, - "dev": true - }, - "lodash._root": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "lodash.clonedeep": { - "version": "4.5.0", - "bundled": true, - "dev": true - }, - "lodash.restparam": { - "version": "3.6.1", - "bundled": true, - "dev": true - }, - "lodash.union": { - "version": "4.6.0", - "bundled": true, - "dev": true - }, - "lodash.uniq": { - "version": "4.5.0", - "bundled": true, - "dev": true - }, - "lodash.without": { - "version": "4.4.0", - "bundled": true, - "dev": true - }, - "lowercase-keys": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "lru-cache": { - "version": "5.1.1", + "minipass": { + "version": "3.1.3", "bundled": true, "dev": true, "requires": { - "yallist": "^3.0.2" + "yallist": "^4.0.0" } }, - "make-dir": { - "version": "1.3.0", + "minipass-collect": { + "version": "1.0.2", "bundled": true, "dev": true, "requires": { - "pify": "^3.0.0" + "minipass": "^3.0.0" } }, - "make-fetch-happen": { - "version": "5.0.2", + "minipass-fetch": { + "version": "1.3.3", "bundled": true, "dev": true, "requires": { - "agentkeepalive": "^3.4.1", - "cacache": "^12.0.0", - "http-cache-semantics": "^3.8.1", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "node-fetch-npm": "^2.0.2", - "promise-retry": "^1.1.1", - "socks-proxy-agent": "^4.0.0", - "ssri": "^6.0.0" + "encoding": "^0.1.12", + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" } }, - "meant": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "mime-db": { - "version": "1.35.0", - "bundled": true, - "dev": true - }, - "mime-types": { - "version": "2.1.19", + "minipass-flush": { + "version": "1.0.5", "bundled": true, "dev": true, "requires": { - "mime-db": "~1.35.0" + "minipass": "^3.0.0" } }, - "minimatch": { - "version": "3.0.4", + "minipass-json-stream": { + "version": "1.0.1", "bundled": true, "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" } }, - "minimist": { - "version": "1.2.5", - "bundled": true, - "dev": true - }, - "minizlib": { - "version": "1.3.3", + "minipass-pipeline": { + "version": "1.2.4", "bundled": true, "dev": true, "requires": { - "minipass": "^2.9.0" - }, - "dependencies": { - "minipass": { - "version": "2.9.0", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - } + "minipass": "^3.0.0" } }, - "mississippi": { - "version": "3.0.0", + "minipass-sized": { + "version": "1.0.3", "bundled": true, "dev": true, "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" + "minipass": "^3.0.0" } }, - "mkdirp": { - "version": "0.5.5", + "minizlib": { + "version": "2.1.2", "bundled": true, "dev": true, "requires": { - "minimist": "^1.2.5" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "bundled": true, - "dev": true - } + "minipass": "^3.0.0", + "yallist": "^4.0.0" } }, - "move-concurrently": { - "version": "1.0.1", + "mkdirp": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "mkdirp-infer-owner": { + "version": "2.0.0", "bundled": true, "dev": true, "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true - } + "chownr": "^2.0.0", + "infer-owner": "^1.0.4", + "mkdirp": "^1.0.3" } }, "ms": { - "version": "2.1.1", + "version": "2.1.3", "bundled": true, "dev": true }, "mute-stream": { - "version": "0.0.7", + "version": "0.0.8", "bundled": true, "dev": true }, - "node-fetch-npm": { - "version": "2.0.2", + "negotiator": { + "version": "0.6.2", "bundled": true, - "dev": true, - "requires": { - "encoding": "^0.1.11", - "json-parse-better-errors": "^1.0.0", - "safe-buffer": "^5.1.1" - } + "dev": true }, "node-gyp": { - "version": "5.1.0", + "version": "7.1.2", "bundled": true, "dev": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", - "graceful-fs": "^4.2.2", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", + "graceful-fs": "^4.2.3", + "nopt": "^5.0.0", "npmlog": "^4.1.2", - "request": "^2.88.0", - "rimraf": "^2.6.3", - "semver": "^5.7.1", - "tar": "^4.4.12", - "which": "^1.3.1" + "request": "^2.88.2", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "tar": "^6.0.2", + "which": "^2.0.2" } }, "nopt": { - "version": "4.0.3", + "version": "5.0.0", "bundled": true, "dev": true, "requires": { - "abbrev": "1", - "osenv": "^0.1.4" + "abbrev": "1" } }, "normalize-package-data": { - "version": "2.5.0", + "version": "3.0.2", "bundled": true, "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", + "hosted-git-info": "^4.0.1", + "resolve": "^1.20.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "resolve": { - "version": "1.10.0", - "bundled": true, - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - } } }, "npm-audit-report": { - "version": "1.3.3", + "version": "2.1.5", "bundled": true, "dev": true, "requires": { - "cli-table3": "^0.5.0", - "console-control-strings": "^1.1.0" + "chalk": "^4.0.0" } }, "npm-bundled": { - "version": "1.1.1", + "version": "1.1.2", "bundled": true, "dev": true, "requires": { "npm-normalize-package-bin": "^1.0.1" } }, - "npm-cache-filename": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, "npm-install-checks": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "semver": "^2.3.0 || 3.x || 4 || 5" - } - }, - "npm-lifecycle": { - "version": "3.1.5", + "version": "4.0.0", "bundled": true, "dev": true, "requires": { - "byline": "^5.0.0", - "graceful-fs": "^4.1.15", - "node-gyp": "^5.0.2", - "resolve-from": "^4.0.0", - "slide": "^1.1.6", - "uid-number": "0.0.6", - "umask": "^1.1.0", - "which": "^1.3.1" + "semver": "^7.1.1" } }, - "npm-logical-tree": { - "version": "1.2.1", - "bundled": true, - "dev": true - }, "npm-normalize-package-bin": { "version": "1.0.1", "bundled": true, "dev": true }, "npm-package-arg": { - "version": "6.1.1", + "version": "8.1.5", "bundled": true, "dev": true, "requires": { - "hosted-git-info": "^2.7.1", - "osenv": "^0.1.5", - "semver": "^5.6.0", + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", "validate-npm-package-name": "^3.0.0" } }, "npm-packlist": { - "version": "1.4.8", + "version": "2.2.2", "bundled": true, "dev": true, "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", + "glob": "^7.1.6", + "ignore-walk": "^3.0.3", + "npm-bundled": "^1.1.1", "npm-normalize-package-bin": "^1.0.1" } }, "npm-pick-manifest": { - "version": "3.0.2", + "version": "6.1.1", "bundled": true, "dev": true, "requires": { - "figgy-pudding": "^3.5.1", - "npm-package-arg": "^6.0.0", - "semver": "^5.4.1" + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" } }, "npm-profile": { - "version": "4.0.4", + "version": "5.0.4", "bundled": true, "dev": true, "requires": { - "aproba": "^1.1.2 || 2", - "figgy-pudding": "^3.4.1", - "npm-registry-fetch": "^4.0.0" + "npm-registry-fetch": "^11.0.0" } }, "npm-registry-fetch": { - "version": "4.0.7", - "bundled": true, - "dev": true, - "requires": { - "JSONStream": "^1.3.4", - "bluebird": "^3.5.1", - "figgy-pudding": "^3.4.1", - "lru-cache": "^5.1.1", - "make-fetch-happen": "^5.0.0", - "npm-package-arg": "^6.1.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "bundled": true, - "dev": true - } - } - }, - "npm-run-path": { - "version": "2.0.2", + "version": "11.0.0", "bundled": true, "dev": true, "requires": { - "path-key": "^2.0.0" + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" } }, "npm-user-validate": { - "version": "1.0.0", + "version": "1.0.1", "bundled": true, "dev": true }, @@ -8357,20 +7674,6 @@ "bundled": true, "dev": true }, - "object-keys": { - "version": "1.0.12", - "bundled": true, - "dev": true - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, "once": { "version": "1.4.0", "bundled": true, @@ -8380,149 +7683,61 @@ } }, "opener": { - "version": "1.5.1", - "bundled": true, - "dev": true - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "p-finally": { - "version": "1.0.0", + "version": "1.5.2", "bundled": true, "dev": true }, - "package-json": { - "version": "4.0.1", + "p-map": { + "version": "4.0.0", "bundled": true, "dev": true, "requires": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" + "aggregate-error": "^3.0.0" } }, "pacote": { - "version": "9.5.12", - "bundled": true, - "dev": true, - "requires": { - "bluebird": "^3.5.3", - "cacache": "^12.0.2", - "chownr": "^1.1.2", - "figgy-pudding": "^3.5.1", - "get-stream": "^4.1.0", - "glob": "^7.1.3", - "infer-owner": "^1.0.4", - "lru-cache": "^5.1.1", - "make-fetch-happen": "^5.0.0", - "minimatch": "^3.0.4", - "minipass": "^2.3.5", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "normalize-package-data": "^2.4.0", - "npm-normalize-package-bin": "^1.0.0", - "npm-package-arg": "^6.1.0", - "npm-packlist": "^1.1.12", - "npm-pick-manifest": "^3.0.0", - "npm-registry-fetch": "^4.0.0", - "osenv": "^0.1.5", - "promise-inflight": "^1.0.1", - "promise-retry": "^1.1.1", - "protoduck": "^5.0.1", - "rimraf": "^2.6.2", - "safe-buffer": "^5.1.2", - "semver": "^5.6.0", - "ssri": "^6.0.1", - "tar": "^4.4.10", - "unique-filename": "^1.1.1", - "which": "^1.3.1" - }, - "dependencies": { - "minipass": { - "version": "2.9.0", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - } - } - }, - "parallel-transform": { - "version": "1.1.0", + "version": "11.3.4", "bundled": true, - "dev": true, - "requires": { - "cyclist": "~0.2.2", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": 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" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "dev": true, + "requires": { + "@npmcli/git": "^2.0.1", + "@npmcli/installed-package-contents": "^1.0.6", + "@npmcli/promise-spawn": "^1.2.0", + "@npmcli/run-script": "^1.8.2", + "cacache": "^15.0.5", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.3", + "mkdirp": "^1.0.3", + "npm-package-arg": "^8.0.1", + "npm-packlist": "^2.1.4", + "npm-pick-manifest": "^6.0.0", + "npm-registry-fetch": "^11.0.0", + "promise-retry": "^2.0.1", + "read-package-json-fast": "^2.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.0" } }, - "path-exists": { - "version": "3.0.0", + "parse-conflict-json": { + "version": "1.1.1", "bundled": true, - "dev": true + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "just-diff": "^3.0.1", + "just-diff-apply": "^3.0.0" + } }, "path-is-absolute": { "version": "1.0.1", "bundled": true, "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "path-key": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, "path-parse": { - "version": "1.0.6", + "version": "1.0.7", "bundled": true, "dev": true }, @@ -8531,18 +7746,23 @@ "bundled": true, "dev": true }, - "pify": { - "version": "3.0.0", + "proc-log": { + "version": "1.0.0", "bundled": true, "dev": true }, - "prepend-http": { - "version": "1.0.4", + "process-nextick-args": { + "version": "2.0.1", "bundled": true, "dev": true }, - "process-nextick-args": { - "version": "2.0.0", + "promise-all-reject-late": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-call-limit": { + "version": "1.0.1", "bundled": true, "dev": true }, @@ -8552,19 +7772,12 @@ "dev": true }, "promise-retry": { - "version": "1.1.1", + "version": "2.0.1", "bundled": true, "dev": true, "requires": { - "err-code": "^1.0.0", - "retry": "^0.10.0" - }, - "dependencies": { - "retry": { - "version": "0.10.1", - "bundled": true, - "dev": true - } + "err-code": "^2.0.2", + "retry": "^0.12.0" } }, "promzard": { @@ -8575,66 +7788,13 @@ "read": "1" } }, - "proto-list": { - "version": "1.2.4", - "bundled": true, - "dev": true - }, - "protoduck": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "requires": { - "genfun": "^5.0.0" - } - }, - "prr": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, "psl": { - "version": "1.1.29", + "version": "1.8.0", "bundled": true, "dev": true }, - "pump": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "bundled": true, - "dev": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, "punycode": { - "version": "1.4.1", + "version": "2.1.1", "bundled": true, "dev": true }, @@ -8648,32 +7808,6 @@ "bundled": true, "dev": true }, - "query-string": { - "version": "6.8.2", - "bundled": true, - "dev": true, - "requires": { - "decode-uri-component": "^0.2.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - } - }, - "qw": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, "read": { "version": "1.0.7", "bundled": true, @@ -8683,57 +7817,42 @@ } }, "read-cmd-shim": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.2" - } - }, - "read-installed": { - "version": "4.0.3", + "version": "2.0.0", "bundled": true, - "dev": true, - "requires": { - "debuglog": "^1.0.1", - "graceful-fs": "^4.1.2", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - } + "dev": true }, "read-package-json": { - "version": "2.1.1", + "version": "3.0.1", "bundled": true, "dev": true, "requires": { "glob": "^7.1.1", - "graceful-fs": "^4.1.2", - "json-parse-better-errors": "^1.0.1", - "normalize-package-data": "^2.0.0", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^3.0.0", "npm-normalize-package-bin": "^1.0.0" } }, - "read-package-tree": { - "version": "5.3.1", + "read-package-json-fast": { + "version": "2.0.2", "bundled": true, "dev": true, "requires": { - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "util-promisify": "^2.1.0" + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" } }, "readable-stream": { - "version": "3.6.0", + "version": "2.3.7", "bundled": true, "dev": true, "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "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" } }, "readdir-scoped-modules": { @@ -8747,25 +7866,8 @@ "once": "^1.3.0" } }, - "registry-auth-token": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "requires": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" - } - }, - "registry-url": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "rc": "^1.0.1" - } - }, "request": { - "version": "2.88.0", + "version": "2.88.2", "bundled": true, "dev": true, "requires": { @@ -8776,7 +7878,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.0", + "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", @@ -8786,25 +7888,40 @@ "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "bundled": true, + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "tough-cookie": { + "version": "2.5.0", + "bundled": true, + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } } }, - "require-directory": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "resolve-from": { - "version": "4.0.0", + "resolve": { + "version": "1.20.0", "bundled": true, - "dev": true + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } }, "retry": { "version": "0.12.0", @@ -8812,28 +7929,13 @@ "dev": true }, "rimraf": { - "version": "2.7.1", + "version": "3.0.2", "bundled": true, "dev": true, "requires": { "glob": "^7.1.3" } }, - "run-queue": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^1.1.1" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true - } - } - }, "safe-buffer": { "version": "5.1.2", "bundled": true, @@ -8845,16 +7947,11 @@ "dev": true }, "semver": { - "version": "5.7.1", - "bundled": true, - "dev": true - }, - "semver-diff": { - "version": "2.1.0", + "version": "7.3.5", "bundled": true, "dev": true, "requires": { - "semver": "^5.0.3" + "lru-cache": "^6.0.0" } }, "set-blocking": { @@ -8862,34 +7959,8 @@ "bundled": true, "dev": true }, - "sha": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.2" - } - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "slide": { - "version": "1.1.6", + "version": "3.0.3", "bundled": true, "dev": true }, @@ -8898,82 +7969,27 @@ "bundled": true, "dev": true }, - "socks": { - "version": "2.3.3", - "bundled": true, - "dev": true, - "requires": { - "ip": "1.1.5", - "smart-buffer": "^4.1.0" - } - }, - "socks-proxy-agent": { - "version": "4.0.2", - "bundled": true, - "dev": true, - "requires": { - "agent-base": "~4.2.1", - "socks": "~2.3.2" - }, - "dependencies": { - "agent-base": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "requires": { - "es6-promisify": "^5.0.0" - } - } - } - }, - "sorted-object": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "sorted-union-stream": { - "version": "2.1.3", - "bundled": true, - "dev": true, - "requires": { - "from2": "^1.3.0", - "stream-iterate": "^1.1.0" - }, - "dependencies": { - "from2": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~1.1.10" - } - }, - "isarray": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "bundled": true, - "dev": true, - "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", - "bundled": true, - "dev": true - } + "socks": { + "version": "2.6.1", + "bundled": true, + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4", + "socks": "^2.3.3" } }, "spdx-correct": { - "version": "3.0.0", + "version": "3.1.1", "bundled": true, "dev": true, "requires": { @@ -8982,12 +7998,12 @@ } }, "spdx-exceptions": { - "version": "2.1.0", + "version": "2.3.0", "bundled": true, "dev": true }, "spdx-expression-parse": { - "version": "3.0.0", + "version": "3.0.1", "bundled": true, "dev": true, "requires": { @@ -8996,17 +8012,12 @@ } }, "spdx-license-ids": { - "version": "3.0.5", - "bundled": true, - "dev": true - }, - "split-on-first": { - "version": "1.1.0", + "version": "3.0.9", "bundled": true, "dev": true }, "sshpk": { - "version": "1.14.2", + "version": "1.16.1", "bundled": true, "dev": true, "requires": { @@ -9022,65 +8033,13 @@ } }, "ssri": { - "version": "6.0.1", - "bundled": true, - "dev": true, - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "stream-each": { - "version": "1.2.2", - "bundled": true, - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-iterate": { - "version": "1.2.0", + "version": "8.0.1", "bundled": true, "dev": true, "requires": { - "readable-stream": "^2.1.5", - "stream-shift": "^1.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": 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" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "minipass": "^3.1.1" } }, - "stream-shift": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "strict-uri-encode": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, "string-width": { "version": "2.1.1", "bundled": true, @@ -9095,11 +8054,6 @@ "bundled": true, "dev": true }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, "strip-ansi": { "version": "4.0.0", "bundled": true, @@ -9111,18 +8065,11 @@ } }, "string_decoder": { - "version": "1.3.0", + "version": "1.1.1", "bundled": true, "dev": true, "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.0", - "bundled": true, - "dev": true - } + "safe-buffer": "~5.1.0" } }, "stringify-package": { @@ -9138,55 +8085,25 @@ "ansi-regex": "^2.0.0" } }, - "strip-eof": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, "supports-color": { - "version": "5.4.0", + "version": "7.2.0", "bundled": true, "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } }, "tar": { - "version": "4.4.13", - "bundled": true, - "dev": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - }, - "dependencies": { - "minipass": { - "version": "2.9.0", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - } - } - }, - "term-size": { - "version": "1.2.0", + "version": "6.1.0", "bundled": true, "dev": true, "requires": { - "execa": "^0.7.0" + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" } }, "text-table": { @@ -9194,62 +8111,15 @@ "bundled": true, "dev": true }, - "through": { - "version": "2.3.8", - "bundled": true, - "dev": true - }, - "through2": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": 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" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "timed-out": { - "version": "4.0.1", - "bundled": true, - "dev": true - }, "tiny-relative-date": { "version": "1.3.0", "bundled": true, "dev": true }, - "tough-cookie": { - "version": "2.4.3", + "treeverse": { + "version": "1.0.4", "bundled": true, - "dev": true, - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - } + "dev": true }, "tunnel-agent": { "version": "0.6.0", @@ -9262,23 +8132,15 @@ "tweetnacl": { "version": "0.14.5", "bundled": true, - "dev": true, - "optional": true - }, - "typedarray": { - "version": "0.0.6", - "bundled": true, - "dev": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, "dev": true }, - "umask": { - "version": "1.1.0", + "typedarray-to-buffer": { + "version": "3.1.5", "bundled": true, - "dev": true + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } }, "unique-filename": { "version": "1.1.1", @@ -9289,54 +8151,19 @@ } }, "unique-slug": { - "version": "2.0.0", + "version": "2.0.2", "bundled": true, "dev": true, "requires": { "imurmurhash": "^0.1.4" } }, - "unique-string": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "crypto-random-string": "^1.0.0" - } - }, - "unpipe": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "unzip-response": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "update-notifier": { - "version": "2.5.0", - "bundled": true, - "dev": true, - "requires": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "url-parse-lax": { - "version": "1.0.0", + "uri-js": { + "version": "4.4.1", "bundled": true, "dev": true, "requires": { - "prepend-http": "^1.0.1" + "punycode": "^2.1.0" } }, "util-deprecate": { @@ -9344,21 +8171,8 @@ "bundled": true, "dev": true }, - "util-extend": { - "version": "1.0.3", - "bundled": true, - "dev": true - }, - "util-promisify": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3" - } - }, "uuid": { - "version": "3.3.3", + "version": "3.4.0", "bundled": true, "dev": true }, @@ -9389,6 +8203,11 @@ "extsprintf": "^1.2.0" } }, + "walk-up-path": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, "wcwidth": { "version": "1.0.1", "bundled": true, @@ -9398,230 +8217,41 @@ } }, "which": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^1.0.2" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "widest-line": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^2.1.1" - } - }, - "worker-farm": { - "version": "1.7.0", - "bundled": true, - "dev": true, - "requires": { - "errno": "~0.1.7" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "bundled": true, - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "string-width": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "write-file-atomic": { - "version": "2.4.3", + "version": "2.0.2", "bundled": true, "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "isexe": "^2.0.0" } }, - "xdg-basedir": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "xtend": { - "version": "4.0.1", + "wide-align": { + "version": "1.1.3", "bundled": true, - "dev": true + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } }, - "y18n": { - "version": "4.0.0", + "wrappy": { + "version": "1.0.2", "bundled": true, "dev": true }, - "yallist": { + "write-file-atomic": { "version": "3.0.3", "bundled": true, - "dev": true - }, - "yargs": { - "version": "14.2.3", - "bundled": true, "dev": true, "requires": { - "cliui": "^5.0.0", - "decamelize": "^1.2.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": "^15.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "bundled": true, - "dev": true - }, - "find-up": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "locate-path": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "bundled": true, - "dev": true - }, - "string-width": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, - "yargs-parser": { - "version": "15.0.1", + "yallist": { + "version": "4.0.0", "bundled": true, - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "bundled": true, - "dev": true - } - } + "dev": true } } }, @@ -9739,20 +8369,14 @@ "integrity": "sha512-7n4IpLMzGGcLEMiQKsNR7vCe+N5E9LORFrtNUVy4sO3dj9a3HedZCxEL2T7QuLhcHN1NBuBsMOKaOsAYI9IIvg==", "dev": true }, - "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", - "dev": true - }, "object-is": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", - "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "object-keys": { @@ -9777,15 +8401,15 @@ } }, "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" } }, "object.pick": { @@ -9885,9 +8509,9 @@ "dev": true }, "p-each-series": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz", - "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", + "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", "dev": true }, "p-filter": { @@ -9942,13 +8566,13 @@ "dev": true }, "p-retry": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.2.0.tgz", - "integrity": "sha512-jPH38/MRh263KKcq0wBNOGFJbm+U6784RilTmHjB/HM9kH9V8WlCpVUcdOmip9cjXOh6MxZ5yk1z2SjDUJfWmA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.0.tgz", + "integrity": "sha512-SAHbQEwg3X5DRNaLmWjT+DlGc93ba5i+aP3QLfVNDncQEQO4xjbYW4N/lcVTSuP0aJietGfx2t94dJLzfBMpXw==", "dev": true, "requires": { "@types/retry": "^0.12.0", - "retry": "^0.12.0" + "retry": "^0.13.1" } }, "p-try": { @@ -9979,6 +8603,14 @@ "registry-auth-token": "^3.0.1", "registry-url": "^3.0.3", "semver": "^5.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "pako": { @@ -10049,9 +8681,9 @@ "dev": true }, "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==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-type": { @@ -10072,9 +8704,9 @@ } }, "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true }, "performance-now": { @@ -10083,9 +8715,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, "pify": { @@ -10234,6 +8866,12 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "quick-lru": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", @@ -10454,9 +9092,9 @@ } }, "regenerate": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", - "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "dev": true }, "regenerate-unicode-properties": { @@ -10479,13 +9117,13 @@ } }, "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "regexpp": { @@ -10495,9 +9133,9 @@ "dev": true }, "regexpu-core": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", - "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", "dev": true, "requires": { "regenerate": "^1.4.0", @@ -10534,9 +9172,9 @@ "dev": true }, "regjsparser": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", - "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", + "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -10566,9 +9204,9 @@ "dev": true }, "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true }, "repeat-string": { @@ -10651,11 +9289,12 @@ } }, "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { + "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } }, @@ -10697,9 +9336,9 @@ "dev": true }, "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true }, "reusify": { @@ -10724,15 +9363,18 @@ "dev": true }, "run-parallel": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", - "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } }, "rxjs": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz", - "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==", + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -10758,31 +9400,41 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "selenium-webdriver": { - "version": "4.0.0-alpha.7", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.7.tgz", - "integrity": "sha512-D4qnTsyTr91jT8f7MfN+OwY0IlU5+5FmlO5xlgRUV6hDEV8JyYx2NerdTEqDDkNq7RZDYc4VoPALk8l578RBHw==", + "version": "4.0.0-beta.4", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-beta.4.tgz", + "integrity": "sha512-+s/CIYkWzmnC9WASBxxVj7Lm0dcyl6OaFxwIJaFCT5WCuACiimEEr4lUnOOFP/QlKfkDQ56m+aRczaq2EvJEJg==", "dev": true, "requires": { - "jszip": "^3.2.2", - "rimraf": "^2.7.1", - "tmp": "0.0.30" + "jszip": "^3.6.0", + "rimraf": "^3.0.2", + "tmp": "^0.2.1", + "ws": ">=7.4.6" }, "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "tmp": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", "dev": true, "requires": { - "os-tmpdir": "~1.0.1" + "rimraf": "^3.0.0" } } } }, "semantic-release": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.2.3.tgz", - "integrity": "sha512-MY1MlowGQrkOR7+leOD8ICkVOC6i1szbwDODdbJ0UdshtMx8Ms0bhpRQmEEliqYKEb5PLv/dqs6zKKuHT7UxTg==", + "version": "17.4.4", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.4.4.tgz", + "integrity": "sha512-fQIA0lw2Sy/9+TcoM/BxyzKCSwdUd8EPRwGoOuBLgxKigPCY6kaKs8TOsgUVy6QrlTYwni2yzbMb5Q2107P9eA==", "dev": true, "requires": { "@semantic-release/commit-analyzer": "^8.0.0", @@ -10791,19 +9443,19 @@ "@semantic-release/npm": "^7.0.0", "@semantic-release/release-notes-generator": "^9.0.0", "aggregate-error": "^3.0.0", - "cosmiconfig": "^6.0.0", + "cosmiconfig": "^7.0.0", "debug": "^4.0.0", "env-ci": "^5.0.0", - "execa": "^4.0.0", + "execa": "^5.0.0", "figures": "^3.0.0", - "find-versions": "^3.0.0", - "get-stream": "^5.0.0", + "find-versions": "^4.0.0", + "get-stream": "^6.0.0", "git-log-parser": "^1.2.0", "hook-std": "^2.0.0", - "hosted-git-info": "^3.0.0", - "lodash": "^4.17.15", - "marked": "^1.0.0", - "marked-terminal": "^4.0.0", + "hosted-git-info": "^4.0.0", + "lodash": "^4.17.21", + "marked": "^2.0.0", + "marked-terminal": "^4.1.1", "micromatch": "^4.0.2", "p-each-series": "^2.1.0", "p-reduce": "^2.0.0", @@ -10812,7 +9464,7 @@ "semver": "^7.3.2", "semver-diff": "^3.1.1", "signale": "^1.2.1", - "yargs": "^15.0.1" + "yargs": "^16.2.0" }, "dependencies": { "ansi-regex": { @@ -10839,21 +9491,15 @@ "fill-range": "^7.0.1" } }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "requires": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "wrap-ansi": "^7.0.0" } }, "color-convert": { @@ -10889,19 +9535,19 @@ "dev": true }, "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, @@ -10934,18 +9580,15 @@ } }, "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true }, "hosted-git-info": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.7.tgz", - "integrity": "sha512-fWqc0IcuXs+BmE9orLDyVykAG9GJtGLGuZAAqgcckPgv5xad4AcXGIv8galtQvlwutxSlaMcdw7BUtq2EIvqCQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -10988,19 +9631,19 @@ } }, "marked": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.4.tgz", - "integrity": "sha512-6x5TFGCTKSQBLTZtOburGxCxFEBJEGYVLwCMTBCxzvyuisGcC20UNzDSJhCr/cJ/Kmh6ulfJm10g6WWEAJ3kvg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.2.tgz", + "integrity": "sha512-ueJhIvklJJw04qxQbGIAu63EXwwOCYc7yKMBjgagTM4rjC5QtWyqSNgW7jCosV1/Km/1TUfs5qEpAqcGG0Mo5g==", "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "mimic-fn": { @@ -11037,9 +9680,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -11098,10 +9741,13 @@ "dev": true }, "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "semver-diff": { "version": "3.1.1", @@ -11136,9 +9782,9 @@ "dev": true }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", "dev": true, "requires": { "emoji-regex": "^8.0.0", @@ -11180,9 +9826,9 @@ } }, "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { "ansi-styles": "^4.0.0", @@ -11190,6 +9836,12 @@ "strip-ansi": "^6.0.0" } }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -11197,40 +9849,32 @@ "dev": true }, "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" } }, "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true } } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "semver-diff": { @@ -11240,12 +9884,20 @@ "dev": true, "requires": { "semver": "^5.0.3" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "semver-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", - "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.2.tgz", + "integrity": "sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA==", "dev": true }, "serialize-error": { @@ -11579,9 +10231,9 @@ } }, "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=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "dev": true }, "spawn-error-forwarder": { @@ -11631,9 +10283,9 @@ } }, "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", "dev": true }, "split": { @@ -11655,22 +10307,23 @@ } }, "split2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", - "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", "dev": true, "requires": { - "through2": "^2.0.2" + "readable-stream": "^3.0.0" }, "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } } } @@ -11698,10 +10351,21 @@ } }, "stack-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", - "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", - "dev": true + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.5.tgz", + "integrity": "sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } }, "static-extend": { "version": "0.1.2", @@ -11786,26 +10450,6 @@ } } }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -11913,9 +10557,9 @@ } }, "supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", "dev": true, "requires": { "has-flag": "^4.0.0", @@ -12036,9 +10680,9 @@ "dev": true }, "tempy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.0.tgz", - "integrity": "sha512-eLXG5B1G0mRPHmgH2WydPl5v4jH35qEn3y/rA/aahKhIa91Pn119SsU7n7v/433gtT9ONzC8ISvNHIh2JSTm0w==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", + "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", "dev": true, "requires": { "del": "^6.0.0", @@ -12086,9 +10730,9 @@ } }, "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", "dev": true, "requires": { "array-union": "^2.1.0", @@ -12106,9 +10750,9 @@ "dev": true }, "is-path-inside": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", - "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, "is-stream": { @@ -12316,14 +10960,6 @@ "repeat-string": "^1.6.1" } }, - "topo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", - "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", - "requires": { - "hoek": "6.x.x" - } - }, "tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -12358,9 +10994,9 @@ "dev": true }, "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, "tunnel-agent": { @@ -12404,9 +11040,9 @@ "dev": true }, "uglify-js": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.1.tgz", - "integrity": "sha512-RjxApKkrPJB6kjJxQS3iZlf///REXWYxYJxO/MpmlQzVkDWVI3PSnCBWezMecmTU/TRkNxrl8bmsfFQCp+LO+Q==", + "version": "3.13.9", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.9.tgz", + "integrity": "sha512-wZbyTQ1w6Y7fHdt8sJnHfSIuWeDgk6B5rCb4E/AM6QNNPbOMIZph21PW5dRB3h7Df0GszN+t7RuUH6sWK5bF0g==", "dev": true, "optional": true }, @@ -12489,9 +11125,9 @@ "dev": true }, "universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true }, "unset-value": { @@ -12582,9 +11218,9 @@ } }, "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==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "requires": { "punycode": "^2.1.0" } @@ -12764,6 +11400,12 @@ "signal-exit": "^3.0.2" } }, + "ws": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.0.tgz", + "integrity": "sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw==", + "dev": true + }, "xdg-basedir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", @@ -12783,9 +11425,9 @@ "dev": true }, "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==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, "yallist": { @@ -12795,9 +11437,9 @@ "dev": true }, "yaml": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", - "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true }, "yargs": { diff --git a/package.json b/package.json index e1e19001..43afd384 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "index.js" ], "engines": { - "node": ">=6.0.0" + "node": ">=10.13.0" }, "scripts": { "test": "npm run test:unit && npm run test:e2e", @@ -31,14 +31,12 @@ "test:integration": "cross-env NOCK_OFF=true npm test", "posttest": "npm run lint -s", "lint": "eslint . --cache", - "cover": "nyc npm run test:unit -s", - "cover:integration": "nyc npm test:integration -s", + "cover": "nyc npm run test -s", "jsdoc": "jsdoc -c .jsdoc.json .", "docs": "mkdir -p doc && jsdoc2md --example-lang js --template doc/.template.hbs --files .docs.js index.js lib/* | sed -e 's/[ \t]*$//' -e 's/\\[\\ '//g' -e 's/'\\ \\]//g' > doc/readme.md" }, "dependencies": { "bluebird": "^3.5.5", - "joi": "^14.0.3", "lodash": "^4.17.5", "request": "^2.83.0", "request-promise": "^4.2.2" diff --git a/test/end-to-end/auth-client.js b/test/end-to-end/auth-client.js index b647e904..767aa1b9 100644 --- a/test/end-to-end/auth-client.js +++ b/test/end-to-end/auth-client.js @@ -4,11 +4,11 @@ const _ = require('lodash'); const test = require('ava'); const smartcar = require('../../'); -const {getAuthClientParams, runAuthFlow} = require('./helpers'); +const {getAuthClientParams, runAuthFlow, DEFAULT_SCOPES} = require('./helpers'); test('exchangeCode', async(t) => { const client = new smartcar.AuthClient(getAuthClientParams()); - const code = await runAuthFlow(client.getAuthUrl()); + const code = await runAuthFlow(client.getAuthUrl(DEFAULT_SCOPES)); const access = await client.exchangeCode(code); t.deepEqual( @@ -18,13 +18,13 @@ test('exchangeCode', async(t) => { 'refreshExpiration', 'refreshToken', ]), - [] + [], ); }); test('exchangeRefreshToken', async(t) => { const client = new smartcar.AuthClient(getAuthClientParams()); - const code = await runAuthFlow(client.getAuthUrl()); + const code = await runAuthFlow(client.getAuthUrl(DEFAULT_SCOPES)); const oldAccess = await client.exchangeCode(code); const newAccess = await client.exchangeRefreshToken(oldAccess.refreshToken); @@ -36,38 +36,14 @@ test('exchangeRefreshToken', async(t) => { 'refreshExpiration', 'refreshToken', ]), - [] + [], ); -}); - -test('isCompatible - no country set', async(t) => { - const client = new smartcar.AuthClient(getAuthClientParams()); - - const teslaVin = '5YJXCDE22HF068739'; - const audiVin = 'WAUAFAFL1GN014882'; - - const scopes = ['read_odometer', 'read_location']; - - const teslaComp = await client.isCompatible(teslaVin, scopes); - const audiComp = await client.isCompatible(audiVin, scopes); - - t.truthy(teslaComp); - t.falsy(audiComp); -}); - -test('isCompatible - country set', async(t) => { - const client = new smartcar.AuthClient(getAuthClientParams()); - - const teslaVin = '5YJXCDE22HF068739'; - const audiVin = 'WAUAFAFL1GN014882'; - const scopes = ['read_odometer', 'read_location']; - - const country = 'US'; - - const teslaComp = await client.isCompatible(teslaVin, scopes, country); - const audiComp = await client.isCompatible(audiVin, scopes, country); + const error = await t.throwsAsync( + client.exchangeRefreshToken(oldAccess.refreshToken) + ); + const expectedMessage = 'invalid_grant:undefined - Invalid or expired refresh token.'; + t.is(error.message, expectedMessage); - t.truthy(teslaComp); - t.falsy(audiComp); + t.is(error.type, 'invalid_grant'); }); diff --git a/test/end-to-end/helpers/index.js b/test/end-to-end/helpers/index.js index 53ce6533..88dedd68 100644 --- a/test/end-to-end/helpers/index.js +++ b/test/end-to-end/helpers/index.js @@ -11,18 +11,18 @@ const helpers = {}; /* eslint-disable no-process-env */ const HEADLESS = isCI || process.env.HEADLESS; -const CLIENT_ID = process.env.INTEGRATION_CLIENT_ID; -const CLIENT_SECRET = process.env.INTEGRATION_CLIENT_SECRET; +const CLIENT_ID = process.env.E2E_SMARTCAR_CLIENT_ID; +const CLIENT_SECRET = process.env.E2E_SMARTCAR_CLIENT_SECRET; /* eslint-enable */ if (!CLIENT_ID || !CLIENT_SECRET) { throw new Error( // eslint-disable-next-line max-len - '"INTEGRATION_CLIENT_ID" and "INTEGRATION_CLIENT_SECRET" environment variables must be set', + '"E2E_SMARTCAR_CLIENT_ID" and "E2E_SMARTCAR_CLIENT_SECRET" environment variables must be set', ); } -const DEFAULT_SCOPE = [ +helpers.DEFAULT_SCOPES = [ 'required:read_vehicle_info', 'required:read_location', 'required:read_odometer', @@ -35,11 +35,10 @@ const DEFAULT_SCOPE = [ 'required:read_tires', ]; -helpers.getAuthClientParams = (scope = DEFAULT_SCOPE) => ({ +helpers.getAuthClientParams = () => ({ clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, redirectUri: 'https://example.com/auth', - scope, testMode: true, }); @@ -56,7 +55,11 @@ const getCodeFromUri = function(uri) { } }; -helpers.runAuthFlow = async function(authUrl, brand = 'CHEVROLET') { +helpers.runAuthFlow = async function( + authUrl, + brand = 'CHEVROLET', + email = '' +) { const firefoxOptions = new firefox.Options(); const chromeOptions = new chrome.Options() .addArguments('disable-infobars') @@ -84,7 +87,7 @@ helpers.runAuthFlow = async function(authUrl, brand = 'CHEVROLET') { .click(); // Login - const email = `${uuid()}@email.com`; + email = email || `${uuid()}@email.com`; await driver.findElement(By.css('input[id=username]')).sendKeys(email); await driver.findElement(By.css('input[id=password')).sendKeys('password'); await driver.findElement(By.css('button[id=sign-in-button]')).click(); diff --git a/test/end-to-end/index.js b/test/end-to-end/index.js index bdbf1a59..1de6514f 100644 --- a/test/end-to-end/index.js +++ b/test/end-to-end/index.js @@ -1,22 +1,88 @@ 'use strict'; +const _ = require('lodash'); const test = require('ava'); const smartcar = require('../../'); -const {getAuthClientParams, runAuthFlow} = require('./helpers'); +const {getAuthClientParams, runAuthFlow, DEFAULT_SCOPES} = require('./helpers'); test.before(async(t) => { const client = new smartcar.AuthClient(getAuthClientParams()); - const code = await runAuthFlow(client.getAuthUrl()); + const code = await runAuthFlow(client.getAuthUrl(DEFAULT_SCOPES)); const {accessToken} = await client.exchangeCode(code); - t.context.accessToken = accessToken; + // t.context.accessToken = 'f14a1599-b5d9-4fe7-bff0-c890f837b7b4'; }); -test('getVehicleIds', async(t) => { - await t.notThrowsAsync(smartcar.getVehicleIds(t.context.accessToken)); +test('getVehicles', async(t) => { + const response = await smartcar.getVehicles(t.context.accessToken); + t.deepEqual( + _.xor(_.keys(response), [ + 'vehicles', + 'paging', + 'meta', + ]), + [], + ); + t.deepEqual(response.paging.offset, 0); + response.vehicles.forEach((vehicleId) => { + t.deepEqual(vehicleId.length, 36); + }); + t.deepEqual(response.meta.requestId.length, 36); }); -test('getUserId', async(t) => { - await t.notThrowsAsync(smartcar.getUserId(t.context.accessToken)); +test('getUser', async(t) => { + const response = await smartcar.getUser(t.context.accessToken); + t.deepEqual( + _.xor(_.keys(response), [ + 'id', + 'meta', + ]), + [], + ); + + t.deepEqual(response.id.length, 36); + t.deepEqual(response.meta.requestId.length, 36); +}); + +test('getCompatibility', async(t) => { + const {clientId, clientSecret} = getAuthClientParams(); + const teslaVin = '5YJXCDE22HF068739'; + const audiVin = 'WAUAFAFL1GN014882'; + + const scope = ['read_odometer', 'read_location']; + + const teslaComp = await smartcar.getCompatibility( + teslaVin, + scope, + null, + {clientId, clientSecret}, + ); + const audiComp = await smartcar.getCompatibility( + audiVin, + scope, + null, + {clientId, clientSecret}, + ); + + t.deepEqual( + _.xor(_.keys(teslaComp), [ + 'compatible', + 'meta', + ]), + [], + ); + + t.deepEqual( + _.xor(_.keys(audiComp), [ + 'compatible', + 'meta', + ]), + [], + ); + + t.truthy(teslaComp.compatible); + t.deepEqual(teslaComp.meta.requestId.length, 36); + t.falsy(audiComp.compatible); + t.deepEqual(audiComp.meta.requestId.length, 36); }); diff --git a/test/end-to-end/util.js b/test/end-to-end/util.js new file mode 100644 index 00000000..5388901a --- /dev/null +++ b/test/end-to-end/util.js @@ -0,0 +1,99 @@ +'use strict'; + +const test = require('ava'); + +const smartcar = require('../../'); +const SmartcarError = require('../../lib/smartcar-error'); +const {getAuthClientParams, runAuthFlow} = require('./helpers'); + +const getVehicleObject = async function(email, version = '') { + const client = new smartcar.AuthClient(getAuthClientParams()); + const code = await runAuthFlow( + client.getAuthUrl(['read_odometer'], {forcePrompt: true}), + 'CHEVROLET', + email + ); + const {accessToken} = await client.exchangeCode(code); + const {vehicles} = await smartcar.getVehicles(accessToken); + + return new smartcar.Vehicle(vehicles[0], accessToken, {version}); +}; + +test('handleError - SmartcarError V2 resolution string', async function(t) { + const description = 'The vehicle was unable to perform your request' + + ' due to an unknown issue.'; + + const vehicle = await getVehicleObject( + 'VEHICLE_STATE.UNKNOWN@smartcar.com' + ); + const error = await t.throwsAsync(vehicle.odometer()); + + t.true(error instanceof SmartcarError); + t.is(error.statusCode, 409); + t.is(error.resolution.type, 'RETRY_LATER'); + t.is(error.docURL, 'https://smartcar.com/docs/errors/v2.0/vehicle-state/#unknown'); + t.is(error.description, description); + t.is(error.type, 'VEHICLE_STATE'); + t.is(error.code, 'UNKNOWN'); + t.is(error.requestId.length, 36); + t.is(error.message, `VEHICLE_STATE:UNKNOWN - ${description}`); +}); + +test('handleError - SmartcarError V2 resolution null', async function(t) { + const description = 'This vehicle is no longer associated with the user\'s ' + + 'connected services account. Please prompt the user to re-add' + + ' the vehicle to their account.'; + + const vehicle = await getVehicleObject( + 'CONNECTED_SERVICES_ACCOUNT.VEHICLE_MISSING@smartcar.com' + ); + const error = await t.throwsAsync(vehicle.odometer()); + + t.true(error instanceof SmartcarError); + t.is(error.statusCode, 400); + t.is(error.resolution.type, null); + t.is(error.docURL, 'https://smartcar.com/docs/errors/v2.0/connected-services-account/#vehicle_missing'); + t.is(error.description, description); + t.is(error.type, 'CONNECTED_SERVICES_ACCOUNT'); + t.is(error.code, 'VEHICLE_MISSING'); + t.is(error.requestId.length, 36); + t.is(error.message, + `CONNECTED_SERVICES_ACCOUNT:VEHICLE_MISSING - ${description}` + ); +}); + +test('handleError - SmartcarError V1 error', async function(t) { + const vehicle = await getVehicleObject( + 'smartcar@vs-000.vehicle-state-error.com', + '1.0', + ); + const error = await t.throwsAsync(vehicle.odometer()); + + t.true(error instanceof SmartcarError); + t.is(error.statusCode, 409); + t.is(error.type, 'vehicle_state_error'); + t.is(error.code, 'VS_000'); + t.is(error.requestId.length, 36); + const expectedMessage = 'vehicle_state_error:VS_000 - ' + + 'Vehicle state cannot be determined.'; + t.is(error.message, expectedMessage); +}); + +test('handleError - SmartcarError V2 code null', async function(t) { + const description = 'Your application has insufficient permissions to access ' + + 'the requested resource. Please prompt the user to re-authenticate' + + ' using Smartcar Connect.'; + + const vehicle = await getVehicleObject(); + const error = await t.throwsAsync(vehicle.location()); + + t.true(error instanceof SmartcarError); + t.is(error.statusCode, 403); + t.is(error.resolution.type, 'REAUTHENTICATE'); + t.is(error.docURL, 'https://smartcar.com/docs/errors/v2.0/other-errors/#permission'); + t.is(error.description, description); + t.is(error.type, 'PERMISSION'); + t.is(error.code, undefined); + t.is(error.requestId.length, 36); + t.is(error.message, `PERMISSION:null - ${description}`); +}); diff --git a/test/end-to-end/vehicle.js b/test/end-to-end/vehicle.js index e33341f2..7e0bb629 100644 --- a/test/end-to-end/vehicle.js +++ b/test/end-to-end/vehicle.js @@ -1,117 +1,389 @@ 'use strict'; - +const _ = require('lodash'); const test = require('ava'); const smartcar = require('../../'); -const {getAuthClientParams, runAuthFlow} = require('./helpers'); +const {getOrThrowConfig} = require('../../lib/util'); + +const {getAuthClientParams, runAuthFlow, DEFAULT_SCOPES} = require('./helpers'); /** * Returns access token to a vehicle that has compatibility + permission to scope */ const getVehicle = async function(brand, scope) { - const client = new smartcar.AuthClient(getAuthClientParams(scope)); - const code = await runAuthFlow(client.getAuthUrl(), brand); + const client = new smartcar.AuthClient(getAuthClientParams()); + const code = await runAuthFlow(client.getAuthUrl(scope), brand); const {accessToken} = await client.exchangeCode(code); - const vehicleIds = await smartcar.getVehicleIds(accessToken); + const {vehicles} = await smartcar.getVehicles(accessToken); - return new smartcar.Vehicle(vehicleIds.vehicles[0], accessToken); + return new smartcar.Vehicle(vehicles[0], accessToken); }; test.before(async(t) => { const [volt, egolf] = await Promise.all([ - getVehicle('CHEVROLET', [ - 'required:read_vehicle_info', - 'required:read_location', - 'required:read_odometer', + getVehicle('CHEVROLET', DEFAULT_SCOPES), + getVehicle('VOLKSWAGEN', [ + 'required:control_charge', 'required:control_security', - 'required:read_vin', - 'required:read_fuel', - 'required:read_battery', - 'required:read_charge', - 'required:read_engine_oil', - 'required:read_tires', - ]), - getVehicle('VOLKSWAGEN', ['required:control_charge']), + ]), ]); smartcar.setApiVersion('1.0'); t.context = {volt, egolf}; }); -test('vehicle info', async(t) => { - await t.notThrowsAsync(t.context.volt.info()); +test('vehicle vin', async(t) => { + const response = await t.context.volt.vin(); + t.deepEqual( + _.xor(_.keys(response), [ + 'vin', + 'meta', + ]), + [], + ); + t.is(response.vin.length, 17); + t.is(response.meta.requestId.length, 36); }); -test('vehicle location', async(t) => { - await t.notThrowsAsync(t.context.volt.location()); +test('vehicle charge', async(t) => { + const response = await t.context.volt.charge(); + t.deepEqual( + _.xor(_.keys(response), [ + 'isPluggedIn', + 'state', + 'meta', + ]), + [], + ); + + t.truthy( + ['CHARGING', 'FULLY_CHARGED', 'NOT_CHARGING'].includes(response.state), + ); + t.truthy(typeof response.isPluggedIn === 'boolean'); + t.truthy(response.meta.dataAge instanceof Date); + t.is(response.meta.requestId.length, 36); }); -test('vehicle odometer', async(t) => { - await t.notThrowsAsync(t.context.volt.odometer()); +test('vehicle battery', async(t) => { + const response = await t.context.volt.battery(); + t.deepEqual( + _.xor(_.keys(response), [ + 'range', + 'percentRemaining', + 'meta', + ]), + [], + ); + + t.truthy(typeof response.range === 'number'); + t.truthy(response.percentRemaining >= 0 && response.percentRemaining <= 1); + t.truthy(response.meta.dataAge instanceof Date); + t.is(response.meta.requestId.length, 36); + t.is(response.meta.unitSystem, 'metric'); }); -test('vehicle fuel', async(t) => { - await t.notThrowsAsync(t.context.volt.fuel()); +test('vehicle batteryCapacity', async(t) => { + const response = await t.context.volt.batteryCapacity(); + t.deepEqual( + _.xor(_.keys(response), [ + 'capacity', + 'meta', + ]), + [], + ); + + t.truthy(typeof response.capacity === 'number'); + t.truthy(response.meta.dataAge instanceof Date); + t.is(response.meta.requestId.length, 36); }); -test('vehicle oil', async(t) => { - await t.notThrowsAsync(t.context.volt.oil()); +test('vehicle fuel', async(t) => { + const response = await t.context.volt.fuel(); + t.deepEqual( + _.xor(_.keys(response), [ + 'range', + 'percentRemaining', + 'amountRemaining', + 'meta', + ]), + [], + ); + + t.truthy(typeof response.range === 'number'); + t.truthy(typeof response.amountRemaining === 'number'); + t.truthy(response.percentRemaining >= 0 && response.percentRemaining <= 1); + t.truthy(response.meta.dataAge instanceof Date); + t.is(response.meta.requestId.length, 36); + t.is(response.meta.unitSystem, 'metric'); }); test('vehicle tire pressure', async(t) => { - await t.notThrowsAsync(t.context.volt.tirePressure()); + const keys = ['frontLeft', 'frontRight', 'backLeft', 'backRight']; + const response = await t.context.volt.tirePressure(); + t.deepEqual( + _.xor(_.keys(response), keys.concat(['meta'])), + [], + ); + + keys.forEach((key) => t.truthy(typeof response[key] === 'number')); + t.truthy(response.meta.dataAge instanceof Date); + t.is(response.meta.requestId.length, 36); + t.is(response.meta.unitSystem, 'metric'); }); -test('vehicle battery', async(t) => { - await t.notThrowsAsync(t.context.volt.battery()); +test('vehicle engine oil', async(t) => { + const response = await t.context.volt.engineOil(); + t.deepEqual( + _.xor(_.keys(response), [ + 'lifeRemaining', + 'meta', + ]), + [], + ); + + t.truthy(response.lifeRemaining >= 0 && response.lifeRemaining <= 1); + t.truthy(response.meta.dataAge instanceof Date); + t.is(response.meta.requestId.length, 36); }); -test('vehicle batteryCapacity', async(t) => { - await t.notThrowsAsync(t.context.volt.batteryCapacity()); +test('vehicle odometer', async(t) => { + const response = await t.context.volt.odometer(); + t.deepEqual( + _.xor(_.keys(response), [ + 'distance', + 'meta', + ]), + [], + ); + + t.truthy(typeof response.distance === 'number'); + t.truthy(response.meta.dataAge instanceof Date); + t.is(response.meta.requestId.length, 36); + t.is(response.meta.unitSystem, 'metric'); }); -test('vehicle charge', async(t) => { - await t.notThrowsAsync(t.context.volt.charge()); +test('vehicle location', async(t) => { + const response = await t.context.volt.location(); + t.deepEqual( + _.xor(_.keys(response), [ + 'longitude', + 'latitude', + 'meta', + ]), + [], + ); + + t.truthy(typeof response.longitude === 'number'); + t.truthy(typeof response.latitude === 'number'); + t.truthy(response.meta.dataAge instanceof Date); + t.is(response.meta.requestId.length, 36); }); -test('vehicle vin', async(t) => { - await t.notThrowsAsync(t.context.volt.vin()); + +test('vehicle attributes', async(t) => { + const response = await t.context.volt.attributes(); + t.deepEqual( + _.xor(_.keys(response), [ + 'make', + 'model', + 'year', + 'id', + 'meta', + ]), + [], + ); + + t.is(response.id.length, 36); + t.is(response.make, 'CHEVROLET'); + t.is(response.model, 'Volt'); + t.truthy(typeof response.year === 'number'); + t.is(response.meta.requestId.length, 36); +}); + +test('vehicle permissions', async(t) => { + const response = await t.context.volt.permissions(); + t.deepEqual( + _.xor(_.keys(response), [ + 'permissions', + 'meta', + 'paging', + ]), + [], + ); + + t.deepEqual( + _.xor( + response.permissions.map((item) => `required:${item}`), + DEFAULT_SCOPES, + ), + [], + ); + t.is(response.meta.requestId.length, 36); + t.is(response.paging.offset, 0); + t.is(response.paging.count, 10); +}); + +test('vehicle subscribe and unsubscribe - success', async(t) => { + const webhookId = getOrThrowConfig('E2E_SMARTCAR_WEBHOOK_ID'); + const amt = getOrThrowConfig('E2E_SMARTCAR_AMT'); + let response = await t.context.volt.subscribe(webhookId); + t.deepEqual( + _.xor(_.keys(response), [ + 'webhookId', + 'vehicleId', + 'meta', + ]), + [], + ); + t.is(response.vehicleId, t.context.volt.id); + t.is(response.webhookId, webhookId); + t.is(response.meta.requestId.length, 36); + + response = await t.context.volt.unsubscribe(amt, webhookId); + t.deepEqual( + _.xor(_.keys(response), [ + 'status', + 'meta', + ]), + [], + ); + + t.is(response.status, 'success'); + t.is(response.meta.requestId.length, 36); +}); + +test('vehicle subscribe - error', async(t) => { + const errorMessage = 'VALIDATION:null - Request invalid or malformed.' + + ' Please check for missing parameters,' + + ' spelling and casing mistakes, and other syntax issues.'; + const error = await t.throwsAsync(t.context.volt.subscribe('webhookID')); + t.is(error.requestId.length, 36); + t.is(error.statusCode, 400); + t.is(error.message, errorMessage); + t.is(error.type, 'VALIDATION'); +}); + +test('vehicle unsubscribe - error', async(t) => { + const errorMessage = 'AUTHENTICATION:null - The authorization header' + + ' is missing or malformed, or it contains invalid or' + + ' expired authentication credentials. Please check for missing parameters,' + + ' spelling and casing mistakes, and other syntax issues.'; + const error = await t.throwsAsync( + t.context.volt.unsubscribe('amt', 'webhookID'), + ); + t.is(error.requestId.length, 36); + t.is(error.statusCode, 401); + t.is(error.message, errorMessage); + t.is(error.type, 'AUTHENTICATION'); }); test('vehicle lock', async(t) => { - await t.notThrowsAsync(t.context.volt.lock()); + const response = await t.context.egolf.lock(); + t.deepEqual( + _.xor(_.keys(response), [ + 'status', + 'message', + 'meta', + ]), + [], + ); + + t.is(response.status, 'success'); + t.is(response.message, 'Successfully sent request to vehicle'); + t.is(response.meta.requestId.length, 36); }); test('vehicle unlock', async(t) => { - await t.notThrowsAsync(t.context.volt.unlock()); + const response = await t.context.egolf.unlock(); + t.deepEqual( + _.xor(_.keys(response), [ + 'status', + 'message', + 'meta', + ]), + [], + ); + + t.is(response.status, 'success'); + t.is(response.message, 'Successfully sent request to vehicle'); + t.is(response.meta.requestId.length, 36); }); test('vehicle startCharge', async(t) => { - await t.notThrowsAsync(t.context.egolf.startCharge()); + const response = await t.context.egolf.startCharge(); + t.deepEqual( + _.xor(_.keys(response), [ + 'status', + 'message', + 'meta', + ]), + [], + ); + + t.is(response.status, 'success'); + t.is(response.message, 'Successfully sent request to vehicle'); + t.is(response.meta.requestId.length, 36); }); test('vehicle stopCharge', async(t) => { - await t.notThrowsAsync(t.context.egolf.stopCharge()); + const response = await t.context.egolf.stopCharge(); + t.deepEqual( + _.xor(_.keys(response), [ + 'status', + 'message', + 'meta', + ]), + [], + ); + t.is(response.status, 'success'); + t.is(response.message, 'Successfully sent request to vehicle'); + t.is(response.meta.requestId.length, 36); }); test('vehicle batch', async(t) => { - await t.notThrowsAsync(t.context.volt.batch(['/odometer', '/location'])); -}); + const response = await t.context.volt.batch(['/odometer', '/location']); -test('vehicle permissions', async(t) => { - await t.notThrowsAsync(t.context.volt.permissions()); -}); + const odometer = response.odometer(); + t.deepEqual( + _.xor(_.keys(odometer), [ + 'distance', + 'meta', + ]), + [], + ); -test('vehicle has permission', async(t) => { - await t.notThrowsAsync(t.context.volt.hasPermissions('read_odometer')); -}); + t.truthy(typeof odometer.distance === 'number'); + t.truthy(odometer.meta.dataAge instanceof Date); + t.is(odometer.meta.requestId.length, 36); + t.is(odometer.meta.unitSystem, 'metric'); + t.truthy(Boolean(response)); -test('vehicle has permissions', async(t) => { - await t.notThrowsAsync( - t.context.volt.hasPermissions(['read_odometer', 'read_vehicle_info']), + const location = response.location(); + t.deepEqual( + _.xor(_.keys(location), [ + 'longitude', + 'latitude', + 'meta', + ]), + [], ); + + t.truthy(typeof location.longitude === 'number'); + t.truthy(typeof location.latitude === 'number'); + t.truthy(location.meta.dataAge instanceof Date); + t.is(location.meta.requestId.length, 36); }); test.after.always('vehicle disconnect', async(t) => { - await t.notThrowsAsync(t.context.volt.disconnect()); + const response = await t.context.volt.disconnect(); + t.deepEqual( + _.xor(_.keys(response), [ + 'status', + 'meta', + ]), + [], + ); + + t.is(response.status, 'success'); + t.is(response.meta.requestId.length, 36); }); diff --git a/test/unit/index.js b/test/unit/index.js index da21503e..e2853758 100644 --- a/test/unit/index.js +++ b/test/unit/index.js @@ -5,51 +5,40 @@ const nock = require('nock'); const smartcar = require('../../'); -test('isExpired - error', function(t) { +test('setApiVersion and getApiVersion', function(t) { + let vehicle = new smartcar.Vehicle(); + t.is(vehicle.version, '2.0'); - t.throws(() => smartcar.isExpired(1000), TypeError); - t.throws(() => smartcar.isExpired({}), TypeError); - t.throws(() => smartcar.isExpired('not a date'), TypeError); + smartcar.setApiVersion('4.0'); + t.is(smartcar.getApiVersion(), '4.0'); + // checking the old vehicle object has same version as before + t.is(vehicle.version, '2.0'); -}); - -test('isExpired - date', function(t) { - - let expiration; + vehicle = new smartcar.Vehicle(); + t.is(vehicle.version, '4.0'); - expiration = new Date(Date.now() - (60 * 1000)); - t.true(smartcar.isExpired(expiration)); - - expiration = new Date(Date.now() + (60 * 1000)); - t.false(smartcar.isExpired(expiration)); + smartcar.setApiVersion('2.0'); + t.is(vehicle.version, '4.0'); + vehicle = new smartcar.Vehicle(); + t.is(vehicle.version, '2.0'); }); -test('isExpired - string', function(t) { - - let expiration; - - expiration = new Date(Date.now() - (60 * 1000)).toISOString(); - t.true(smartcar.isExpired(expiration)); - - expiration = new Date(Date.now()).toISOString(); - t.true(smartcar.isExpired(expiration)); - - expiration = new Date(Date.now() + (60 * 1000)).toISOString(); - t.false(smartcar.isExpired(expiration)); - +test('hashChallenge', function(t) { + const res = smartcar.hashChallenge('amt', 'challenge'); + t.is(res, '9baf5a7464bd86740ad5a06e439dcf535a075022ed2c92d74efacf646d79328e'); }); -test('getVehicleIds - missing token', async function(t) { - - const err = await t.throwsAsync(smartcar.getVehicleIds(), TypeError); - t.is(err.message, '"token" argument must be a string'); - +test('verifyPayload', function(t) { + // eslint-disable-next-line max-len + const signature = '4c05a8da471f05156ad717baa4017acd13a3a809850b9ca7d3301dcaaa854f70'; + const res = smartcar.verifyPayload('amt', signature, {pizza: 'pasta'}); + t.true(res); }); -test('getVehicleIds - simple', async function(t) { +test('getVehicles - simple', async function(t) { - const n = nock('https://api.smartcar.com/v1.0/') + const n = nock('https://api.smartcar.com/v2.0/') .get('/vehicles') .matchHeader('Authorization', 'Bearer simple') .reply(200, { @@ -57,15 +46,14 @@ test('getVehicleIds - simple', async function(t) { paging: {count: 3, offset: 0}, }); - const res = await smartcar.getVehicleIds('simple'); + const res = await smartcar.getVehicles('simple'); t.is(res.vehicles.length, 3); t.true(n.isDone()); - }); -test('getVehicleIds - paging', async function(t) { +test('getVehicles - paging', async function(t) { - const n = nock('https://api.smartcar.com/v1.0/') + const n = nock('https://api.smartcar.com/v2.0/') .get('/vehicles') .query({limit: '1'}) .matchHeader('Authorization', 'Bearer token') @@ -74,50 +62,88 @@ test('getVehicleIds - paging', async function(t) { paging: {count: 1, offset: 0}, }); - const res = await smartcar.getVehicleIds('token', {limit: 1}); + const res = await smartcar.getVehicles('token', {limit: 1}); t.is(res.vehicles.length, 1); t.true(n.isDone()); - }); -test('getUserId', async function(t) { - - const n = nock('https://api.smartcar.com/v1.0/') +test('getUser', async function(t) { + const n = nock('https://api.smartcar.com/v2.0/') .get('/user') .matchHeader('Authorization', 'Bearer token') .reply(200, { id: 'userid', }); - const id = await smartcar.getUserId('token'); - t.is(id, 'userid'); + const response = await smartcar.getUser('token'); + t.is(response.id, 'userid'); t.true(n.isDone()); +}); +test('exports', function(t) { + t.true('SmartcarError' in smartcar); + t.true('Vehicle' in smartcar); + t.true('AuthClient' in smartcar); }); -test( - 'getUserId throws TypeError when token param not string', - async function(t) { +test('getCompatibility - client id and secret errors', async function(t) { + const vin = 'fake_vin'; + const scope = ['read_location', 'read_odometer']; + - const n = nock('https://api.smartcar.com/v1.0/') - .get('/user') - .matchHeader('Authorization', 'Bearer token') - .reply(200, { - id: 'userid', - }); + let error = await t.throwsAsync(smartcar.getCompatibility(vin, scope)); + t.is(error.message, 'SMARTCAR_CLIENT_ID not set or passed as arguments'); - try { - await smartcar.getUserId(1337); - } catch (err) { - t.is(err.name, 'TypeError'); - t.false(n.isDone()); - } + error = await t.throwsAsync( + smartcar.getCompatibility(vin, scope, 'US', {clientId: 'clientId'}), + ); + t.is(error.message, 'SMARTCAR_CLIENT_SECRET not set or passed as arguments'); +}); +test('getCompatibility - with flags, testModeCompatibilityLevel and override version', async function(t) { + const vin = 'fake_vin'; + const scope = ['read_location', 'read_odometer']; + const path = '/compatibility?vin=fake_vin&' + + 'scope=read_location%20read_odometer&country=US&' + + 'flags=test%3Atest&test_mode_compatibility_level=pizza&mode=test'; + const n = nock('https://api.smartcar.com/v6.6/') + .get(path) + .matchHeader('Authorization', 'Basic Y2xpZW50SWQ6Y2xpZW50U2VjcmV0') + .reply(200, { + pizza: 'pasta', + }); + + const response = await smartcar.getCompatibility(vin, scope, 'US', { + clientId: 'clientId', + clientSecret: 'clientSecret', + version: '6.6', + flags: {test: 'test'}, + testModeCompatibilityLevel: 'pizza', }); + t.is(response.pizza, 'pasta'); + t.true(n.isDone()); +}); -test('exports', function(t) { - t.true('errors' in smartcar); - t.true('Vehicle' in smartcar); - t.true('AuthClient' in smartcar); +test('getCompatibility - with testMode true', async function(t) { + const vin = 'fake_vin'; + const scope = ['read_location', 'read_odometer']; + const path = '/compatibility?vin=fake_vin&' + + 'scope=read_location%20read_odometer&country=US&mode=test'; + const n = nock('https://api.smartcar.com/v6.6/') + .get(path) + .matchHeader('Authorization', 'Basic Y2xpZW50SWQ6Y2xpZW50U2VjcmV0') + .reply(200, { + pizza: 'pasta', + }); + + const response = await smartcar.getCompatibility(vin, scope, 'US', { + clientId: 'clientId', + clientSecret: 'clientSecret', + version: '6.6', + testMode: true, + }); + + t.is(response.pizza, 'pasta'); + t.true(n.isDone()); }); diff --git a/test/unit/lib/auth-client.js b/test/unit/lib/auth-client.js index 2ee36c86..ca98e991 100644 --- a/test/unit/lib/auth-client.js +++ b/test/unit/lib/auth-client.js @@ -7,7 +7,6 @@ const nock = require('nock'); const AuthClient = require('../../../lib/auth-client'); const CLIENT_ID = '4cf82729-4275-46d9-9255-8437ba777151'; -const INVALID_CLIENT_ID = '4cf82729-4275-46d9-9255-87ba151'; const CLIENT_SECRET = '4cf82729-4275-46d9-9255-8437ba777151'; test('constructor', function(t) { @@ -15,75 +14,41 @@ test('constructor', function(t) { clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], }); t.is(client.clientId, CLIENT_ID); t.is(client.clientSecret, CLIENT_SECRET); t.is(client.redirectUri, 'https://insurance.co/callback'); - t.deepEqual(client.scope, ['read_odometer', 'read_vehicle_info']); t.is(client.testMode, false); - t.true('request' in client); + t.true('service' in client); }); -test('constructor - missing required parameter', function(t) { - t.throws( +test('constructor - client id, secret and redirect url errors', function(t) { + let error = t.throws( () => new AuthClient({ - clientId: 'f3266b17-961d-4295-8544-054c7bd94fbb', - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - }) + clientId: 'clientId', + clientSecret: 'clientSecret', + }), ); -}); - -test('constructor - invalid uuid parameter', function(t) { - t.throws( - () => - new AuthClient({ - clientId: INVALID_CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - }) - ); -}); + let message = 'SMARTCAR_REDIRECT_URI not set or passed as arguments'; + t.is(error.message, message); -test('constructor - invalid scope parameter', function(t) { - t.throws( + error = t.throws( () => new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: 'read_odometer', - }) + clientId: 'clientId', + }), ); -}); + message = 'SMARTCAR_CLIENT_SECRET not set or passed as arguments'; + t.is(error.message, message); -test('constructor - invalid development parameter', function(t) { - t.throws( + error = t.throws( () => - new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - development: 'truthsies', - }) - ); -}); - -test('iOS and Android redirect uri', function(t) { - t.notThrows( - () => - new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'sc4a1b01e5-0497-417c-a30e-6df6ba33ba46://callback', - scope: ['read_odometer', 'read_vehicle_info'], - }) + new AuthClient(), ); + message = 'SMARTCAR_CLIENT_ID not set or passed as arguments'; + t.is(error.message, message); }); test('getAuthUrl - simple', function(t) { @@ -91,10 +56,9 @@ test('getAuthUrl - simple', function(t) { clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], }); - const actual = client.getAuthUrl(); + const actual = client.getAuthUrl(['read_odometer', 'read_vehicle_info']); let expected = 'https://connect.smartcar.com/oauth/authorize?'; expected += `response_type=code&client_id=${CLIENT_ID}`; expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; @@ -105,165 +69,47 @@ test('getAuthUrl - simple', function(t) { t.is(actual, expected); }); -test('getAuthUrl - with vehicleInfo={...}', function(t) { - +test('getAuthUrl - with optional arguments', function(t) { const client = new AuthClient({ clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - }); - - const vehicleInfo = { - make: 'TESLA', - }; - - const actual = client.getAuthUrl({vehicleInfo}); - let expected = 'https://connect.smartcar.com/oauth/authorize?'; - expected += `response_type=code&client_id=${CLIENT_ID}`; - expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; - expected += '&approval_prompt=auto'; - expected += '&scope=read_odometer%20read_vehicle_info'; - expected += '&make=TESLA'; - expected += '&mode=live'; - - t.is(actual, expected); - -}); - -test('getAuthUrl - with incorrect vehicleInfo={...}', function(t) { - - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - }); - - const vehicleInfo = { - pizza: 'isGood', - }; - - const actual = client.getAuthUrl({vehicleInfo}); - - t.is(actual.includes('&pizza=isGood'), false); - -}); - - -test('getAuthUrl - no scope', function(t) { - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - }); - - const actual = client.getAuthUrl({ - scope: 'this should be ignored', - state: 'fakestate', - forcePrompt: true, - }); - - let expected = 'https://connect.smartcar.com/oauth/authorize?'; - expected += `response_type=code&client_id=${CLIENT_ID}`; - expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; - expected += '&approval_prompt=force'; - expected += '&state=fakestate'; - expected += '&mode=live'; - - t.is(actual, expected); -}); - -test('getAuthUrl - state & approval prompt', function(t) { - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - }); - - const actual = client.getAuthUrl({ - scope: 'this should be ignored', - state: 'fakestate', - forcePrompt: true, - }); - - let expected = 'https://connect.smartcar.com/oauth/authorize?'; - expected += `response_type=code&client_id=${CLIENT_ID}`; - expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; - expected += '&approval_prompt=force'; - expected += '&scope=read_odometer%20read_vehicle_info'; - expected += '&state=fakestate'; - expected += '&mode=live'; - - t.is(actual, expected); -}); - -test('getAuthUrl - test mode true', function(t) { - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], testMode: true, }); - const actual = client.getAuthUrl({ - scope: 'this should be ignored', - state: 'fakestate', - forcePrompt: true, - }); - + const actual = client.getAuthUrl( + ['read_odometer', 'read_vehicle_info'], + { + makeBypass: 'TESLA', + state: 'fakestate', + forcePrompt: true, + flags: {country: 'DE', flag: 'suboption'}, + } + ); let expected = 'https://connect.smartcar.com/oauth/authorize?'; expected += `response_type=code&client_id=${CLIENT_ID}`; expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; expected += '&approval_prompt=force'; expected += '&scope=read_odometer%20read_vehicle_info'; expected += '&state=fakestate'; + expected += '&make=TESLA'; + expected += '&flags=country%3ADE%20flag%3Asuboption'; expected += '&mode=test'; t.is(actual, expected); }); -test('getAuthUrl - test mode false', function(t) { - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - testMode: false, - }); - - const actual = client.getAuthUrl({ - scope: 'this should be ignored', - state: 'fakestate', - forcePrompt: true, - }); - - let expected = 'https://connect.smartcar.com/oauth/authorize?'; - expected += `response_type=code&client_id=${CLIENT_ID}`; - expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; - expected += '&approval_prompt=force'; - expected += '&scope=read_odometer%20read_vehicle_info'; - expected += '&state=fakestate'; - expected += '&mode=live'; - - t.is(actual, expected); -}); - -test('getAuthUrl - single select true', function(t) { +test('getAuthUrl - single select enabled true', function(t) { const client = new AuthClient({ clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], }); - const actual = client.getAuthUrl({ - scope: 'this should be ignored', + const actual = client.getAuthUrl(['read_odometer', 'read_vehicle_info'], { state: 'fakestate', forcePrompt: true, - singleSelect: true, + singleSelect: {enabled: true}, }); let expected = 'https://connect.smartcar.com/oauth/authorize?'; @@ -278,19 +124,17 @@ test('getAuthUrl - single select true', function(t) { t.is(actual, expected); }); -test('getAuthUrl - single select false', function(t) { +test('getAuthUrl - single select enabled false', function(t) { const client = new AuthClient({ clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], }); - const actual = client.getAuthUrl({ - scope: 'this should be ignored', + const actual = client.getAuthUrl(['read_odometer', 'read_vehicle_info'], { state: 'fakestate', forcePrompt: true, - singleSelect: false, + singleSelect: {enabled: false}, }); let expected = 'https://connect.smartcar.com/oauth/authorize?'; @@ -310,15 +154,13 @@ test('getAuthUrl - single select vin', function(t) { clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], }); const singleSelect = { vin: '01234567890123', }; - const actual = client.getAuthUrl({ - scope: 'this should be ignored', + const actual = client.getAuthUrl(['read_odometer', 'read_vehicle_info'], { state: 'fakestate', forcePrompt: true, singleSelect, @@ -338,195 +180,6 @@ test('getAuthUrl - single select vin', function(t) { t.is(actual, expected); }); -test('getAuthUrl - single select with junk information passed in', function(t) { - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - }); - - const actual = client.getAuthUrl({ - scope: 'this should be ignored', - state: 'fakestate', - forcePrompt: true, - singleSelect: 'alkdjfklsdjf', - }); - - let expected = 'https://connect.smartcar.com/oauth/authorize?'; - expected += `response_type=code&client_id=${CLIENT_ID}`; - expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; - expected += '&approval_prompt=force'; - expected += '&scope=read_odometer%20read_vehicle_info'; - expected += '&state=fakestate'; - expected += '&single_select=false'; - expected += '&mode=live'; - - t.is(actual, expected); -}); - -test('getAuthUrl - single select with only junk keys in object passed in', function(t) { - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - }); - - const actual = client.getAuthUrl({ - scope: 'this should be ignored', - state: 'fakestate', - forcePrompt: true, - singleSelect: {pizza: '123124'}, - }); - - let expected = 'https://connect.smartcar.com/oauth/authorize?'; - expected += `response_type=code&client_id=${CLIENT_ID}`; - expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; - expected += '&approval_prompt=force'; - expected += '&scope=read_odometer%20read_vehicle_info'; - expected += '&state=fakestate'; - expected += '&single_select=false'; - expected += '&mode=live'; - - t.is(actual, expected); -}); - -test('getAuthUrl - single select with valid and junk keys in object passed in', function(t) { - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - }); - - const actual = client.getAuthUrl({ - scope: 'this should be ignored', - state: 'fakestate', - forcePrompt: true, - singleSelect: { - pizza: '123124', - vin: '12345678901234', - }, - }); - - let expected = 'https://connect.smartcar.com/oauth/authorize?'; - expected += `response_type=code&client_id=${CLIENT_ID}`; - expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; - expected += '&approval_prompt=force'; - expected += '&scope=read_odometer%20read_vehicle_info'; - expected += '&state=fakestate'; - expected += '&single_select=true'; - expected += '&single_select_vin=12345678901234'; - expected += '&mode=live'; - - t.is(actual, expected); -}); - -test('getAuthUrl - excludes single select when singleSelect not passed in', function(t) { - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - }); - - const actual = client.getAuthUrl({ - scope: 'this should be ignored', - state: 'fakestate', - forcePrompt: true, - }); - - let expected = 'https://connect.smartcar.com/oauth/authorize?'; - expected += `response_type=code&client_id=${CLIENT_ID}`; - expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; - expected += '&approval_prompt=force'; - expected += '&scope=read_odometer%20read_vehicle_info'; - expected += '&state=fakestate'; - expected += '&mode=live'; - - t.is(actual, expected); -}); - -test('getAuthUrl - flags are included', function(t) { - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - }); - - const actual = client.getAuthUrl({ - scope: 'this should be ignored', - state: 'fakestate', - forcePrompt: true, - flags: ['country:DE', 'flag:suboption'], - }); - - let expected = 'https://connect.smartcar.com/oauth/authorize?'; - expected += `response_type=code&client_id=${CLIENT_ID}`; - expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; - expected += '&approval_prompt=force'; - expected += '&scope=read_odometer%20read_vehicle_info'; - expected += '&state=fakestate'; - expected += '&flags=country%3ADE%20flag%3Asuboption'; - expected += '&mode=live'; - - t.is(actual, expected); -}); - -test('getAuthUrl - deprecated development mode', function(t) { - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - development: true, - }); - - const actual = client.getAuthUrl({ - scope: 'this should be ignored', - state: 'fakestate', - forcePrompt: true, - }); - - let expected = 'https://connect.smartcar.com/oauth/authorize?'; - expected += `response_type=code&client_id=${CLIENT_ID}`; - expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; - expected += '&approval_prompt=force'; - expected += '&scope=read_odometer%20read_vehicle_info'; - expected += '&state=fakestate'; - expected += '&mode=test'; - - t.is(actual, expected); -}); - -test('getAuthUrl - deprecated development mode false', function(t) { - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - scope: ['read_odometer', 'read_vehicle_info'], - development: false, - }); - - const actual = client.getAuthUrl({ - scope: 'this should be ignored', - state: 'fakestate', - forcePrompt: true, - }); - - let expected = 'https://connect.smartcar.com/oauth/authorize?'; - expected += `response_type=code&client_id=${CLIENT_ID}`; - expected += '&redirect_uri=https%3A%2F%2Finsurance.co%2Fcallback'; - expected += '&approval_prompt=force'; - expected += '&scope=read_odometer%20read_vehicle_info'; - expected += '&state=fakestate'; - expected += '&mode=live'; - - t.is(actual, expected); -}); - test('exchangeCode', async function(t) { const client = new AuthClient({ clientId: CLIENT_ID, @@ -536,7 +189,7 @@ test('exchangeCode', async function(t) { /* eslint-disable camelcase */ const n = nock('https://auth.smartcar.com') - .post('/oauth/token', { + .post('/oauth/token?flags=pizza%3Apasta', { code: 'AUTHCODE', grant_type: 'authorization_code', redirect_uri: 'https://insurance.co/callback', @@ -553,7 +206,10 @@ test('exchangeCode', async function(t) { }); /* eslint-enable camelcase */ - const response = await client.exchangeCode('AUTHCODE'); + const response = await client.exchangeCode( + 'AUTHCODE', + {flags: {pizza: 'pasta'}}, + ); t.is(response.accessToken, 'access'); t.is(response.refreshToken, 'refresh'); @@ -572,7 +228,7 @@ test('exchangeRefreshToken', async function(t) { /* eslint-disable camelcase */ const n = nock('https://auth.smartcar.com') - .post('/oauth/token', { + .post('/oauth/token?flags=pizza%3Apasta', { refresh_token: 'TOKEN', grant_type: 'refresh_token', }) @@ -588,8 +244,10 @@ test('exchangeRefreshToken', async function(t) { }); /* eslint-enable camelcase */ - const response = await client.exchangeRefreshToken('TOKEN'); - + const response = await client.exchangeRefreshToken( + 'TOKEN', + {flags: {pizza: 'pasta'}}, + ); t.is(response.accessToken, 'access'); t.is(response.refreshToken, 'refresh'); @@ -597,30 +255,3 @@ test('exchangeRefreshToken', async function(t) { t.true(_.isDate(response.refreshExpiration)); t.true(n.isDone()); }); - -test('isCompatible - with scope', async function(t) { - const client = new AuthClient({ - clientId: CLIENT_ID, - clientSecret: CLIENT_SECRET, - redirectUri: 'https://insurance.co/callback', - }); - - const vin = 'fake_vin'; - const scope = ['read_location', 'read_odometer']; - - const n = nock('https://api.smartcar.com') - .get('/v1.0/compatibility') - .query({vin, scope: 'read_location read_odometer', country: 'US'}) - .basicAuth({ - user: CLIENT_ID, - pass: CLIENT_SECRET, - }) - .reply(200, { - compatible: true, - }); - - const response = await client.isCompatible(vin, scope); - - t.is(response, true); - t.true(n.isDone()); -}); diff --git a/test/unit/lib/errors.js b/test/unit/lib/errors.js deleted file mode 100644 index 69751e44..00000000 --- a/test/unit/lib/errors.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -const test = require('ava'); - -const errors = require('../../../lib/errors'); - -test('inheritance check', function(t) { - - Object.keys(errors).forEach(function(error) { - switch (error) { - case 'VehicleStateError': - t.true( - new errors[error]('Message', {code: 'VS_000'}) - instanceof errors.SmartcarError - ); - break; - default: - t.true(new errors[error]('Message') instanceof errors.SmartcarError); - } - }); - - t.true(new errors.SmartcarError() instanceof Error); - -}); - -test('message check', function(t) { - - Object.keys(errors).forEach(function(error) { - switch (error) { - case 'VehicleStateError': - t.regex(new errors[error]('R2D2', {code: 'VS_000'}).message, /R2D2/); - break; - case 'SmartcarErrorV2': - t.regex(new errors[error]('R2D2').description, /R2D2/); - const sampleError = { - type: '', - code: '', - description: '', - }; - t.is(new errors[error](sampleError).message, ': - '); - break; - default: - t.regex(new errors[error]('R2D2').message, /R2D2/); - } - }); - -}); diff --git a/test/unit/lib/util.js b/test/unit/lib/util.js index 08aed5f1..ee3dc04b 100644 --- a/test/unit/lib/util.js +++ b/test/unit/lib/util.js @@ -2,14 +2,14 @@ const _ = require('lodash'); const test = require('ava'); -const nock = require('nock'); const Promise = require('bluebird'); const {StatusCodeError} = require('request-promise/errors'); +const {env} = require('process'); const util = require('../../../lib/util'); const smartcar = require('../../../'); const config = require('../../../lib/config'); -const errors = require('../../../lib/errors'); +const SmartcarError = require('../../../lib/smartcar-error'); const API_URL = config.api + '/v' + config.version; @@ -51,7 +51,16 @@ test('formatAccess', function(t) { const rActual = access.refreshExpiration.getTime(); t.true(expected - 1000 <= actual && actual <= expected + 1000); t.true(rExpected - 1000 <= rActual && rActual <= rExpected + 1000); +}); + +test('getOrThrowConfig - success', function(t) { + env.PIZZA = 'PASTA'; + t.is(util.getOrThrowConfig('PIZZA'), 'PASTA'); +}); +test('getOrThrowConfig - error', function(t) { + const error = t.throws(() => (util.getOrThrowConfig('PASTA'))); + t.is(error.message, 'PASTA not set or passed as arguments'); }); test('getUrl - no args', function(t) { @@ -70,30 +79,10 @@ test('getUrl - id & endpoint', function(t) { }); test('getUrl - version 2.0', function(t) { - smartcar.setApiVersion('2.0'); - const url = util.getUrl('VID', 'odometer'); + const url = util.getUrl('VID', 'odometer', '2.0'); t.is(url, 'https://api.smartcar.com/v2.0/vehicles/VID/odometer'); }); -test('request - default opts', async function(t) { - const n = nock('https://mock.com') - .get('/test') - .matchHeader('accept', 'application/json') - .matchHeader( - 'user-agent', - /* eslint-disable-next-line max-len */ - /^Smartcar\/(\d+\.\d+\.\d+-[\w-]*) \((\w+); (\w+)\) Node.js v(\d+\.\d+\.\d+)$/ - ) - .reply(200, {test: 'data'}); - - const response = await util.request('https://mock.com/test'); - - t.is(typeof response, 'object'); - t.is(response.test, 'data'); - t.true(n.isDone()); - -}); - test('wrap', async function(t) { const not = util.wrap(Promise.reject(new Error('blah'))); @@ -104,241 +93,167 @@ test('wrap', async function(t) { }); -test('catch - ValidationError', async function(t) { - - const n = nock('https://mock.com') - .get('/validation') - .reply(400, { - error: 'validation_error', - message: 'password must be a string', - }); - - const err = await t.throwsAsync(util.request('https://mock.com/validation')); - const boxed = t.throws(() => util.catch(err)); - - t.true(boxed instanceof errors.ValidationError); - t.is(boxed.message, 'password must be a string'); - t.true(n.isDone()); - -}); - -test('catch - AuthenticationError', async function(t) { - - const n = nock('https://mock.com') - .get('/auth') - .reply(401, { - error: 'authentication_error', - message: 'invalid bearer header', - }); - - const err = await t.throwsAsync(util.request('https://mock.com/auth', { - auth: { - bearer: 'pizza', +test('handleError - non-json', function(t) { + const boxed = t.throws(() => util.handleError({ + statusCode: 504, + response: { + body: 'what', }, })); - const boxed = t.throws(() => util.catch(err)); - - t.true(boxed instanceof errors.AuthenticationError); - t.true(boxed.message.includes('invalid bearer header')); - t.true(n.isDone()); + t.true(boxed instanceof SmartcarError); + t.is(boxed.statusCode, 504); + t.is(boxed.message, 'what'); }); -test('catch - PermissionError', async function(t) { - - const n = nock('https://mock.com') - .get('/perm') - .reply(403, { - error: 'permission_error', - message: 'you shall not pass', - }); - - const err = await t.throwsAsync(util.request('https://mock.com/perm')); - const boxed = t.throws(() => util.catch(err)); - - t.true(boxed instanceof errors.PermissionError); - t.regex(boxed.message, /https:\/\/mock.com\/perm/); - t.true(n.isDone()); - -}); - -test('catch - ResourceNotFoundError', async function(t) { - - const n = nock('https://mock.com') - .get('/404') - .reply(404, { - error: 'resource_not_found_error', - message: 'wat', - }); - - const err = await t.throwsAsync(util.request('https://mock.com/404')); - const boxed = t.throws(() => util.catch(err)); - - t.true(boxed instanceof errors.ResourceNotFoundError); - t.regex(boxed.message, /https:\/\/mock.com\/404/); - t.true(n.isDone()); - -}); - -test('catch - VehicleStateError', async function(t) { - - const n = nock('https://mock.com') - .get('/state') - .reply(409, { - error: 'vehicle_state_error', - message: 'wat', - }); - - const err = await t.throwsAsync(util.request('https://mock.com/state', { - json: {ACTION: 'LOCK'}, +test('handleError - String/non-json body', function(t) { + const boxed = t.throws(() => util.handleError({ + statusCode: 500, + response: { + body: 'what', + headers: { + 'content-type': 'application/json', + }, + }, })); - const boxed = t.throws(() => util.catch(err)); - - t.true(boxed instanceof errors.VehicleStateError); - t.is(boxed.message, 'wat'); - t.true(n.isDone()); - -}); - -test('catch - RateLimitingError', async function(t) { - - const n = nock('https://mock.com') - .get('/ratelimit') - .reply(429, { - error: 'rate_limit_error', - message: 'wat', - }); - - const err = await t.throwsAsync(util.request('https://mock.com/ratelimit')); - const boxed = t.throws(() => util.catch(err)); - - t.true(boxed instanceof errors.RateLimitingError); - t.notRegex(boxed.message, /https:\/\/mock.com\/ratelimit/); - t.true(n.isDone()); - -}); - -test('catch - MonthlyLimitExceeded', async function(t) { - - const n = nock('https://mock.com') - .get('/monthly') - .reply(430, { - error: 'montly_limit_error', - message: 'wat', - }); - - const err = await t.throwsAsync(util.request('https://mock.com/monthly')); - const boxed = t.throws(() => util.catch(err)); - - t.true(boxed instanceof errors.MonthlyLimitExceeded); - t.notRegex(boxed.message, /https:\/\/mock.com\/monthly/); - t.true(n.isDone()); + t.true(boxed instanceof SmartcarError); + t.is(boxed.statusCode, 500); + t.is(boxed.message, 'SDK_ERROR:undefined - what'); + t.is(boxed.type, 'SDK_ERROR'); }); -test('catch - ServerError', async function(t) { - - const n = nock('https://mock.com') - .get('/server') - .reply(500, { - error: 'server_error', - message: 'wat', - }); - - const err = await t.throwsAsync(util.request('https://mock.com/server')); - const boxed = t.throws(() => util.catch(err)); +test('handleError - SmartcarError V1', function(t) { + const boxed = t.throws(() => util.handleError({ + statusCode: 600, + response: { + body: { + error: 'monkeys_on_mars', + message: 'yes, really', + }, + headers: { + 'content-type': 'application/json', + }, + }, + })); - t.true(boxed instanceof errors.ServerError); - t.is(boxed.message, 'Unexpected server error'); - t.true(n.isDone()); + t.true(boxed instanceof SmartcarError); + t.is(boxed.statusCode, 600); + t.is(boxed.message, 'monkeys_on_mars:undefined - yes, really'); + t.is(boxed.type, 'monkeys_on_mars'); }); -test('catch - VehicleNotCapableError', async function(t) { - const n = nock('https://mock.com') - .get('/notcap') - .reply(501, { - error: 'vehicle_not_capable_error', - message: 'wat', - }); - - const err = await t.throwsAsync(util.request('https://mock.com/notcap')); - const boxed = t.throws(() => util.catch(err)); +test('handleError - when bit-flips because of moon position', function(t) { + const boxed = t.throws(() => util.handleError({ + statusCode: 999, + response: { + body: { + random: 'testing', + }, + headers: { + 'content-type': 'application/json', + }, + }, + })); - t.true(boxed instanceof errors.VehicleNotCapableError); - t.regex(boxed.message, /https:\/\/mock.com\/notcap/); - t.true(n.isDone()); + t.true(boxed instanceof SmartcarError); + t.is(boxed.statusCode, 999); + t.is(boxed.message, 'SDK_ERROR:undefined - Unknown error'); + t.is(boxed.type, 'SDK_ERROR'); }); -test('catch - SmartcarNotCapableError', async function(t) { - const n = nock('https://mock.com') - .get('/notcap') - .reply(501, { - error: 'smartcar_not_capable_error', - message: 'wat', - }); - const err = await t.throwsAsync(util.request('https://mock.com/notcap')); - const boxed = t.throws(() => util.catch(err)); +test('handleError - SmartcarError V2 no resolution', function(t) { + const boxed = t.throws(() => util.handleError({ + statusCode: 500, + response: { + body: { + type: 'type', + code: 'code', + description: 'description', + resolution: null, + detail: null, + requestId: '123', + docURL: null, + statusCode: 500, + }, + headers: { + 'content-type': 'application/json', + }, + }, + })); - t.true(boxed instanceof errors.SmartcarNotCapableError); - t.is(boxed.message, 'wat'); - t.true(n.isDone()); + t.true(boxed instanceof SmartcarError); + t.is(boxed.statusCode, 500); + t.false('resolution' in boxed); + t.false('detail' in boxed); + t.false('docURL' in boxed); + t.is(boxed.description, 'description'); + t.is(boxed.type, 'type'); + t.is(boxed.code, 'code'); + t.is(boxed.requestId, '123'); + t.is(boxed.message, 'type:code - description'); }); -test('catch - SmartcarError', async function(t) { - - const n = nock('https://mock.com') - .get('/generic') - .reply(600, { - error: 'monkeys_on_mars', - message: 'yes, really', - }); - - const err = await t.throwsAsync(util.request('https://mock.com/generic')); - const boxed = t.throws(() => util.catch(err)); - - t.true(boxed instanceof errors.SmartcarError); - t.regex(boxed.message, /monkeys_on_mars/); - t.true(boxed.original instanceof StatusCodeError); - t.true(n.isDone()); - -}); +test('handleError - SmartcarError V2 resolution string', function(t) { + const boxed = t.throws(() => util.handleError({ + statusCode: 500, + response: { + body: { + type: 'type', + code: 'code', + description: 'description', + resolution: 'resolution', + requestId: '123', + statusCode: 500, + }, + headers: { + 'content-type': 'application/json', + }, + }, + })); -test.serial('catch - SmartcarErrorV2', async function(t) { - - const n = nock('https://api.smartcar.com/v2.0') - .get('/something') - .reply(500, { - type: 'type', - code: 'code', - description: 'description', - resolution: null, - detail: null, - requestId: '123', - docURL: null, - statusCode: 500, - }); - - const err = await t.throwsAsync(util.request('https://api.smartcar.com/v2.0/something')); - const boxed = t.throws(() => util.catch(err)); - - t.true(boxed instanceof errors.SmartcarErrorV2); + t.true(boxed instanceof SmartcarError); + t.is(boxed.statusCode, 500); + t.is(boxed.resolution.type, 'resolution'); + t.false('url' in boxed.resolution); + t.false('detail' in boxed); + t.false('docURL' in boxed); t.is(boxed.description, 'description'); - t.true(n.isDone()); - + t.is(boxed.type, 'type'); + t.is(boxed.code, 'code'); + t.is(boxed.requestId, '123'); + t.is(boxed.message, 'type:code - description'); }); -test.serial('catch - SmartcarErrorV2 - string response', async function(t) { - - const n = nock('https://api.smartcar.com/v2.0') - .get('/something') - .reply(500, 'just a string response'); - - const err = await t.throwsAsync(util.request('https://api.smartcar.com/v2.0/something')); - const boxed = t.throws(() => util.catch(err)); - - t.true(boxed instanceof errors.SmartcarErrorV2); - t.is(boxed.description, 'just a string response'); - t.true(n.isDone()); +test('handleError - SmartcarError V2 with all attrbutes', function(t) { + const boxed = t.throws(() => util.handleError({ + statusCode: 500, + response: { + body: { + type: 'type', + code: 'code', + description: 'description', + docURL: 'docURL', + resolution: {pizza: 'resolution'}, + requestId: '123', + statusCode: 500, + detail: ['pizza'], + }, + headers: { + 'content-type': 'application/json', + }, + }, + })); + t.true(boxed instanceof SmartcarError); + t.is(boxed.statusCode, 500); + t.is(boxed.resolution.pizza, 'resolution'); + t.is(boxed.docURL, 'docURL'); + t.is(boxed.description, 'description'); + t.is(boxed.type, 'type'); + t.is(boxed.code, 'code'); + t.is(boxed.requestId, '123'); + t.is(boxed.message, 'type:code - description'); + t.is(boxed.detail[0], 'pizza'); }); diff --git a/test/unit/lib/vehicle.js b/test/unit/lib/vehicle.js index 107aad2d..077ac45d 100644 --- a/test/unit/lib/vehicle.js +++ b/test/unit/lib/vehicle.js @@ -1,6 +1,5 @@ 'use strict'; -const _ = require('lodash'); const nock = require('nock'); const test = require('ava'); @@ -13,8 +12,8 @@ const TOKEN = '9ad942c6-32b8-4af2-ada6-5e8ecdbad9c2'; const vehicle = new Vehicle(VID, TOKEN); const nocks = { - base(vid = VID, token = TOKEN) { - return nock(`https://api.smartcar.com/v1.0/vehicles/${vid}`) + base(version = vehicle.version, vid = VID, token = TOKEN) { + return nock(`https://api.smartcar.com/v${version}/vehicles/${vid}`) .matchHeader('User-Agent', USER_AGENT) .matchHeader('Authorization', `Bearer ${token}`); }, @@ -26,591 +25,103 @@ test.afterEach(function(t) { } }); -test('constructor', async function(t) { +test('constructor - default parameters check', async function(t) { + const vehicle = new Vehicle(VID, TOKEN); t.context.n = nocks - .base() + .base(vehicle.version) .matchHeader('sc-unit-system', 'metric') .get('/default') - .reply(200, 'default'); + .reply(200, '{"pizza": "pasta"}'); - const vehicle = new Vehicle(VID, TOKEN); t.is(vehicle.id, VID); t.is(vehicle.token, TOKEN); - t.is(typeof vehicle.request, 'function'); t.is(vehicle.unitSystem, 'metric'); + t.is(vehicle.version, '2.0'); - const res = await vehicle.request('/default'); - t.is(res, 'default'); + const res = await vehicle.service.request('get', 'default'); + t.is(res.pizza, 'pasta'); }); -test('constructor - imperial', async function(t) { +test('constructor - non default unit and version', async function(t) { + const vehicle = new Vehicle(VID, TOKEN, { + unitSystem: 'imperial', + version: '4.4', + }); t.context.n = nocks - .base() + .base('4.4') .matchHeader('sc-unit-system', 'imperial') .get('/constructor/imperial') - .reply(200, 'imperial build'); + .reply(200, '{"pizza": "pasta"}'); - const vehicle = new Vehicle(VID, TOKEN, 'imperial'); t.is(vehicle.id, VID); t.is(vehicle.token, TOKEN); - t.is(typeof vehicle.request, 'function'); - t.is(vehicle.unitSystem, 'imperial'); - - const res = await vehicle.request('/constructor/imperial'); - t.is(res, 'imperial build'); -}); - -test('constructor - errors without new', function(t) { - const err = t.throws(() => Vehicle(VID, TOKEN), TypeError); - t.regex(err.message, /cannot be invoked without 'new'/); -}); - -test('constructor - errors for invalid unit', function(t) { - t.throws(() => Vehicle(VID, TOKEN), TypeError); -}); - -test('setUnitSystem - imperial', async function(t) { - t.context.n = nocks - .base() - .matchHeader('sc-unit-system', 'imperial') - .get('/unit/imperial') - .reply(200, 'imperial'); - - const vehicle = new Vehicle(VID, TOKEN); - vehicle.setUnitSystem('imperial'); t.is(vehicle.unitSystem, 'imperial'); - const res = await vehicle.request('/unit/imperial'); - t.is(res, 'imperial'); -}); - -test('setUnitSystem - metric', async function(t) { - t.context.n = nocks - .base() - .matchHeader('sc-unit-system', 'metric') - .get('/unit/metric') - .reply(200, 'metric'); - - const vehicle = new Vehicle(VID, TOKEN, 'imperial'); - vehicle.setUnitSystem('metric'); - t.is(vehicle.unitSystem, 'metric'); - - const res = await vehicle.request('/unit/metric'); - t.is(res, 'metric'); -}); - -test('setUnitSystem - error', function(t) { - const err = t.throws(() => vehicle.setUnitSystem('big'), TypeError); - t.regex(err.message, /unit/); -}); - -test('disconnect', async function(t) { - t.context.n = nocks - .base() - .delete('/application') - .reply(200, 'disconnect'); - - const response = await vehicle.disconnect(); - t.is(response, 'disconnect'); -}); - -test('permissions', async function(t) { - t.context.n = nocks - .base() - .get('/permissions') - .reply(200, { - permissions: ['permission1', 'permission2', 'permission3'], - }); - - const permissions = await vehicle.permissions(); - t.is(permissions.length, 3); -}); - -test('has permissions - single', async function(t) { - t.context.n = nocks - .base() - .get('/permissions') - .reply(200, { - permissions: ['permission1', 'permission2', 'permission3'], - }); - - const hasPermission = await vehicle.hasPermissions('required:permission1'); - - t.is(hasPermission, true); + const res = await vehicle.service.request('get', '/constructor/imperial'); + t.is(res.pizza, 'pasta'); }); -test('has permissions - multi', async function(t) { +test('vehicle webhook subscribe', async(t) => { + const responseBody = {webhookId: 'webhookID', vehicleId: 'vehicleId'}; t.context.n = nocks .base() - .get('/permissions') - .reply(200, { - permissions: ['permission1', 'permission2', 'permission3'], - }); + .post('/webhooks/webhookID') + .reply(200, responseBody, {'sc-request-id': 'requestId'}); - const hasPermissions = await vehicle.hasPermissions([ - 'permission1', - 'required:permission2', - ]); + const response = await vehicle.subscribe('webhookID'); - t.is(hasPermissions, true); + t.is(response.webhookId, 'webhookID'); + t.is(response.vehicleId, 'vehicleId'); + t.is(response.meta.requestId, 'requestId'); }); -test('has permissions - false', async function(t) { +test('vehicle webhook unsubscribe', async(t) => { t.context.n = nocks - .base() - .get('/permissions') - .reply(200, { - permissions: ['permission1', 'permission2', 'permission3'], - }); + .base(vehicle.version, VID, 'amt') + .delete('/webhooks/webhookID') + .reply(200, '', {'sc-request-id': 'requestId'}); - const hasPermission = await vehicle.hasPermissions('permission4'); + const response = await vehicle.unsubscribe('amt', 'webhookID'); - t.is(hasPermission, false); + t.is(response.meta.requestId, 'requestId'); }); -test('has permissions - multi false', async function(t) { +test('vehicle permissions', async(t) => { t.context.n = nocks .base() .get('/permissions') - .reply(200, { - permissions: ['permission1', 'permission2', 'permission3'], - }); - - const hasPermissions = await vehicle.hasPermissions([ - 'permission1', - 'permission4', - ]); - - t.is(hasPermissions, false); -}); - -test('info', async function(t) { - const body = { - id: 'id', - make: 'make', - model: 'model', - year: 1234, - }; - t.context.n = nocks - .base() - .get('/') - .reply(200, body); - - const response = await vehicle.info(); - t.deepEqual(response, body); -}); - -test('location', async function(t) { - const body = { - latitude: 1234, - longitude: 1234, - }; - const headers = { - 'sc-data-age': '2018-05-03T03:45:51+00:00', - }; - t.context.n = nocks - .base() - .get('/location') - .reply(200, body, headers); - - const response = await vehicle.location(); - t.deepEqual(response.data, body); - t.true(_.isDate(response.age)); - const expectedISOString = new Date(headers['sc-data-age']).toISOString(); - t.is(response.age.toISOString(), expectedISOString); -}); - -test('location - no age', async function(t) { - const body = { - latitude: 1234, - longitude: 1234, - }; - const headers = {}; - t.context.n = nocks - .base() - .get('/location') - .reply(200, body, headers); - - const response = await vehicle.location(); - t.deepEqual(response.data, body); - t.is(response.age, null); -}); - -test('odometer', async function(t) { - const body = { - distance: 1234, - }; - const headers = { - 'sc-data-age': '2018-05-03T03:45:51+00:00', - 'sc-unit-system': 'metric', - }; - t.context.n = nocks - .base() - .get('/odometer') - .reply(200, body, headers); - - const response = await vehicle.odometer(); - t.deepEqual(response.data, body); - t.true(_.isDate(response.age)); - const expectedISOString = new Date(headers['sc-data-age']).toISOString(); - t.is(response.age.toISOString(), expectedISOString); - t.is(response.unitSystem, headers['sc-unit-system']); -}); - -test('odometer - no age', async function(t) { - const body = { - distance: 1234, - }; - const headers = { - 'sc-unit-system': 'metric', - }; - t.context.n = nocks - .base() - .get('/odometer') - .reply(200, body, headers); - - const response = await vehicle.odometer(); - t.deepEqual(response.data, body); - t.is(response.age, null); - t.is(response.unitSystem, headers['sc-unit-system']); -}); - -test('fuel', async function(t) { - const body = { - range: 1234, - percentRemaining: 0.43, - amountRemaining: 7, - }; - const headers = { - 'sc-data-age': '2018-05-03T03:45:51+00:00', - 'sc-unit-system': 'metric', - }; - t.context.n = nocks - .base() - .get('/fuel') - .reply(200, body, headers); - - const response = await vehicle.fuel(); - t.deepEqual(response.data, body); - t.true(_.isDate(response.age)); - const expectedISOString = new Date(headers['sc-data-age']).toISOString(); - t.is(response.age.toISOString(), expectedISOString); - t.is(response.unitSystem, headers['sc-unit-system']); -}); - -test('fuel - no age', async function(t) { - const body = { - range: 1234, - percentRemaining: 0.43, - amountRemaining: 7, - }; - const headers = { - 'sc-unit-system': 'metric', - }; - t.context.n = nocks - .base() - .get('/fuel') - .reply(200, body, headers); - - const response = await vehicle.fuel(); - t.deepEqual(response.data, body); - t.is(response.age, null); - t.is(response.unitSystem, headers['sc-unit-system']); -}); - -test('oil', async function(t) { - const body = { - lifeRemaining: 0.86, - }; - const headers = { - 'sc-data-age': '2018-05-03T03:45:51+00:00', - }; - t.context.n = nocks - .base() - .get('/engine/oil') - .reply(200, body, headers); - - const response = await vehicle.oil(); - t.deepEqual(response.data, body); - t.true(_.isDate(response.age)); - const expectedISOString = new Date(headers['sc-data-age']).toISOString(); - t.is(response.age.toISOString(), expectedISOString); -}); - -test('oil - no age', async function(t) { - const body = { - lifeRemaining: 0.86, - }; - const headers = {}; - t.context.n = nocks - .base() - .get('/engine/oil') - .reply(200, body, headers); - - const response = await vehicle.oil(); - t.deepEqual(response.data, body); - t.is(response.age, null); -}); - -test('tire pressure', async function(t) { - const body = { - frontLeft: 33.0, - frontRight: 34.0, - backLeft: 33.0, - backRight: 33.0, - }; - const headers = { - 'sc-data-age': '2018-05-03T03:45:51+00:00', - 'sc-unit-system': 'imperial', - }; - t.context.n = nocks - .base() - .get('/tires/pressure') - .reply(200, body, headers); - - const response = await vehicle.tirePressure(); - t.deepEqual(response.data.tires, body); - t.true(_.isDate(response.age)); - const expectedISOString = new Date(headers['sc-data-age']).toISOString(); - t.is(response.age.toISOString(), expectedISOString); - t.is(response.unitSystem, headers['sc-unit-system']); -}); - -test('tire pressure - no age', async function(t) { - const body = { - frontLeft: 33.0, - frontRight: 34.0, - backLeft: 33.0, - backRight: 33.0, - }; - const headers = { - 'sc-unit-system': 'imperial', - }; - t.context.n = nocks - .base() - .get('/tires/pressure') - .reply(200, body, headers); - - const response = await vehicle.tirePressure(); - t.deepEqual(response.data.tires, body); - t.is(response.age, null); - t.is(response.unitSystem, headers['sc-unit-system']); -}); - -test('battery', async function(t) { - const body = { - range: 1234, - percentRemaining: 0.43, - }; - const headers = { - 'sc-data-age': '2018-05-03T03:45:51+00:00', - 'sc-unit-system': 'metric', - }; - t.context.n = nocks - .base() - .get('/battery') - .reply(200, body, headers); - - const response = await vehicle.battery(); - t.deepEqual(response.data, body); - t.true(_.isDate(response.age)); - const expectedISOString = new Date(headers['sc-data-age']).toISOString(); - t.is(response.age.toISOString(), expectedISOString); - t.is(response.unitSystem, headers['sc-unit-system']); -}); - -test('battery - no age', async function(t) { - const body = { - range: 1234, - percentRemaining: 0.43, - }; - const headers = { - 'sc-unit-system': 'metric', - }; - t.context.n = nocks - .base() - .get('/battery') - .reply(200, body, headers); - - const response = await vehicle.battery(); - t.deepEqual(response.data, body); - t.is(response.age, null); - t.is(response.unitSystem, headers['sc-unit-system']); -}); - -test('batteryCapacity', async function(t) { - const body = { - capacity: 24, - }; - const headers = { - 'sc-data-age': '2018-05-03T03:45:51+00:00', - 'sc-unit-system': 'metric', - }; - t.context.n = nocks - .base() - .get('/battery/capacity') - .reply(200, body, headers); - - const response = await vehicle.batteryCapacity(); - t.deepEqual(response.data, body); - t.true(_.isDate(response.age)); - const expectedISOString = new Date(headers['sc-data-age']).toISOString(); - t.is(response.age.toISOString(), expectedISOString); - t.is(response.unitSystem, headers['sc-unit-system']); -}); - -test('charge', async function(t) { - const body = { - isPluggedIn: true, - state: 'CHARGING', - }; - const headers = { - 'sc-data-age': '2018-05-03T03:45:51+00:00', - }; - t.context.n = nocks - .base() - .get('/charge') - .reply(200, body, headers); - - const response = await vehicle.charge(); - t.deepEqual(response.data, body); - t.true(_.isDate(response.age)); - const expectedISOString = new Date(headers['sc-data-age']).toISOString(); - t.is(response.age.toISOString(), expectedISOString); -}); - -test('charge - no age', async function(t) { - const body = { - isPluggedIn: true, - state: 'CHARGING', - }; - const headers = {}; - t.context.n = nocks - .base() - .get('/charge') - .reply(200, body, headers); - - const response = await vehicle.charge(); - t.deepEqual(response.data, body); - t.is(response.age, null); -}); - -test('vin', async function(t) { - const body = { - vin: '4JGBB8GB2AA537355', - }; - t.context.n = nocks - .base() - .get('/vin') - .reply(200, body); + .query({limit: '1'}) + .reply(200, {permissions: []}, {'sc-request-id': 'requestId'}); - const vin = await vehicle.vin(); - t.is(vin, body.vin); -}); - -test('lock', async function(t) { - t.context.nock = nocks - .base() - .post('/security', {action: 'LOCK'}) - .reply(200, {status: 'success'}); - - const response = await vehicle.lock(); - - t.deepEqual(_.xor(_.keys(response), ['status']), []); - t.is(response.status, 'success'); -}); - -test('unlock', async function(t) { - t.context.nock = nocks - .base() - .post('/security', {action: 'UNLOCK'}) - .reply(200, {status: 'success'}); - - const response = await vehicle.unlock(); - - t.deepEqual(_.xor(_.keys(response), ['status']), []); - t.is(response.status, 'success'); -}); - -test('startCharge', async function(t) { - t.context.nock = nocks - .base() - .post('/charge', {action: 'START'}) - .reply(200, {status: 'success'}); - - const response = await vehicle.startCharge(); + const response = await vehicle.permissions({limit: 1}); - t.deepEqual(_.xor(_.keys(response), ['status']), []); - t.is(response.status, 'success'); + t.is(response.meta.requestId, 'requestId'); + t.is(response.permissions.length, 0); + t.true(t.context.n.isDone()); }); -test('stopCharge', async function(t) { - t.context.nock = nocks - .base() - .post('/charge', {action: 'STOP'}) - .reply(200, {status: 'success'}); - - const response = await vehicle.stopCharge(); - - t.deepEqual(_.xor(_.keys(response), ['status']), []); - t.is(response.status, 'success'); -}); - -test('batch', async function(t) { - const paths = ['/odometer', '/transmission/fluid', '/fuel', '/sunroof']; +test('batch - success', async function(t) { + const paths = ['/odometer', '/engine/oil', '/location']; const requestBody = { requests: [ { path: '/odometer', }, { - path: '/transmission/fluid', - }, - { - path: '/fuel', + path: '/engine/oil', }, { - path: '/sunroof', + path: '/location', }, ], }; - const expected = { - '/odometer': { - headers: {'sc-unit-system': 'imperial'}, - code: 200, - body: { - distance: 32768, - }, - }, - '/transmission/fluid': { - headers: {'sc-unit-system': 'imperial'}, - code: 200, - body: { - temperature: 98.2, - wear: 0.5, - }, - }, - '/fuel': { - headers: {'sc-unit-system': 'imperial'}, - code: 200, - body: { - range: 550.8499755859375, - percentRemaining: 0.9449999928474426, - }, - }, - '/sunroof': { - headers: {'sc-unit-system': 'imperial'}, - code: 501, - body: { - error: 'vehicle_not_capable_error', - message: 'Vehicle is not capable of performing request.', - }, - }, - }; const mockResponse = { responses: [ { - headers: {'sc-unit-system': 'imperial'}, + headers: { + 'sc-unit-system': 'imperial', + 'sc-data-age': '2018-05-04T07:20:50.844Z', + }, path: '/odometer', code: 200, body: { @@ -618,26 +129,16 @@ test('batch', async function(t) { }, }, { - headers: {'sc-unit-system': 'imperial'}, - path: '/transmission/fluid', - code: 200, - body: { - temperature: 98.2, - wear: 0.5, - }, - }, - { - headers: {'sc-unit-system': 'imperial'}, - path: '/fuel', + headers: {'sc-data-age': '2018-05-04T07:20:50.844Z'}, + path: '/engine/oil', code: 200, body: { - range: 550.8499755859375, - percentRemaining: 0.9449999928474426, + lifeRemaining: 0.1123, }, }, { headers: {'sc-unit-system': 'imperial'}, - path: '/sunroof', + path: '/location', code: 501, body: { error: 'vehicle_not_capable_error', @@ -649,9 +150,54 @@ test('batch', async function(t) { t.context.n = nocks .base() .post('/batch', requestBody) - .reply(200, mockResponse); + .reply(200, mockResponse, {'sc-request-id': 'requestId'}); const response = await vehicle.batch(paths); - t.deepEqual(response, expected); + const odometer = response.odometer(); + t.is(odometer.distance, 32768); + t.is(odometer.meta.requestId, 'requestId'); + t.is(odometer.meta.unitSystem, 'imperial'); + t.is(odometer.meta.dataAge.valueOf(), 1525418450844); + + const engineOil = response.engineOil(); + t.is(engineOil.lifeRemaining, 0.1123); + t.is(engineOil.meta.dataAge.valueOf(), 1525418450844); + + const expectedMessage = 'vehicle_not_capable_error:undefined - ' + + 'Vehicle is not capable of performing request.'; + const error = t.throws(() => response.location()); + t.is(error.message, expectedMessage); + t.is(error.type, 'vehicle_not_capable_error'); +}); + +test('batch - error', async function(t) { + const paths = ['/odometer', '/engine/oil', '/location']; + const requestBody = { + requests: [ + { + path: '/odometer', + }, + { + path: '/engine/oil', + }, + { + path: '/location', + }, + ], + }; + + t.context.n = nocks + .base() + .post('/batch', requestBody) + .reply(500, { + error: 'monkeys_on_mars', + message: 'yes, really', + }, { + 'sc-request-id': 'requestId', + }); + + const error = await t.throwsAsync(vehicle.batch(paths)); + t.is(error.message, 'monkeys_on_mars:undefined - yes, really'); + t.is(error.type, 'monkeys_on_mars'); });