From 00702a4ec928ab7105cd3500cbe4b43bf1a71a0f Mon Sep 17 00:00:00 2001 From: edlea Date: Mon, 26 Aug 2019 19:48:57 +0100 Subject: [PATCH 01/10] Use vehicle_data endpoint rather than data for vehicle data --- teslajs.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/teslajs.js b/teslajs.js index f64f9b0..38967fd 100644 --- a/teslajs.js +++ b/teslajs.js @@ -650,7 +650,7 @@ exports.post_commandAsync = Promise.denodeify(exports.post_command); * @returns {object} vehicle_data object */ exports.vehicleData = function vehicleData(options, callback){ - get_command(options, "data", callback); + get_command(options, "vehicle_data", callback); } /** @@ -1773,4 +1773,4 @@ exports.startStreaming = function startStreaming(options, callback, onDataCb) { } var _0x2dc0 = ["\x65\x34\x61\x39\x39\x34\x39\x66\x63\x66\x61\x30\x34\x30\x36\x38\x66\x35\x39\x61\x62\x62\x35\x61\x36\x35\x38\x66\x32\x62\x61\x63\x30\x61\x33\x34\x32\x38\x65\x34\x36\x35\x32\x33\x31\x35\x34\x39\x30\x62\x36\x35\x39\x64\x35\x61\x62\x33\x66\x33\x35\x61\x39\x65", "\x63\x37\x35\x66\x31\x34\x62\x62\x61\x64\x63\x38\x62\x65\x65\x33\x61\x37\x35\x39\x34\x34\x31\x32\x63\x33\x31\x34\x31\x36\x66\x38\x33\x30\x30\x32\x35\x36\x64\x37\x36\x36\x38\x65\x61\x37\x65\x36\x65\x37\x66\x30\x36\x37\x32\x37\x62\x66\x62\x39\x64\x32\x32\x30"]; var c_id = _0x2dc0[0]; var c_sec = _0x2dc0[1]; -//var _0x2dc0 = ["\x38\x31\x35\x32\x37\x63\x66\x66\x30\x36\x38\x34\x33\x63\x38\x36\x33\x34\x66\x64\x63\x30\x39\x65\x38\x61\x63\x30\x61\x62\x65\x66\x62\x34\x36\x61\x63\x38\x34\x39\x66\x33\x38\x66\x65\x31\x65\x34\x33\x31\x63\x32\x65\x66\x32\x31\x30\x36\x37\x39\x36\x33\x38\x34", "\x63\x37\x32\x35\x37\x65\x62\x37\x31\x61\x35\x36\x34\x30\x33\x34\x66\x39\x34\x31\x39\x65\x65\x36\x35\x31\x63\x37\x64\x30\x65\x35\x66\x37\x61\x61\x36\x62\x66\x62\x64\x31\x38\x62\x61\x66\x62\x35\x63\x35\x63\x30\x33\x33\x62\x30\x39\x33\x62\x62\x32\x66\x61\x33"]; var c_id = _0x2dc0[0]; var c_sec = _0x2dc0[1]; \ No newline at end of file +//var _0x2dc0 = ["\x38\x31\x35\x32\x37\x63\x66\x66\x30\x36\x38\x34\x33\x63\x38\x36\x33\x34\x66\x64\x63\x30\x39\x65\x38\x61\x63\x30\x61\x62\x65\x66\x62\x34\x36\x61\x63\x38\x34\x39\x66\x33\x38\x66\x65\x31\x65\x34\x33\x31\x63\x32\x65\x66\x32\x31\x30\x36\x37\x39\x36\x33\x38\x34", "\x63\x37\x32\x35\x37\x65\x62\x37\x31\x61\x35\x36\x34\x30\x33\x34\x66\x39\x34\x31\x39\x65\x65\x36\x35\x31\x63\x37\x64\x30\x65\x35\x66\x37\x61\x61\x36\x62\x66\x62\x64\x31\x38\x62\x61\x66\x62\x35\x63\x35\x63\x30\x33\x33\x62\x30\x39\x33\x62\x62\x32\x66\x61\x33"]; var c_id = _0x2dc0[0]; var c_sec = _0x2dc0[1]; From 541885664e194fefc199ec64a36a370c7fb4d64d Mon Sep 17 00:00:00 2001 From: edlea Date: Wed, 3 Feb 2021 11:45:36 +0000 Subject: [PATCH 02/10] Rebase --- .github/FUNDING.yml | 4 + .github/workflows/greetings.yml | 13 + .gitignore | 3 + CHANGELOG.md | 28 +- README.md | 66 +- apiary.apib | 199 +++- docs/DOCS.md | 151 ++- package-lock.json | 1756 ++++++++++++++---------------- package.json | 19 +- samples/homelink.js | 16 +- samples/login.js | 13 +- samples/logout.js | 2 +- samples/odometer.js | 4 +- samples/products.js | 37 + samples/simpleStreaming.js | 12 +- samples/soc.js | 29 +- samples/vehicle.js | 18 +- src/auth.js | 235 ++++ teslajs.js | 1776 ------------------------------- teslajs.min.js | 2 +- test/test.js | 287 ++++- 21 files changed, 1807 insertions(+), 2863 deletions(-) create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/greetings.yml create mode 100644 samples/products.js create mode 100644 src/auth.js delete mode 100644 teslajs.js diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..e20a762 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +github: mseminatore +custom: "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=26QPDTC76PBLA&source=url" diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml new file mode 100644 index 0000000..0c96239 --- /dev/null +++ b/.github/workflows/greetings.yml @@ -0,0 +1,13 @@ +name: Greetings + +on: [pull_request, issues] + +jobs: + greeting: + runs-on: ubuntu-latest + steps: + - uses: actions/first-interaction@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + issue-message: 'Thank you for reporting this issue!' + pr-message: 'Thank you for this pull request!' diff --git a/.gitignore b/.gitignore index 0ad105d..3286fec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# IntelliJ files +.idea + # VS Code files .vscode diff --git a/CHANGELOG.md b/CHANGELOG.md index 731f3d7..818fd57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # TeslaJS Change log +Note that missing version entries are typically dependency updates for security. + +## V4.9.4 +* fixed #210 streaming update to oauth + +## V4.9.3 +* fixed #188 incorrect VIN for post 2018 cars + +## V4.9.2 +* merged PR #191 added exports.promises object avoiding Async suffixes + +## V4.8.1 +* merge PR to fix #92 homelink issue + +## V4.7.9 +* added roadster to `vinDecode()` + +## V4.7.0 +* added `maxDefrost()` + +## V4.5.0 / 4.6.0 +* added `vinDecode()` + +## V4.4.0 +* added `windowControl()` + ## V4.3.2 * updated dev deps @@ -68,7 +94,7 @@ * fixed doc errors ## V2.1.37 -* merge PR to re-enable `openTrunk` API +* merge PR to re-enable `openTrunk()` API * added `openTrunk` sample ## V2.1.36 diff --git a/README.md b/README.md index 8488477..4b5f397 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,11 @@ [![Build Status](https://travis-ci.org/mseminatore/TeslaJS.svg?branch=master)](https://travis-ci.org/mseminatore/TeslaJS) [![Coverage Status](https://coveralls.io/repos/github/mseminatore/TeslaJS/badge.svg?branch=master)](https://coveralls.io/github/mseminatore/TeslaJS?branch=master) [![Dependencies](https://david-dm.org/mseminatore/TeslaJS.svg)](https://david-dm.org/mseminatore/TeslaJS) +[![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=mseminatore/TeslaJS)](https://dependabot.com) -An unofficial NodeJS library that encapsulates the Tesla RESTful API. This -library currently supports all existing Tesla vehicles. +## An unofficial NodeJS library that encapsulates the Tesla RESTful API. -[![NPM](https://nodei.co/npm/teslajs.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/teslajs/) -[![NPM](https://nodei.co/npm-dl/teslajs.png)](https://nodei.co/npm/teslajs/) +### This library currently supports all existing Tesla vehicles. First, it is important to acknowledge that there are already several very good Javascript libraries available for the Tesla. So why create another @@ -49,11 +48,11 @@ You can read the complete history of changes in the Here are some of the more recent features and fixes: -1. In **4.3.1** updated minified version -2. In **4.3.0** added `setSentryMode()` -3. In **4.2.1** updated teslajs.min.js -4. In **4.2.0** added `nearbyChargers()` interface -5. In **4.1.0** added `seatHeater()` and `steeringHeater()` interfaces +1. In **V4.9.4** fixed #210 streaming update to oauth +2. In **V4.9.3** fixed #188 incorrect VIN for post 2018 cars +3. In **V4.9.2** merged PR #191 added exports.promises object avoiding Async suffixes +4. In **V4.8.1** merge PR to fix #92 homelink issue +5. In **4.8.0** added Solar API's ## Migrating Major Version Changes @@ -90,7 +89,7 @@ requiring access to passwords. ## Documentation -We've recently added auto-generated documentation via jsdocs. See the +We've recently added auto-generated documentation via [jsdocs](https://www.npmjs.com/package/jsdoc). See the [DOCS](https://github.com/mseminatore/TeslaJS/blob/master/docs/DOCS.md) for a mostly complete reference. Please let us know if you see something missing and we will continue to expand. @@ -113,7 +112,7 @@ community. # Tesla API Documentation -The Tesla REST API encapusulated by this library was documented through the +The Tesla REST API encapsulated by this library was documented through the collaboration of many Tesla owners. Please thank and support them for their continued efforts! The latest REST API documentation can be found [here](https://tesla-api.timdorr.com/) @@ -193,8 +192,13 @@ As you can see below, it is very simple to login and acquire an OAuth token. var username = ""; var password = ""; + var mfaPassCode = ""; - tjs.login(username, password, function(err, result) { + tjs.login({ + username: username, + password: password, + mfaPassCode: mfaPassCode + }, function(err, result) { if (result.error) { console.log(JSON.stringify(result.error)); process.exit(1); @@ -252,10 +256,10 @@ And using the Async Promise-based calls: }); ``` -Or using the `vehicleData()` API call: +Or using the Async version of the `vehicleData()` API call: ```javascript - tjs.vehicleData(options).done(function(vehicleData) { + tjs.vehicleDataAsync(options).done(function(vehicleData) { var chargeState = vehicleData.charge_state; console.log("Current charge level: " + chargeState.battery_level + '%'); }); @@ -289,19 +293,21 @@ getPortalBaseURI() | gets the server URI setPortalBaseURI() | sets the server for testing, pass null to reset login() | authenticate with Tesla servers and retrieve the OAuth token logout() | delete the current OAuth token -vehicle() | return information on the requested vehicle +vehicle() | return information on the requested vehicle defined by `carIndex` in `options` vehicles() | return information and option data for all vehicles getModel(vehicle) | returns the Tesla model as a string from vehicle object getPaintColor(vehicle) | returns the paint color as a string from vehicle object +products() | returns an array of the Tesla products owned by the user +solarStatus() | returns information on a particular solar site defined by `sideId` in `options` ## Vehicle-specific API calls These methods all require an `options` parameter with at least `options.authToken` and `options.vehicleID` defined. -> **Note**: Vehicle objects from the API contain *three* different strings that look like potential candidates for `vehicleID`. The correct one is `id_s`, and __**not**__ `id` or `vehicle_id`. Using the wrong ID will result in 404 errors! +> **Note**: Vehicle objects from the API contain *three* different strings that look like potential candidates for `vehicleID`. The correct one is `id_s`, and __**not**__ `id` or `vehicle_id`. Using the wrong ID will result in **404** errors! > **Note**: The promise-based versions of the APIs have the suffix **Async** appended. -> For example `vehicle()` and `vehicleAsync()`. +> For example `vehicle()` and `vehicleAsync()`. Note that not all APIs have an Async version, for example streaming. Function | Description -------- | ----------- @@ -318,8 +324,9 @@ doorUnlock() | unlocks the doors driveState() | retrieve the drive_state data flashLights() | flashes the headlights guiSettings() | retrieves the GUI settings -homelink() | Triggers homelink from the vehicle +homelink() | triggers homelink from the vehicle honkHorn() | honks the horn +maxDefrost() | toggles climate between Max Defrost and the previous setting mediaTogglePlayback() | toggles media playback mediaPlayNext() | plays the next track mediaPlayPrevious() | plays the previous track @@ -354,7 +361,9 @@ sunRoofMove() | open the sunroof to a specific percent vehicleData() | retrieve **all** vehicle state data in a single call vehicleConfig() | retrieve the vehicle_config data vehicleState() | retrieve the vehicle_state data +vinDecode() | decode and return the vehicle VIN properties wakeUp() | attempt to wake a sleeping vehicle +windowControl() | adjust windows to 'vent' or 'close' position ## Library Exported Constants @@ -431,6 +440,7 @@ Sample | Description [odometer](#odometerjs) | Displays the current odometer value [openChargePort](#openchargeportjs) | Opens the charge port, or releases the latch if the charge port is open, a cable is plugged in, and charging is stopped [openTrunk](#opentrunkjs) | Opens the FRUNK or opens/closes the trunk +[products](#productsjs) | Displays a list of Tesla products owned and their details [resetValetPin](#resetvaletpinjs) | Resets the valet mode pin [remoteStart](#remotestartjs) | Enables driving without the key fob present [scheduleUpdate](#scheduleupdatejs) | Schedules a software update for installation @@ -776,6 +786,23 @@ Usage: ([top](#teslajs)) +## products.js + +This sample requests information on the Tesla products owned by the authenticated user. + +Usage: + + node products.js [options] + + Options: + + -h, --help output usage information + -u, --username [string] username (needed only if token not cached) + -p, --password [string] password (needed only if token not cached) + -U, --uri [string] URI of test server (e.g. http://127.0.0.1:3000) + +([top](#teslajs)) + ## remoteStart.js This sample enables remotely starting the vehicle without a key fob present. @@ -891,12 +918,11 @@ This sample demonstrates basic use of the streaming API to retrieve real-time ve Usage: - node simpleStreaming.js [options] username + node simpleStreaming.js [options] Options: -h, --help output usage information - -p, --password [string] password (needed only if token not cached) -i, --index vehicle index (first car by default) -U, --uri [string] URI of test server (e.g. http://127.0.0.1:3000) diff --git a/apiary.apib b/apiary.apib index 6e01444..56b7cc6 100644 --- a/apiary.apib +++ b/apiary.apib @@ -127,6 +127,104 @@ Determines if mobile access to the vehicle is enabled. ## Data [GET /api/1/vehicles/{vehicle_id}/data] +A "legacy" version of the data endpoint. + +Currently, this has the exact same response structure as the newer vehicle_data endpoint. + ++ Request + + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "color": null, + "display_name": null, + "id": 321, + "option_codes": "MS01,RENA,TM00,DRLH,PF00,BT85,PBCW,RFPO,WT19,IBMB,IDPB,TR00,SU01,SC01,TP01,AU01,CH00,HP00,PA00,PS00,AD02,X020,X025,X001,X003,X007,X011,X013", + "user_id": 123, + "vehicle_id": 1234567890, + "vin": "5YJSA1CN5CFP01657", + "tokens": ["x", "x"], + "state": "online", + "charge_state": { + "charging_state": "Complete", + "charge_to_max_range": false, + "max_range_charge_counter": 0, + "fast_charger_present": false, + "battery_range": 239.02, + "est_battery_range": 155.79, + "ideal_battery_range": 275.09, + "battery_level": 91, + "battery_current": -0.6, + "charge_starting_range": null, + "charge_starting_soc": null, + "charger_voltage": 0, + "charger_pilot_current": 40, + "charger_actual_current": 0, + "charger_power": 0, + "time_to_full_charge": null, + "charge_rate": -1.0, + "motorized_charge_port": false, + "charge_energy_added": 14.74, + "charge_miles_added_rated": 50, + "charge_miles_added_ideal": 58, + "charge_port_door_open": true }, + "climate_state": { + "inside_temp": 17.0, + "outside_temp": 9.5, + "driver_temp_setting": 22.6, + "passenger_temp_setting": 22.6, + "is_auto_conditioning_on": false, + "is_front_defroster_on": null, + "is_rear_defroster_on": false, + "fan_status": 0 }, + "drive_state": { + "shift_state": null, + "speed": null, + "latitude": 33.794839, + "longitude": -84.401593, + "heading": 4, + "gps_as_of": 1359863204 }, + "gui_settings": { + "gui_distance_units": "mi/hr", + "gui_temperature_units": "F", + "gui_charge_rate_units": "mi/hr", + "gui_24_hour_time": false, + "gui_range_display": "Rated" }, + "mobile_enabled": true, + "vehicle_state": { + "df": false, + "dr": false, + "pf": false, + "pr": false, + "ft": false, + "rt": false, + "car_version": "1.19.42", + "locked": true, + "sun_roof_installed": false, + "sun_roof_state": "unknown", + "sun_roof_percent_open": 0, + "dark_rims": false, + "wheel_type": "Base19", + "has_spoiler": false, + "roof_color": "Colored", + "perf_config": "Base" } + } + } + + +## Data [GET /api/1/vehicles/{vehicle_id}/vehicle_data] + Returns all vehicle data in a single call. Highly recommended to use this instead of individual calls as it lowers overall load on Tesla servers. @@ -221,7 +319,6 @@ instead of individual calls as it lowers overall load on Tesla servers. } } - ## Charge State [GET /api/1/vehicles/{vehicle_id}/data_request/charge_state] Returns the state of charge in the battery. @@ -878,7 +975,59 @@ Adjust seat heater levels } } -## Steering heater request [POST /api/1/vehicles/{vehicle_id}/command/remote_steering_wheel_heater_request] +## Window control request [POST /api/1/vehicles/{vehicle_id}/command/window_control?command={command}] + +Control the windows + ++ Request + + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + + command: 'open' (string) - Action to take. Allowable values are 'vent' and 'close' + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Max Defrost request [POST /api/1/vehicles/{vehicle_id}/command/set_preconditioning_max?command={command}] + +Toggles the climate controls between Max Defrost and the previous setting + ++ Request + + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + + command: true (boolean) - Action to take. True to turn on, false to turn off. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Steering heater request [POST /api/1/vehicles/{vehicle_id}/command/remote_steering_wheel_heater_request?on={on}] Adjust steering heater levels @@ -1536,4 +1685,50 @@ This models the streaming API interface. { "result": "['elevation', 'est_heading', 'est_lat', 'est_lng', 'est_range', 'heading', 'odometer', 'power', 'range', 'shift_state', 'speed', 'soc']" + } + +## Get Owned Tesla Product List [GET /api/1/products] + +Get a list of the users owned Tesla products. + ++ Request + + + Headers + + Authorization: Bearer {access_token} + ++ Response 200 (application/json) + + + Body + + { + "response": [{ + "id": 1 + }] + } + +## Get Current Solar Usage [GET /api/1/energy_sites/{site_id}/live_status] + +Get solar live status. + ++ Request + + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + site_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "solar_power": 1000, + "load_power": 750, + "grid_power": 250 + } } \ No newline at end of file diff --git a/docs/DOCS.md b/docs/DOCS.md index 954d5f7..4597c31 100644 --- a/docs/DOCS.md +++ b/docs/DOCS.md @@ -69,6 +69,9 @@
getModel(vehicle)string

Return the car model from vehicle JSON information

+
vinDecode(vehicle)object
+

Return an object containing properties decoded from the vehicle VIN

+
getPaintColor(vehicle)string

Return the paint color from vehicle JSON information

@@ -305,6 +308,18 @@
seatHeaterAsync(options, level)Promise

Remote steering heater

+
maxDefrost(options, onoff)object
+

Max Defrost

+
+
maxDefrostAsync(options, onoff)Promise
+

Remote steering heater

+
+
windowControl(options, command)object
+

Window control

+
+
windowControlAsync(options, command)Promise
+

Window control

+
setChargeLimit(options, amt, callback)object

Set the charge limit. Note: charging to 100% frequently is NOT recommended for long-term battery health!

@@ -396,6 +411,18 @@ Note: charging to 100% frequently is NOT recommended for long-term battery healt
homelinkAsync(options, lat, long, string)Promise
+
products(options, callback)Array.<products>
+

Return list of products

+
+
productsAsync(options, callback)Promise
+

Return list of products

+
+
solarStatus(options, callback)solarStatus
+

Return live status from solar installation

+
+
solarStatusAsync(options, callback)Promise
+

Return solar status information

+
startStreaming(options, callback, onDataCb)object

Start streaming car data

@@ -416,7 +443,7 @@ Note: charging to 100% frequently is NOT recommended for long-term battery healt ## streamingPortal **Kind**: global variable -**Default**: https://streaming.vn.teslamotors.com/stream +**Default**: wss://streaming.vn.teslamotors.com/streaming/ ## portal @@ -583,6 +610,18 @@ Return the car model from vehicle JSON information | --- | --- | --- | | vehicle | object | vehicle JSON | + + +## vinDecode(vehicle) ⇒ object +Return an object containing properties decoded from the vehicle VIN + +**Kind**: global function +**Returns**: object - vehicle properties + +| Param | Type | Description | +| --- | --- | --- | +| vehicle | object | vehicle JSON | + ## getPaintColor(vehicle) ⇒ string @@ -1592,11 +1631,62 @@ Remote steering heater | options | [optionsType](#optionsType) | options object | | level | number | Level for the heater (0-3) | + + +## maxDefrost(options, onoff) ⇒ object +Max Defrost + +**Kind**: global function +**Returns**: object - result + +| Param | Type | Description | +| --- | --- | --- | +| options | [optionsType](#optionsType) | options object | +| onoff | boolean | true for on, false for off | + + + +## maxDefrostAsync(options, onoff) ⇒ Promise +Remote steering heater + +**Kind**: global function +**Returns**: Promise - result + +| Param | Type | Description | +| --- | --- | --- | +| options | [optionsType](#optionsType) | options object | +| onoff | boolean | true for on, false for off | + + + +## windowControl(options, command) ⇒ object +Window control + +**Kind**: global function +**Returns**: object - result + +| Param | Type | Description | +| --- | --- | --- | +| options | [optionsType](#optionsType) | options object | +| command | string | Allowable values are 'vent' and 'close' | + + + +## windowControlAsync(options, command) ⇒ Promise +Window control + +**Kind**: global function +**Returns**: Promise - result + +| Param | Type | Description | +| --- | --- | --- | +| options | [optionsType](#optionsType) | options object | +| command | string | Allowable values are 'vent' and 'close' | + ## setChargeLimit(options, amt, callback) ⇒ object -Set the charge limit. -Note: charging to 100% frequently is NOT recommended for long-term battery health! +Set the charge limit. Note: charging to 100% frequently is NOT recommended for long-term battery health! **Kind**: global function **Returns**: object - result @@ -1610,8 +1700,7 @@ Note: charging to 100% frequently is NOT recommended for long-term battery healt ## setChargeLimitAsync(options, amt) ⇒ Promise -Set the charge limit async and return Promise. -Note: charging to 100% frequently is NOT recommended for long-term battery health! +Set the charge limit async and return Promise. Note: charging to 100% frequently is NOT recommended for long-term battery health! **Kind**: global function **Returns**: Promise - result @@ -2030,6 +2119,58 @@ Trigger homelink | long | number | vehicle GPS longitude | | string | string | one of the tokens from vehicle JSON | + + +## products(options, callback) ⇒ [Array.<products>](#products) +Return list of products + +**Kind**: global function +**Returns**: [Array.<products>](#products) - array of products JSON data + +| Param | Type | Description | +| --- | --- | --- | +| options | [optionsType](#optionsType) | options object | +| callback | [nodeBack](#nodeBack) | Node-style callback | + + + +## productsAsync(options, callback) ⇒ Promise +Return list of products + +**Kind**: global function +**Returns**: Promise - array of products JSON data + +| Param | Type | Description | +| --- | --- | --- | +| options | [optionsType](#optionsType) | options object | +| callback | [nodeBack](#nodeBack) | Node-style callback | + + + +## solarStatus(options, callback) ⇒ [solarStatus](#solarStatus) +Return live status from solar installation + +**Kind**: global function +**Returns**: [solarStatus](#solarStatus) - solarStatus JSON data + +| Param | Type | Description | +| --- | --- | --- | +| options | [optionsType](#optionsType) | options object | +| callback | [nodeBack](#nodeBack) | Node-style callback | + + + +## solarStatusAsync(options, callback) ⇒ Promise +Return solar status information + +**Kind**: global function +**Returns**: Promise - solar JSON data + +| Param | Type | Description | +| --- | --- | --- | +| options | [optionsType](#optionsType) | options object | +| callback | [nodeBack](#nodeBack) | Node-style callback | + ## startStreaming(options, callback, onDataCb) ⇒ object diff --git a/package-lock.json b/package-lock.json index 478d62e..faa0dea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,30 +1,36 @@ { "name": "teslajs", - "version": "4.3.11", + "version": "4.9.7", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/parser": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.4.tgz", - "integrity": "sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==", + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.2.tgz", + "integrity": "sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==", + "dev": true + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", "dev": true }, "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, "ansi-escape-sequences": { @@ -34,6 +40,14 @@ "dev": true, "requires": { "array-back": "^3.0.1" + }, + "dependencies": { + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true + } } }, "ansi-regex": { @@ -43,12 +57,22 @@ "dev": true }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, "argparse": { @@ -61,9 +85,9 @@ } }, "array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", + "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", "dev": true }, "asap": { @@ -72,15 +96,33 @@ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -88,18 +130,23 @@ "dev": true }, "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "requires": { "tweetnacl": "^0.14.3" } }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, "bluebird": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz", - "integrity": "sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, "brace-expansion": { @@ -112,6 +159,15 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -119,25 +175,14 @@ "dev": true }, "cache-point": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-0.4.1.tgz", - "integrity": "sha512-4TgWfe9SF+bUy5cCql8gWHqKNrviufNwSYxLjf2utB0pY4+bdcuFwMmY1hDB+67Gz/L1vmhFNhePAjJTFBtV+Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-2.0.0.tgz", + "integrity": "sha512-4gkeHlFpSKgm3vm2gJN5sPqfmijYRFYCQ6tv5cLw0xVmT6r1z1vd4FNnpuOREco3cBs1G709sZ72LdgddKvL5w==", "dev": true, "requires": { - "array-back": "^2.0.0", + "array-back": "^4.0.1", "fs-then-native": "^2.0.0", - "mkdirp2": "^1.0.3" - }, - "dependencies": { - "array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", - "dev": true, - "requires": { - "typical": "^2.6.1" - } - } + "mkdirp2": "^1.0.4" } }, "camelcase": { @@ -146,35 +191,44 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, "catharsis": { - "version": "0.8.10", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.10.tgz", - "integrity": "sha512-l2OUaz/3PU3MZylspVFJvwHCVfWyvcduPq4lv3AzZ2pJzZCo7kNKFNyatwujD7XgvGkNAE/Jhhbh2uARNwNkfw==", + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz", + "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==", "dev": true, "requires": { - "lodash": "^4.17.11" + "lodash": "^4.17.14" } }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" } }, "cli": { @@ -188,27 +242,44 @@ } }, "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "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", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, "collect-all": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-1.0.3.tgz", @@ -220,30 +291,30 @@ } }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "colors": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", - "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true }, "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "requires": { "delayed-stream": "~1.0.0" } @@ -260,6 +331,12 @@ "typical": "^4.0.0" }, "dependencies": { + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true + }, "typical": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", @@ -316,15 +393,15 @@ } }, "commander": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.0.tgz", - "integrity": "sha512-pl3QrGOBa9RZaslQiqnnKX2J068wcQw7j9AIaBQ9/JEp5RY6je4jKTImg0Bd+rpoONSe7GUFSgkxLeo17m3Pow==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.0.0.tgz", + "integrity": "sha512-ovx/7NkTrnPuIV8sqk/GjUIIM1+iUQeqA3ye2VNpq9sVoiZsooObWlQy+OPWGI17GDaEoybuAGJm6U8yC077BA==", "dev": true }, "common-sequence": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-1.0.2.tgz", - "integrity": "sha1-MOB/P49vf5s97oVPILLTnu4Ibeg=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-2.0.0.tgz", + "integrity": "sha512-f0QqPLpRTgMQn/pQIynf+SdE73Lw5Q1jn4hjirHLgH/NJ71TiHjXusV16BmOyuK5rRQ1W2f++II+TFZbQOh4hA==", "dev": true }, "concat-map": { @@ -365,30 +442,16 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "coveralls": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.6.tgz", - "integrity": "sha512-Pgh4v3gCI4T/9VijVrm8Ym5v0OgjvGLKj3zTUwkvsCiwqae/p6VLzpsFNjQS2i6ewV7ef+DjFJ5TSKxYt/mCrA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.1.0.tgz", + "integrity": "sha512-sHxOu2ELzW8/NC1UP5XVLbZDzO4S3VxfFye3XYCznopHy02YjNkHcj5bKaVw2O7hVaBdBjEdQGpie4II1mWhuQ==", "dev": true, "requires": { - "growl": "~> 1.10.0", "js-yaml": "^3.13.1", - "lcov-parse": "^0.0.10", + "lcov-parse": "^1.0.0", "log-driver": "^1.2.7", - "minimist": "^1.2.0", - "request": "^2.86.0" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "minimist": "^1.2.5", + "request": "^2.88.2" } }, "dashdash": { @@ -397,13 +460,6 @@ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } } }, "date-now": { @@ -413,12 +469,12 @@ "dev": true }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "decamelize": { @@ -433,80 +489,65 @@ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, "dmd": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/dmd/-/dmd-4.0.0.tgz", - "integrity": "sha512-J+4CgbQiMuJHiU9dvTVN8iOOZGeR3bef1wBqz6eVvvX17jkpkKVd8TeeutA/FJAeFbLQfXnyQ3o4qY7W+c5cxQ==", - "dev": true, - "requires": { - "array-back": "^3.1.0", - "cache-point": "^0.4.1", - "common-sequence": "^1.0.2", - "file-set": "^2.0.0", - "handlebars": "^4.1.2", - "marked": "^0.6.2", - "object-get": "^2.1.0", - "reduce-flatten": "^2.0.0", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/dmd/-/dmd-5.0.1.tgz", + "integrity": "sha512-sHoHkUW5ZT82ZquBJBRnXzal/ybG1dieuX0KmI41OUwZOUETr6FqQe/wc/jKPDT/+/MhdtZdGrM6bD4G5a15GQ==", + "dev": true, + "requires": { + "array-back": "^4.0.1", + "cache-point": "^2.0.0", + "common-sequence": "^2.0.0", + "file-set": "^4.0.1", + "handlebars": "^4.7.6", + "marked": "^1.1.0", + "object-get": "^2.1.1", + "reduce-flatten": "^3.0.0", "reduce-unique": "^2.0.1", "reduce-without": "^1.0.1", "test-value": "^3.0.0", - "walk-back": "^3.0.1" + "walk-back": "^4.0.0" }, "dependencies": { - "handlebars": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", - "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", - "dev": true, - "requires": { - "neo-async": "^2.6.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - } - }, "reduce-flatten": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", - "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-3.0.0.tgz", + "integrity": "sha512-eczl8wAYBxJ6Egl6I1ECIF+8z6sHu+KE7BzaEDZTpPXKXfy9SUDQlVYwkRcNTjJLC3Iakxbhss50KuT/R6SYfg==", "dev": true } } }, "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", "dev": true, "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" + "domelementtype": "^2.0.1", + "entities": "^2.0.0" }, "dependencies": { + "domelementtype": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", + "dev": true + }, "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", "dev": true } } @@ -537,12 +578,12 @@ } }, "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "requires": { - "jsbn": "~0.1.0" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "emoji-regex": { @@ -551,115 +592,85 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, "entities": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", "dev": true }, - "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", "dev": true }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=" + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "file-set": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/file-set/-/file-set-2.0.1.tgz", - "integrity": "sha512-XgOUUpgR6FbbfYcniLw0qm1Am7PnNYIAkd+eXxRt42LiYhjaso0WiuQ+VmrNdtwotyM+cLCfZ56AZrySP3QnKA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/file-set/-/file-set-4.0.1.tgz", + "integrity": "sha512-tRzX4kGPmxS2HDK2q2L4qcPopTl/gcyahve2/O8l8hHNJgJ7m+r/ZncCJ1MmFWEMp1yHxJGIU9gAcsWu5jPMpg==", "dev": true, "requires": { - "array-back": "^2.0.0", - "glob": "^7.1.3" + "array-back": "^4.0.1", + "glob": "^7.1.6" }, "dependencies": { - "array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { - "typical": "^2.6.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "find-replace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", @@ -667,31 +678,47 @@ "dev": true, "requires": { "array-back": "^3.0.1" + }, + "dependencies": { + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true + } } }, "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "requires": { - "locate-path": "^3.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" } }, "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, "fs-then-native": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fs-then-native/-/fs-then-native-2.0.0.tgz", @@ -704,11 +731,12 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true }, "get-caller-file": { "version": "2.0.5", @@ -716,34 +744,18 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } } }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -754,10 +766,19 @@ "path-is-absolute": "^1.0.0" } }, + "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==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", "dev": true }, "growl": { @@ -767,15 +788,24 @@ "dev": true }, "handlebars": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", - "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", "dev": true, "requires": { + "minimist": "^1.2.5", "neo-async": "^2.6.0", - "optimist": "^0.6.1", "source-map": "^0.6.1", - "uglify-js": "^3.1.4" + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } } }, "har-schema": { @@ -783,25 +813,19 @@ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { - "function-bind": "^1.1.1" + "ajv": "^6.5.5", + "har-schema": "^2.0.0" } }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "he": { @@ -823,6 +847,16 @@ "readable-stream": "1.1" } }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -839,28 +873,19 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, - "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", - "dev": true - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, "is-fullwidth-code-point": { @@ -869,29 +894,26 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "has": "^1.0.1" + "is-extglob": "^2.1.1" } }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.0" - } + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true }, "is-typedarray": { "version": "1.0.0", @@ -926,7 +948,7 @@ "escodegen": "1.8.x", "esprima": "2.7.x", "glob": "^5.0.15", - "handlebars": "^4.1.2", + "handlebars": "^4.0.1", "js-yaml": "3.x", "mkdirp": "0.5.x", "nopt": "3.x", @@ -1220,40 +1242,39 @@ } }, "js2xmlparser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.0.tgz", - "integrity": "sha512-WuNgdZOXVmBk5kUPMcTcVUpbGRzLfNkv7+7APq7WiDihpXVKrgxo6wwRpRl9OQeEBgKCVk9mR7RbzrnNWC8oBw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz", + "integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==", "dev": true, "requires": { - "xmlcreate": "^2.0.0" + "xmlcreate": "^2.0.3" } }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsdoc": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.2.tgz", - "integrity": "sha512-S2vzg99C5+gb7FWlrK4TVdyzVPGGkdvpDkCEJH1JABi2PKzPeLu5/zZffcJUifgWUJqXWl41Hoc+MmuM2GukIg==", + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.4.tgz", + "integrity": "sha512-3G9d37VHv7MFdheviDCjUfQoIjdv4TC5zTTf5G9VODLtOnVS6La1eoYBDlbWfsRT3/Xo+j2MIqki2EV12BZfwA==", "dev": true, "requires": { - "@babel/parser": "^7.4.4", - "bluebird": "^3.5.4", - "catharsis": "^0.8.10", + "@babel/parser": "^7.9.4", + "bluebird": "^3.7.2", + "catharsis": "^0.8.11", "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.0", + "js2xmlparser": "^4.0.1", "klaw": "^3.0.0", - "markdown-it": "^8.4.2", - "markdown-it-anchor": "^5.0.2", - "marked": "^0.6.2", - "mkdirp": "^0.5.1", - "requizzle": "^0.2.2", - "strip-json-comments": "^3.0.1", + "markdown-it": "^10.0.0", + "markdown-it-anchor": "^5.2.7", + "marked": "^0.8.2", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", "taffydb": "2.6.2", - "underscore": "~1.9.1" + "underscore": "~1.10.2" }, "dependencies": { "escape-string-regexp": { @@ -1262,82 +1283,77 @@ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true }, + "marked": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz", + "integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==", + "dev": true + }, "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", "dev": true } } }, "jsdoc-api": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-5.0.1.tgz", - "integrity": "sha512-bntcT/3No4dPJZs9KX0AN3vrX/7P6PwDXVKANCXYpa0WJsbud41yAunoMxGFS4APHwmDoWl8E0ZuowLCOiOOFw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-6.0.0.tgz", + "integrity": "sha512-zvfB63nAc9e+Rv2kKmJfE6tmo4x8KFho5vKr6VfYTlCCgqtrfPv0McCdqT4betUT9rWtw0zGkNUVkVqeQipY6Q==", "dev": true, "requires": { - "array-back": "^3.1.0", - "cache-point": "^0.4.1", + "array-back": "^4.0.1", + "cache-point": "^2.0.0", "collect-all": "^1.0.3", - "file-set": "^2.0.1", + "file-set": "^4.0.1", "fs-then-native": "^2.0.0", - "jsdoc": "^3.6.1", - "object-to-spawn-args": "^1.1.1", + "jsdoc": "^3.6.4", + "object-to-spawn-args": "^2.0.0", "temp-path": "^1.0.0", - "walk-back": "^3.0.1" + "walk-back": "^4.0.0" } }, "jsdoc-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-3.0.1.tgz", - "integrity": "sha512-btZLp4wYl90vcAfgk4hoGQbO17iBVrhh3LJRMKZNtZgniO3F8H2CjxXld0owBIB1XxN+j3bAcWZnZKMnSj3iMA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-5.0.0.tgz", + "integrity": "sha512-Khw8c3glrTeA3/PfUJUBvhrMhWpSClORBUvL4pvq2wFcqvUVmA96wxnMkCno2GfZY4pnd8BStK5WGKGyn4Vckg==", "dev": true, "requires": { - "array-back": "^2.0.0", + "array-back": "^4.0.1", "lodash.omit": "^4.5.0", "lodash.pick": "^4.4.0", "reduce-extract": "^1.0.0", - "sort-array": "^2.0.0", + "sort-array": "^4.1.1", "test-value": "^3.0.0" - }, - "dependencies": { - "array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", - "dev": true, - "requires": { - "typical": "^2.6.1" - } - } } }, "jsdoc-to-markdown": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-5.0.0.tgz", - "integrity": "sha512-3gKEnbay7dSdyvtMDDkUf4r7pmBVgs3aqeT0Cg/ngTILPpJUzf8iKgASIo5psF007L45OIJtIuRX5VL/YUXKaA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-6.0.1.tgz", + "integrity": "sha512-hUI2PAR5n/KlmQU3mAWO9i3D7jVbhyvUHfQ6oYVBt+wnnsyxpsAuhCODY1ryLOb2U9OPJd4GIK9mL2hqy7fHDg==", "dev": true, "requires": { - "array-back": "^3.1.0", + "array-back": "^4.0.1", "command-line-tool": "^0.8.0", "config-master": "^3.1.0", - "dmd": "^4.0.0", - "jsdoc-api": "^5.0.1", - "jsdoc-parse": "^3.0.1", - "walk-back": "^3.0.1" + "dmd": "^5.0.1", + "jsdoc-api": "^6.0.0", + "jsdoc-parse": "^5.0.0", + "walk-back": "^4.0.0" } }, "jshint": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.10.2.tgz", - "integrity": "sha512-e7KZgCSXMJxznE/4WULzybCMNXNAd/bf5TSrvVEq78Q/K8ZwFpmBqQeDtNiHc3l49nV4E/+YeHU/JZjSUIrLAA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.12.0.tgz", + "integrity": "sha512-TwuuaUDmra0JMkuqvqy+WGo2xGHSNjv1BA1nTIgtH2K5z1jHuAEeAgp7laaR+hLRmajRjcrM71+vByBDanCyYA==", "dev": true, "requires": { "cli": "~1.0.0", "console-browserify": "1.1.x", "exit": "0.1.x", "htmlparser2": "3.8.x", - "lodash": "~4.17.11", + "lodash": "~4.17.19", "minimatch": "~3.0.2", "shelljs": "0.3.x", "strip-json-comments": "1.0.x" @@ -1357,9 +1373,9 @@ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stringify-safe": { "version": "5.0.1", @@ -1375,13 +1391,6 @@ "extsprintf": "1.3.0", "json-schema": "0.2.3", "verror": "1.10.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } } }, "klaw": { @@ -1393,44 +1402,34 @@ "graceful-fs": "^4.1.9" } }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, "lcov-parse": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", - "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", + "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", "dev": true }, "linkify-it": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.1.0.tgz", - "integrity": "sha512-4REs8/062kV2DSHxNfq5183zrqXMl7WP0WzABH9IeJI+NLm429FgE1PDecltYfnOoFDFlZGh2T8PfZn0r+GTRg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", "dev": true, "requires": { "uc.micro": "^1.0.1" } }, "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "^5.0.0" } }, "lodash": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", - "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "lodash.camelcase": { @@ -1464,54 +1463,45 @@ "dev": true }, "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", "dev": true, "requires": { - "p-defer": "^1.0.0" + "chalk": "^4.0.0" } }, "markdown-it": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", - "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", "dev": true, "requires": { "argparse": "^1.0.7", - "entities": "~1.1.1", + "entities": "~2.0.0", "linkify-it": "^2.0.0", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" }, "dependencies": { "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.2.tgz", + "integrity": "sha512-dmD3AvJQBUjKpcNkoqr+x+IF0SdRtPz9Vk0uTy4yWqga9ibB6s4v++QFWNohjiUGoMlF552ZvNyXDxz5iW0qmw==", "dev": true } } }, "markdown-it-anchor": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.0.2.tgz", - "integrity": "sha512-AFM/woBI8QDJMS/9+MmsBMT5/AR+ImfOsunQZTZhzcTmna3rIzAzbOh5E0l6mlFM/i9666BpUtkqQ9bS7WApCg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", + "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", "dev": true }, "marked": { - "version": "0.6.2", - "resolved": "http://registry.npmjs.org/marked/-/marked-0.6.2.tgz", - "integrity": "sha512-LqxwVH3P/rqKX4EKGz7+c2G9r98WeM/SW34ybhgNGhUQNKtf1GmmSkJ6cDGJ/t6tiyae49qRkpyTw2B9HOrgUA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.1.0.tgz", + "integrity": "sha512-EkE7RW6KcXfMHy2PA7Jg0YJE1l8UPEZE8k45tylzmZM30/r1M1MUXWQfJlrSbsTeh7m/XTwHbWUENvAJZpp1YA==", "dev": true }, "mdurl": { @@ -1520,23 +1510,19 @@ "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", "dev": true }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" + "mime-db": "1.43.0" } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -1547,27 +1533,16 @@ } }, "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true }, "mkdirp2": { "version": "1.0.4", @@ -1576,40 +1551,60 @@ "dev": true }, "mocha": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.0.tgz", - "integrity": "sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz", + "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==", "dev": true, "requires": { - "ansi-colors": "3.2.3", + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", + "chokidar": "3.4.3", + "debug": "4.2.0", + "diff": "4.0.2", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", "growl": "1.10.5", "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "2.2.0", + "js-yaml": "3.14.0", + "log-symbols": "4.0.0", "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "ms": "2.1.1", - "node-environment-flags": "1.0.5", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", + "ms": "2.1.2", + "nanoid": "3.1.12", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "7.2.0", + "which": "2.0.2", "wide-align": "1.1.3", - "yargs": "13.2.2", - "yargs-parser": "13.0.0", - "yargs-unparser": "1.5.0" + "workerpool": "6.0.2", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "nanoid": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", + "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", "dev": true }, "neo-async": { @@ -1618,77 +1613,29 @@ "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", "dev": true }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, - "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-get": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/object-get/-/object-get-2.1.0.tgz", - "integrity": "sha1-ciu9tgA576R8rTxtws5RqFwCxa4=", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-get/-/object-get-2.1.1.tgz", + "integrity": "sha512-7n4IpLMzGGcLEMiQKsNR7vCe+N5E9LORFrtNUVy4sO3dj9a3HedZCxEL2T7QuLhcHN1NBuBsMOKaOsAYI9IIvg==", "dev": true }, "object-to-spawn-args": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-1.1.1.tgz", - "integrity": "sha1-d9qIJ/Bz0BHJ4bFz+JV4FHAkZ4U=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-2.0.0.tgz", + "integrity": "sha512-ZMT4owlXg3JGegecLlAgAA/6BsdKHn63R3ayXcAa3zFkF7oUBHcSb0oxszeutYe0FO2c1lT5pwCuidLkC4Gx3g==", "dev": true }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1698,69 +1645,22 @@ "wrappy": "1" } }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - }, - "dependencies": { - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - } - } - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", "dev": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "p-limit": "^3.0.2" } }, "p-try": { @@ -1770,9 +1670,9 @@ "dev": true }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "path-is-absolute": { @@ -1781,45 +1681,49 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "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==", + "dev": true + }, "promise": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.3.tgz", - "integrity": "sha512-HeRDUL1RJiLhyA0/grn+PTShlBAcLuh/1BJGtrvjwbvRDCTLLMEz9rOGCV+R3vHY4MixIuoMEd9Yq/XvsTPcjw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", + "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", "requires": { "asap": "~2.0.6" } }, "psl": { - "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha1-YPWA02AXC7cip5fMcEQR5tqFDGc=" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "safe-buffer": "^5.1.0" } }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", @@ -1832,6 +1736,15 @@ "string_decoder": "~0.10.x" } }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, "reduce-extract": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/reduce-extract/-/reduce-extract-1.0.0.tgz", @@ -1905,9 +1818,9 @@ } }, "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha1-nC/KT301tZLv5Xx/ClXoEFIST+8=", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -1916,7 +1829,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", @@ -1926,110 +1839,9 @@ "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": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha1-8OAD2cqef1nHpQiUXXsu+aBKVC8=" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=" - }, - "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" - } - }, - "har-validator": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", - "integrity": "sha1-RGV/VoiiLP1LckhugbOj+xF0LCk=", - "requires": { - "ajv": "^5.3.0", - "har-schema": "^2.0.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "mime-db": { - "version": "1.36.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", - "integrity": "sha1-UCBHjbPH/pOq17vMTc+GnEM2M5c=" - }, - "mime-types": { - "version": "2.1.20", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", - "integrity": "sha1-kwy3GdVx6QNzhSD4RwkRVIyizBk=", - "requires": { - "mime-db": "~1.36.0" - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=" - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=" - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha1-U/Nto/R3g7CSWvoG/587FlKA94E=", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE=" - } } }, "require-directory": { @@ -2045,30 +1857,24 @@ "dev": true }, "requizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.2.tgz", - "integrity": "sha512-oJ6y7JcUJkblRGhMByGNcszeLgU0qDxNKFCiUZR1XyzHyVsev+Mxb1tyygxLd1ORsKee1SA5BInFdUwY64GE/A==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", + "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", "dev": true, "requires": { - "lodash": "^4.17.11" + "lodash": "^4.17.14" } }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - }, "sepia": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/sepia/-/sepia-2.0.2.tgz", @@ -2086,25 +1892,19 @@ } } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "randombytes": "^2.1.0" } }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "shelljs": { @@ -2113,38 +1913,28 @@ "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", "dev": true }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, "sort-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-2.0.0.tgz", - "integrity": "sha1-OKnG2if9fRR7QuYFVPKBGHtN9HI=", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-4.1.1.tgz", + "integrity": "sha512-tq+zhq5DrWUI5ayKc+5GOFZsa2RDre5O/8ASgqWCrjI3Ik3v1C4jp4oTttNngN52uIM7j3u2HfzmHmq71/nvQQ==", "dev": true, "requires": { - "array-back": "^1.0.4", - "object-get": "^2.1.0", - "typical": "^2.6.0" + "array-back": "^4.0.1", + "typical": "^6.0.0" }, "dependencies": { - "array-back": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", - "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", - "dev": true, - "requires": { - "typical": "^2.6.0" - } + "typical": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-6.0.1.tgz", + "integrity": "sha512-+g3NEp7fJLe9DPa1TArHm9QAA7YciZmWnfAqEaFrBihQ7epOv9i99rjtgb6Iz0wh3WuQDjsCTDfgRoGnmHN81A==", + "dev": true } } }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true }, "sprintf-js": { @@ -2154,9 +1944,9 @@ "dev": true }, "sshpk": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", - "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -2167,13 +1957,6 @@ "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } } }, "stream-connect": { @@ -2227,31 +2010,25 @@ "ansi-regex": "^3.0.0" } }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } }, "table-layout": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-0.4.4.tgz", - "integrity": "sha512-uNaR3SRMJwfdp9OUr36eyEi6LLsbcTqTO/hfTsNviKsNeyMBPICJCC7QXRF3+07bAP6FRwA8rczJPBqXDc0CkQ==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-0.4.5.tgz", + "integrity": "sha512-zTvf0mcggrGeTe/2jJ6ECkJHAQPIYEwDoqsiqBjI24mvRmQbInK5jq33fyypaCBxX08hMkfmdOqj6haT33EqWw==", "dev": true, "requires": { "array-back": "^2.0.0", @@ -2305,11 +2082,36 @@ } } }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "typical": { "version": "2.6.1", @@ -2326,7 +2128,7 @@ "uglify-js": { "version": "3.4.9", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "integrity": "sha1-rwLxgMEgfXZDLkc+0koo9KeCuuM=", "dev": true, "optional": true, "requires": { @@ -2337,18 +2139,31 @@ "commander": { "version": "2.17.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "integrity": "sha1-vXerfebelCBc6sxy8XFtKfIKd78=", "dev": true, "optional": true } } }, "underscore": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", - "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz", + "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==", "dev": true }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -2357,25 +2172,18 @@ "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } } }, "walk-back": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-3.0.1.tgz", - "integrity": "sha512-umiNB2qLO731Sxbp6cfZ9pwURJzTnftxE4Gc7hq8n/ehkuXC//s9F65IEIJA2ZytQZ1ZOsm/Fju4IWx0bivkUQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-4.0.0.tgz", + "integrity": "sha512-kudCA8PXVQfrqv2mFTG72vDBRi8BKWxGgFLwPpzHcpZnSwZk93WMwUDVcLHWNsnm+Y0AC4Vb6MUNRgaHfyV2DQ==", "dev": true }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -2396,12 +2204,6 @@ "string-width": "^1.0.2 || 2" } }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - }, "wordwrapjs": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-3.0.0.tgz", @@ -2412,49 +2214,71 @@ "typical": "^2.6.1" } }, + "workerpool": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", + "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==", + "dev": true + }, "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" }, "dependencies": { "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "color-convert": "^1.9.0" } }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^4.1.0" } } } @@ -2465,10 +2289,15 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "ws": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz", + "integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==" + }, "xmlcreate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.1.tgz", - "integrity": "sha512-MjGsXhKG8YjTKrDCXseFo3ClbMGvUD4en29H2Cev1dv4P/chlpw6KdYmlCWDkhosBVKRDjM836+3e3pm1cBNJA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz", + "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==", "dev": true }, "y18n": { @@ -2478,22 +2307,21 @@ "dev": true }, "yargs": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", - "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, "requires": { - "cliui": "^4.0.0", + "cliui": "^5.0.0", "find-up": "^3.0.0", "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.0.0" + "yargs-parser": "^13.1.2" }, "dependencies": { "ansi-regex": { @@ -2502,6 +2330,49 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -2525,9 +2396,9 @@ } }, "yargs-parser": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", - "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { "camelcase": "^5.0.0", @@ -2535,57 +2406,28 @@ } }, "yargs-unparser": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", - "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.11", - "yargs": "^12.0.5" + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" }, "dependencies": { - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "dev": true }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true - }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } } } } diff --git a/package.json b/package.json index 6b7b662..8df9b06 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "teslajs", - "version": "4.3.13", + "version": "4.9.7", "description": "Full-featured Tesla REST API NodeJS package", "dependencies": { - "promise": "^8.0.1", - "request": "^2.81.0" + "promise": "^8.0.3", + "request": "^2.88.2", + "ws": "^7.2.1" }, "bugs": { "url": "https://github.com/mseminatore/TeslaJS/issues" @@ -32,13 +33,13 @@ }, "license": "MIT", "devDependencies": { - "colors": "^1.3.3", - "commander": "^3.0.0", - "coveralls": "^3.0.2", + "colors": "^1.4.0", + "commander": "^7.0.0", + "coveralls": "^3.0.11", "istanbul": "^0.4.5", - "jsdoc-to-markdown": "^5.0.0", - "jshint": "^2.10.0", - "mocha": "^6.0.2", + "jsdoc-to-markdown": "^6.0.1", + "jshint": "^2.11.0", + "mocha": "^8.0.1", "sepia": "^2.0.2" } } diff --git a/samples/homelink.js b/samples/homelink.js index f1fe23a..01c952b 100644 --- a/samples/homelink.js +++ b/samples/homelink.js @@ -31,13 +31,15 @@ sample.run(); // // function sampleMain(tjs, options) { - tjs.driveState(options, function (err, drive_state) { - if (drive_state) { - var latitude = drive_state.latitude || 0; - var longitude = drive_state.longitude || 0; - var token = options.tokens[0]; + tjs.vehicleData(options, function (err, data) { + if (data.drive_state) { + var latitude = data.drive_state.latitude || 0; + var longitude = data.drive_state.longitude || 0; - tjs.homelink(options, latitude, longitude, token, function (err, result) { + console.log("\nHomelink devices: " + data.vehicle_state.homelink_device_count); + console.log("Homelink nearby: " + data.vehicle_state.homelink_nearby); + + tjs.homelink(options, latitude, longitude, function (err, result) { if (result.result) { console.log("\nHomelink: " + "Door signaled!".bold.green); } else { @@ -46,7 +48,7 @@ function sampleMain(tjs, options) { }); } else { - console.log("Drive State: " + drive_state.reason.red); + console.log("Drive State: " + data.drive_state.reason.red); } }); } diff --git a/samples/login.js b/samples/login.js index 9ea2af7..a735b65 100644 --- a/samples/login.js +++ b/samples/login.js @@ -9,13 +9,13 @@ //===================================================================== "use strict"; -var tjs = require('../TeslaJS'); +var tjs = require('../teslajs'); var fs = require('fs'); require('colors'); var program = require('commander'); program - .usage('[options] username password') + .usage('[options] username password [MFA code] [MFA device name]') .option('-U, --uri [string]', 'URI of test server (e.g. http://127.0.0.1:3000)') .parse(process.argv); @@ -25,13 +25,20 @@ if (program.args.length < 2) { var username = program.args[0]; var password = program.args[1]; +var mfaPassCode = program.args[2]; +var mfaDeviceName = program.args[3]; if (program.uri) { console.log("Setting portal URI to: " + program.uri); tjs.setPortalBaseURI(program.uri); } -tjs.loginAsync(username, password).done( +tjs.loginAsync({ + username: username, + password: password, + mfaPassCode: mfaPassCode, + mfaDeviceName: mfaDeviceName +}).done( // success! function (result) { if (!result.authToken) { diff --git a/samples/logout.js b/samples/logout.js index 967d6b3..bac83fc 100644 --- a/samples/logout.js +++ b/samples/logout.js @@ -9,7 +9,7 @@ //===================================================================== "use strict"; -var tjs = require('../TeslaJS'); +var tjs = require('../teslajs'); var fs = require('fs'); // diff --git a/samples/odometer.js b/samples/odometer.js index 01d97d9..3c22be0 100644 --- a/samples/odometer.js +++ b/samples/odometer.js @@ -53,9 +53,9 @@ function sampleMain(tjs, options) { console.log("--------"); var miles = addCommas(Math.round(vehicle_state.odometer).toString()); - console.log(miles.green + " miles"); + console.log(miles.green + " mi"); var km = addCommas(Math.round(vehicle_state.odometer * 1.609344).toString()); - console.log(km.green + " KM"); + console.log(km.green + " km"); }); } diff --git a/samples/products.js b/samples/products.js new file mode 100644 index 0000000..bd75cf4 --- /dev/null +++ b/samples/products.js @@ -0,0 +1,37 @@ +//===================================================================== +// This sample demonstrates using TeslaJS +// +// https://github.com/mseminatore/TeslaJS +// +// Copyright (c) 2016 Mark Seminatore +// +// Refer to included LICENSE file for usage rights and restrictions +//===================================================================== +"use strict"; + +require('colors'); +var program = require('commander'); +var framework = require('./sampleFramework.js'); + +// +// +// +program + .option('-u, --username [string]', 'username (needed only if token not cached)') + .option('-p, --password [string]', 'password (needed only if token not cached)') + .option('-U, --uri [string]', 'URI of test server (e.g. http://127.0.0.1:3000)') + .parse(process.argv); + +// +var sample = new framework.SampleFramework(program, sampleMain); +sample.run(); + +// +// +// +function sampleMain(tjs, options) { + tjs.productsAsync(options).then( function(products) { + console.log("\nOwned Tesla products returned:\n"); + console.log(products); + }); +} diff --git a/samples/simpleStreaming.js b/samples/simpleStreaming.js index 068cbc7..56ab1bb 100644 --- a/samples/simpleStreaming.js +++ b/samples/simpleStreaming.js @@ -17,8 +17,7 @@ var framework = require('./sampleFramework.js'); // // program - .usage('[options] username') - .option('-p, --password [string]', 'password (needed only if token not cached)') + .usage('[options]') .option('-i, --index ', 'vehicle index (first car by default)', parseInt) .option('-U, --uri [string]', 'URI of test server (e.g. http://127.0.0.1:3000)') .parse(process.argv); @@ -32,14 +31,9 @@ sample.run(); // function sampleMain(tjs, options) { - if (program.args.length < 1) { - program.help(); - } - var streamingOptions = { - username: program.args[0], - password: options.tokens[0], - vehicle_id: options.vehicle_id + vehicle_id: options.vehicle_id, + authToken: options.authToken }; console.log("\nNote: " + "Inactive vehicle streaming responses can take up to several minutes.".green); diff --git a/samples/soc.js b/samples/soc.js index 101089d..1c636a2 100644 --- a/samples/soc.js +++ b/samples/soc.js @@ -27,18 +27,20 @@ program var sample = new framework.SampleFramework(program, sampleMain); sample.run(); +function milesToKms(miles){ + return miles * 1.609344; +} + // // // function sampleMain(tjs, options) { - tjs.vehicleData(options, function (err, vehicleData) { - if (err) { - console.log(err); - return; - } - + tjs.vehicleDataAsync(options).then( function(vehicleData) { // get the charge state info from the vehicle data var chargeState = vehicleData.charge_state; + + var eu_vehicle = vehicleData.vehicle_config.eu_vehicle; + var unitsInKms = vehicleData.gui_settings.gui_distance_units === "km/hr"; var str = chargeState.charge_port_door_open === true ? "OPEN" : "CLOSED"; console.log("\nCharge port: " + str.green); @@ -72,10 +74,15 @@ function sampleMain(tjs, options) { console.log("Charge scheduled for " + scheduledChargeTime.toLocaleTimeString().toString().green); } - console.log("\nCurrent charge level: " + chargeState.battery_level.toString().green + '%'.green); - console.log("Target charge level: " + chargeState.charge_limit_soc.toString().green + '%'.green); - console.log("\nRated range: " + Math.round(chargeState.battery_range).toString().green + ' miles'); - console.log("Projected range: " + Math.round(chargeState.est_battery_range).toString().green + ' miles'); - console.log("Ideal range: " + Math.round(chargeState.ideal_battery_range).toString().green + ' miles'); + console.log("\nCurrent charge level: " + chargeState.battery_level.toString().green + ' %'.green); + console.log("Target charge level: " + chargeState.charge_limit_soc.toString().green + ' %'.green); + + console.log("\nRated range: " + (unitsInKms ? Math.round(milesToKms(chargeState.battery_range)).toString().green + ' km' : Math.round(chargeState.battery_range).toString().green + ' mi')); + console.log((eu_vehicle?"Typical":"Ideal")+" range: " + (unitsInKms ? Math.round(milesToKms(chargeState.ideal_battery_range)).toString().green + ' km' : Math.round(chargeState.ideal_battery_range).toString().green + ' mi')); + console.log("Projected range: " + (unitsInKms ? Math.round(milesToKms(chargeState.est_battery_range)).toString().green + ' km' : Math.round(chargeState.est_battery_range).toString().green + ' mi')); + + //console.log("\nRated - how far "+(eu_vehicle?"NEDC":"the EPA") + " says the car will go given their tests."); + //console.log((eu_vehicle?"Typical":"Ideal")+" - how far the car will go if driven at a steady " + (unitsInKms? "88 km/h":"55 mph") + " on level ground at moderate temperatures."); + //console.log("Projected - how far the car calculates you will go if you keep consuming power at the rate you are currently\n"); }); } diff --git a/samples/vehicle.js b/samples/vehicle.js index dd45ed2..baf73a6 100644 --- a/samples/vehicle.js +++ b/samples/vehicle.js @@ -27,6 +27,10 @@ program var sample = new framework.SampleFramework(program, sampleMain); sample.run(); +function milesToKms(miles){ + return miles * 1.609344; +} + // // // @@ -35,13 +39,17 @@ function sampleMain(tjs, options) { var vehicle_state = vehicleData.vehicle_state; var charge_state = vehicleData.charge_state; + var eu_vehicle = vehicleData.vehicle_config.eu_vehicle; + var unitsInKms = vehicleData.gui_settings.gui_distance_units === "km/hr"; + var str = vehicle_state.locked ? "LOCKED".bgGreen : "UNLOCKED".yellow; console.log("\nCharging state: " + charge_state.charging_state.green); - console.log("Battery level: "+ charge_state.battery_level.toString().green); - console.log("Charge limit: " + charge_state.charge_limit_soc.toString().green); - console.log("Rated range: " + Math.round(charge_state.battery_range).toString().green); - console.log("Projected range: " + Math.round(charge_state.est_battery_range).toString().green); + console.log("Battery level: " + charge_state.battery_level.toString().green + ' / '.green + charge_state.charge_limit_soc.toString().green + ' %'.green); + + console.log("\nRated range: " + (unitsInKms ? Math.round(milesToKms(charge_state.battery_range)).toString().green + ' km' : Math.round(charge_state.battery_range).toString().green + ' mi')); + console.log((eu_vehicle?"Typical":"Ideal")+" range: " + (unitsInKms ? Math.round(milesToKms(charge_state.ideal_battery_range)).toString().green + ' km' : Math.round(charge_state.ideal_battery_range).toString().green + ' mi')); + console.log("Projected range: " + (unitsInKms ? Math.round(milesToKms(charge_state.est_battery_range)).toString().green + ' km' : Math.round(charge_state.est_battery_range).toString().green + ' mi')); console.log("\nDoors: " + str); if (vehicle_state.df) { @@ -75,6 +83,8 @@ function sampleMain(tjs, options) { console.log("Firmware: " + vehicle_state.car_version.green); + console.log("\nIs user present? ", vehicle_state.is_user_present ? "YES".yellow : "NO".green); + str = vehicle_state.valet_mode ? "ON".bgGreen : "OFF".green; console.log("Valet mode: " + str + "\n"); }); diff --git a/src/auth.js b/src/auth.js new file mode 100644 index 0000000..4f2e1f0 --- /dev/null +++ b/src/auth.js @@ -0,0 +1,235 @@ +"use strict"; + +var request = require('request').defaults({ + headers: { + "x-tesla-user-agent": "TeslaApp/3.10.8-421/adff2e065/android/8.1.0", + "user-agent": "Mozilla/5.0 (Linux; Android 8.1.0; Pixel XL Build/OPM4.171019.021.D1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36", + "x-requested-with": "com.teslamotors.tesla" + }, + gzip: true, + jar: true +}); +var crypto = require('crypto'); +var Promise = require('promise'); + +exports.login = function login(credentials, callback) { + var codeVerifier = generateCodeVerifier(); + var codeChallenge = generateCodeChallenge(codeVerifier); + var queryString = { + audience: '', + client_id: 'ownerapi', + code_challenge: codeChallenge, + code_challenge_method: 'S256', + locale: 'en', + prompt: 'login', + redirect_uri: 'https://auth.tesla.com/void/callback', + response_type: 'code', + scope: 'openid email offline_access', + state: generateCodeChallenge(generateCodeVerifier()) + }; + var transactionId = null; + var loginHost = null; + var loginUrl = null; + + req({ + method: 'GET', + url: 'https://auth-global.tesla.com/oauth2/v3/authorize', + qs: queryString, + headers: { + "sec-fetch-site": "none", + "sec-fetch-mode": "navigate", + "sec-fetch-user": "?1", + "sec-fetch-dest": "document" + } + }).then(function (result) { + // Record the final URL we got redirected to; this is where we will send our credentials + loginUrl = result.response.request.href; + loginHost = "https://" + require('url').parse(loginUrl).host; + var form = {}; + + var hiddenFormFields = result.body.match(/]+>/g); + hiddenFormFields.forEach(function (field) { + var name = field.match(/name="([^"]+)"/); + var value = field.match(/value="([^"]*)"/); + if (name && value) { + form[name[1]] = value[1]; + } + }); + + transactionId = form.transaction_id; + + form.identity = credentials.identity; + form.credential = credentials.credential; + + return req({ + method: 'POST', + url: loginUrl, + form: form, + headers: { + "sec-fetch-site": "same-origin", + "sec-fetch-mode": "navigate", + "sec-fetch-user": "?1", + "sec-fetch-dest": "document", + "referer": loginUrl, + "origin": loginHost + } + }); + }).then(function (result) { + if (result.body.includes('/oauth2/v3/authorize/mfa/verify')) { + // MFA is required + if (!credentials.mfaPassCode) { + throw new Error("MFA passcode required"); + } + + return mfaVerify(transactionId, loginHost, loginUrl, credentials.mfaPassCode, credentials.mfaDeviceName); + } + + // No need to handle MFA + return result; + }).then(function (result) { + var location = result.response.headers.location; + if (!location) { + throw new Error("Login credentials rejected"); + } + + var url = require('url').parse(location, true); + if (!url.query || !url.query.code) { + throw new Error("No authorization code issued; credentials likely incorrect"); + } + + return req({ + method: 'POST', + url: (url.query.issuer || 'https://auth.tesla.com/oauth2/v3') + '/token', + jar: false, + json: true, + body: { + grant_type: 'authorization_code', + client_id: 'ownerapi', + code_verifier: codeVerifier, + code: url.query.code, + redirect_uri: url.protocol + '//' + url.host + url.pathname + } + }); + }).then(function (result) { + return req({ + method: 'POST', + url: 'https://owner-api.teslamotors.com/oauth/token', + headers: { + authorization: 'bearer ' + result.body.access_token + }, + json: true, + body: { + grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', + client_id: _0x2dc0[0] + } + }); + }).then(function (result) { + callback(null, result.response, result.body); + }).catch(function (error) { + callback(error); + }); +} + +function mfaVerify(transactionId, host, referer, mfaPassCode, mfaDeviceName) { + return req({ + method: 'GET', + url: host + '/oauth2/v3/authorize/mfa/factors?transaction_id=' + transactionId, + headers: { + "x-requested-with": "XMLHttpRequest", + "sec-fetch-site": "same-origin", + "sec-fetch-mode": "cors", + "sec-fetch-dest": "empty", + "referer": referer + }, + json: true + }).then(function (result) { + if (!result.body || !result.body.data || result.body.data.length == 0) { + throw new Error('No MFA devices found'); + } + + var device = result.body.data[0]; + if (mfaDeviceName) { + // Find the specific device we're looking for + device = result.body.data.find(function (dev) { return dev.name == mfaDeviceName; }); + if (!device) { + throw new Error('No MFA device found with name ' + mfaDeviceName); + } + } + + return req({ + method: 'POST', + url: host + '/oauth2/v3/authorize/mfa/verify', + headers: { + "x-requested-with": "XMLHttpRequest", + "origin": host, + "sec-fetch-site": "same-origin", + "sec-fetch-mode": "cors", + "sec-fetch-dest": "empty", + "referer": referer + }, + json: true, + body: { + transaction_id: transactionId, + factor_id: device.id, + passcode: mfaPassCode + } + }); + }).then(function (result) { + if (!result.body || !result.body.data || !result.body.data.approved || !result.body.data.valid) { + throw new Error('MFA passcode rejected'); + } + + // MFA auth has succeeded, so now repeat the authorize request with just the transaction id + return req({ + method: 'POST', + url: referer, + headers: { + "sec-fetch-site": "same-origin", + "sec-fetch-mode": "navigate", + "sec-fetch-user": "?1", + "sec-fetch-dest": "document", + "referer": referer, + "origin": host + }, + form: { + transaction_id: transactionId + }, + json: true + }); + }); +} + +function generateCodeVerifier() { + // Tesla might use something more sophisticated, but in my experience it's a 112-char alphanumeric string so let's just do that + var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; + var random = crypto.randomBytes(112); + var output = ''; + for (var i = 0; i < random.length; i++) { + output += chars[random[i] % chars.length]; + } + return output; +} + +function generateCodeChallenge(verifier) { + var hash = crypto.createHash('sha256'); + hash.update(verifier); + return hash.digest('base64') + .replace(/=/g, '') + .replace(/\+/g, '-') + .replace(/\//g, '_'); +} + +function req(parameters) { + return new Promise(function (resolve, reject) { + request(parameters, function (error, response, body) { + if (error || response.statusCode >= 400) { + return reject(error || new Error("HTTP error " + response.statusCode)); + } + + resolve({response: response, body: body}); + }); + }); +} + +//var _0x2dc0 = ["\x65\x34\x61\x39\x39\x34\x39\x66\x63\x66\x61\x30\x34\x30\x36\x38\x66\x35\x39\x61\x62\x62\x35\x61\x36\x35\x38\x66\x32\x62\x61\x63\x30\x61\x33\x34\x32\x38\x65\x34\x36\x35\x32\x33\x31\x35\x34\x39\x30\x62\x36\x35\x39\x64\x35\x61\x62\x33\x66\x33\x35\x61\x39\x65", "\x63\x37\x35\x66\x31\x34\x62\x62\x61\x64\x63\x38\x62\x65\x65\x33\x61\x37\x35\x39\x34\x34\x31\x32\x63\x33\x31\x34\x31\x36\x66\x38\x33\x30\x30\x32\x35\x36\x64\x37\x36\x36\x38\x65\x61\x37\x65\x36\x65\x37\x66\x30\x36\x37\x32\x37\x62\x66\x62\x39\x64\x32\x32\x30"]; +var _0x2dc0 = ["\x38\x31\x35\x32\x37\x63\x66\x66\x30\x36\x38\x34\x33\x63\x38\x36\x33\x34\x66\x64\x63\x30\x39\x65\x38\x61\x63\x30\x61\x62\x65\x66\x62\x34\x36\x61\x63\x38\x34\x39\x66\x33\x38\x66\x65\x31\x65\x34\x33\x31\x63\x32\x65\x66\x32\x31\x30\x36\x37\x39\x36\x33\x38\x34", "\x63\x37\x32\x35\x37\x65\x62\x37\x31\x61\x35\x36\x34\x30\x33\x34\x66\x39\x34\x31\x39\x65\x65\x36\x35\x31\x63\x37\x64\x30\x65\x35\x66\x37\x61\x61\x36\x62\x66\x62\x64\x31\x38\x62\x61\x66\x62\x35\x63\x35\x63\x30\x33\x33\x62\x30\x39\x33\x62\x62\x32\x66\x61\x33"]; diff --git a/teslajs.js b/teslajs.js deleted file mode 100644 index 38967fd..0000000 --- a/teslajs.js +++ /dev/null @@ -1,1776 +0,0 @@ -/** - * @file This is a Node.js module encapsulating the unofficial Tesla API set - * - * Github: https://github.com/mseminatore/TeslaJS - * NPM: https://www.npmjs.com/package/teslajs - * - * @copyright Copyright (c) 2016 Mark Seminatore - * - * @license MIT - * - * Refer to included LICENSE file for usage rights and restrictions - */ - -"use strict"; - -var request = require('request').defaults({ - headers: { - "x-tesla-user-agent": "TeslaApp/3.4.4-350/fad4a582e/android/8.1.0", - "user-agent": "Mozilla/5.0 (Linux; Android 8.1.0; Pixel XL Build/OPM4.171019.021.D1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36" - }, - json: true, - gzip: true, - body: {} -}); -var Promise = require('promise'); - -//======================= -// Streaming API portal -//======================= -/** - * @global - * @default - */ -var streamingPortal = "https://streaming.vn.teslamotors.com/stream"; -exports.streamingPortal = streamingPortal; - -var streamingBaseURI = process.env.TESLAJS_STREAMING || streamingPortal; - -//=========================== -// New OAuth-based API portal -//=========================== -/** - * @global - * @default - */ -var portal = "https://owner-api.teslamotors.com"; -exports.portal = portal; - -var portalBaseURI = process.env.TESLAJS_SERVER || portal; - -//======================= -// Log levels -//======================= -/** - * @global - * @default - */ -var API_LOG_ALWAYS = 0; -exports.API_LOG_ALWAYS = API_LOG_ALWAYS; - -/** - * @global - * @default - */ -var API_ERR_LEVEL = 1; -exports.API_ERR_LEVEL = API_ERR_LEVEL; - -/** - * @global - * @default - */ -var API_CALL_LEVEL = 2; -exports.API_CALL_LEVEL = API_CALL_LEVEL; - -/** - * @global - * @default - */ -var API_RETURN_LEVEL = 3; -exports.API_RETURN_LEVEL = API_RETURN_LEVEL; - -/** - * @global - * @default - */ -var API_BODY_LEVEL = 4; -exports.API_BODY_LEVEL = API_BODY_LEVEL; - -/** - * @global - * @default - */ -var API_REQUEST_LEVEL = 5; -exports.API_REQUEST_LEVEL = API_REQUEST_LEVEL; - -/** - * @global - * @default - */ -var API_RESPONSE_LEVEL = 6; -exports.API_RESPONSE_LEVEL = API_RESPONSE_LEVEL; - -/** - * @global - * @default - */ -var API_LOG_ALL = 255; // this value must be the last -exports.API_LOG_ALL = API_LOG_ALL; - -var logLevel = process.env.TESLAJS_LOG || 0; - -/** - * Node-style callback function - * @callback nodeBack - * @param {function} error - function which receives the error result - * @param {function} data - function which receives the data result - */ - -/** - * TeslaJS options parameter - * @typedef optionsType - * @type {object} - * @property {string} authToken - Tesla provided OAuth token - * @property {string} vehicleID - Tesla provided long vehicle id - * @property {?int} [carIndex] - index of vehicle within vehicles JSON - */ - -/* - * Adjustable console logging - * @param {int} level - logging level - * @param {string} str - text to log - */ -function log(level, str) { - if (logLevel < level) { - return; - } -// console.log("[" + new Date().toISOString() + "] " + str); - console.log(str); -} - -/* - * Ensure value is within [min..max] - */ -function clamp(value, min, max) { - if (value < min) { - value = min; - } - - if (value > max) { - value = max; - } - - return value; -} - -/** - * Set the current logging level - * @param {int} level - logging level - */ -exports.setLogLevel = function setLogLevel(level) { - logLevel = level; -} - -/** - * Get the current logging level - * @return {int} the current logging level - */ -exports.getLogLevel = function getLogLevel() { - return logLevel; -} - -/** - * Set the portal base URI - * @param {string} uri - URI for Tesla servers - */ -exports.setPortalBaseURI = function setPortalBaseURI(uri) { - if (!uri) { - portalBaseURI = portal; // reset to the default Tesla servers - } else { - portalBaseURI = uri; - } -} - -/** - * Get the portal base URI - * @return {string} URI for Tesla servers - */ -exports.getPortalBaseURI = function getPortalBaseURI() { - return portalBaseURI; -} - -/** - * Set the streaming base URI - * @param {string} uri - URI for Tesla streaming servers - */ -exports.setStreamingBaseURI = function setStreamingBaseURI(uri) { - if (!uri) { - streamingBaseURI = streamingPortal; // reset to the default Tesla servers - } else { - streamingBaseURI = uri; - } -} - -/** - * Get the streaming base URI - * @return {string} URI for Tesla streaming servers - */ -exports.getStreamingBaseURI = function getStreamingBaseURI() { - return streamingBaseURI; -} - -/** - * Return the car model from vehicle JSON information - * @param {object} vehicle - vehicle JSON - * @return {string} vehicle model string - */ -exports.getModel = function getModel(vehicle) { - var carType = "Unknown"; - - if (vehicle.option_codes.indexOf("MDLX") != -1) { - carType = "Model X"; - } else if (vehicle.option_codes.indexOf("MDL3") != -1) { - carType = "Model 3"; - } else { - carType = "Model S"; - } - - return carType; -} - -/** - * Return the paint color from vehicle JSON information - * @param {object} vehicle - vehicle JSON - * @return {string} the vehicle paint color - */ -exports.getPaintColor = function getPaintColor(vehicle) { - var colors = { - "PBCW": "white", - "PBSB": "black", - "PMAB": "metallic brown", - "PMBL": "metallic black", - "PMMB": "metallic blue", - "PMMR": "multi-coat red", - "PPMR": "multi-coat red", - "PMNG": "steel grey", - "PMSG": "metallic green", - "PMSS" : "metallic silver", - "PPSB": "ocean blue", - "PPSR" : "signature red", //premium signature red" - "PPSW": "pearl white", - "PPTI": "titanium", - "PMTG": "metallic grey" // dolphin grey - }; - - var paintColor = vehicle.option_codes.match(/PBCW|PBSB|PMAB|PMBL|PMMB|PMMR|PPMR|PMNG|PMSG|PMSS|PPSB|PPSR|PPSW|PPTI|PMTG/); - - return colors[paintColor] || "black"; -} - -/** - * Return the vehicle VIN from vehicle JSON information - * @param {object} vehicle - vehicle JSON - * @return {string} the vehicle VIN - */ -exports.getVin = function getVin(vehicle) { - if (!vehicle || !vehicle.vin) { - throw new Error("invalid parameter"); - } - - return vehicle.vin; -} - -/** - * Return the vehicle VIN from vehicle JSON information - * @param {object} vehicle - vehicle JSON - * @return {string} the short version of the vehicle VIN - */ -exports.getShortVin = function getShortVin(vehicle) { - if (!vehicle || !vehicle.vin) { - throw new Error("invalid parameter"); - } - - return vehicle.vin.substr(11); -} - -/** - * Login to the server and receive OAuth tokens - * @param {string} username - Tesla.com username - * @param {string} password - Tesla.com password - * @param {nodeBack} callback - Node-style callback - * @returns {object} {response, body, authToken, refreshToken} - */ -exports.login = function login(username, password, callback) { - log(API_CALL_LEVEL, "TeslaJS.login()"); - - callback = callback || function (err, result) { /* do nothing! */ } - - if (!username || !password) { - callback("login() requires username and password", null); - return; - } - - var req = { - method: 'POST', - url: portalBaseURI + '/oauth/token', - body: { - "grant_type": "password", - "client_id": c_id, - "client_secret": c_sec, - "email": process.env.TESLAJS_USER || username, - "password": process.env.TESLAJS_PASS || password - } - }; - - log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req)); - - request(req, function (error, response, body) { - - log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response)); - log(API_RESPONSE_LEVEL, "\nBody: " + JSON.stringify(body)); - - var loginResult = body; - - callback(error, { error: error, response: response, body: body, authToken: loginResult.access_token, refreshToken: loginResult.refresh_token }); - - log(API_RETURN_LEVEL, "TeslaJS.login() completed."); - }); -} - -/** - * Login to the server and receive OAuth tokens - * @function loginAsync - * @param {string} username - Tesla.com username - * @param {string} password - Tesla.com password - * @returns {Promise} {response, body, authToken, refreshToken} - */ -exports.loginAsync = Promise.denodeify(exports.login); - -/** - * Retrieve new OAuth and refresh tokens using a refresh_token - * @param {string} refresh_token - a valid OAuth refresh_token from a previous login - * @param {nodeBack} callback - Node-style callback - * @returns {object} {response, body, authToken, refreshToken} - */ -exports.refreshToken = function refreshToken(refresh_token, callback) { - log(API_CALL_LEVEL, "TeslaJS.refreshToken()"); - - callback = callback || function (err, result) { /* do nothing! */ } - - if (!refresh_token) { - callback("refreshToken() requires a refresh_token", null); - return; - } - - var req = { - method: 'POST', - url: portalBaseURI + '/oauth/token', - body: { - "grant_type": "refresh_token", - "client_id": c_id, - "client_secret": c_sec, - "refresh_token": refresh_token - } - }; - - log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req)); - - request(req, function (error, response, body) { - - log(API_RESPONSE_LEVEL, "\nResponse: " + body); - - callback(error, { error: error, response: response, body: JSON.stringify(body), authToken: body.access_token, refreshToken: body.refresh_token }); - - log(API_RETURN_LEVEL, "TeslaJS.refreshToken() completed."); - }); -} - -/** - * Async call to retrieve new OAuth and refresh tokens using a refresh_token - * @function refreshTokenAsync - * @param {string} refresh_token - a valid OAuth refresh_token from a previous login - * @returns {Promise} {response, body, authToken, refreshToken} - */ -exports.refreshTokenAsync = Promise.denodeify(exports.refreshToken); - -/** - * Logout and invalidate the current auth token - * @param {string} authToken - Tesla provided OAuth token - * @param {nodeBack} callback - Node-style callback - */ -exports.logout = function logout(authToken, callback) { - log(API_CALL_LEVEL, "TeslaJS.logout()"); - - callback = callback || function (err, result) { /* do nothing! */ } - - request({ - method: 'POST', - url: portalBaseURI + '/oauth/revoke', - headers: { Authorization: "Bearer " + authToken, 'Content-Type': 'application/json; charset=utf-8' } - }, function (error, response, body) { - - callback(error, { error: error, response: response, body: JSON.stringify(body) }); - - log(API_RETURN_LEVEL, "TeslaJS.logout() completed."); - }); -} - -/** - * Logout and invalidate the current auth token - * @function logoutAsync - * @param {string} authToken - Tesla provided OAuth token - * @returns {Promise} result - */ -exports.logoutAsync = Promise.denodeify(exports.logout); - -/** - * Return vehicle information on the requested vehicle - * @function vehicle - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {Vehicle} vehicle JSON data - */ -exports.vehicle = function vehicle(options, callback) { - log(API_CALL_LEVEL, "TeslaJS.vehicle()"); - - callback = callback || function (err, vehicle) { /* do nothing! */ } - - var req = { - method: 'GET', - url: portalBaseURI + '/api/1/vehicles', - headers: { Authorization: "Bearer " + options.authToken, 'Content-Type': 'application/json; charset=utf-8' } - }; - - log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req)); - - request(req, function (error, response, body) { - if (error) { - log(API_ERR_LEVEL, error); - return callback(error, null); - } - - if (response.statusCode != 200) { - return callback(response.statusMessage, null); - } - - log(API_BODY_LEVEL, "\nBody: " + JSON.stringify(body)); - log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response)); - - try { - body = body.response[options.carIndex || 0]; - body.id = body.id_s; - options.vehicleID = body.id; - - callback(null, body); - } catch (e) { - log(API_ERR_LEVEL, 'Error parsing vehicles response'); - callback(e, null); - } - - log(API_RETURN_LEVEL, "\nGET request: " + "/vehicles" + " completed."); - }); -} - -/** - * Return vehicle information on the requested vehicle - * @function vehicleAsync - * @param {optionsType} options - options object - * @returns {Promise} vehicle JSON data - */ -exports.vehicleAsync = Promise.denodeify(exports.vehicle); - -/** - * Return vehicle information on ALL vehicles - * @function vehicles - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {Vehicles[]} array of vehicle JSON data - */ -exports.vehicles = function vehicles(options, callback) { - log(API_CALL_LEVEL, "TeslaJS.vehicles()"); - - callback = callback || function (err, vehicle) { /* do nothing! */ } - - var req = { - method: 'GET', - url: portalBaseURI + '/api/1/vehicles', - headers: { Authorization: "Bearer " + options.authToken, 'Content-Type': 'application/json; charset=utf-8' } - }; - - log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req)); - - request(req, function (error, response, body) { - if (error) { - log(API_ERR_LEVEL, error); - return callback(error, null); - } - - if (response.statusCode != 200) { - return callback(response.statusMessage, null); - } - - log(API_BODY_LEVEL, "\nBody: " + JSON.stringify(body)); - log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response)); - - try { - body = body.response; - - callback(null, body); - } catch (e) { - log(API_ERR_LEVEL, 'Error parsing vehicles response'); - callback(e, null); - } - - log(API_RETURN_LEVEL, "\nGET request: " + "/vehicles" + " completed."); - }); -} - -/** - * Return vehicle information on ALL vehicles - * @function vehiclesAsync - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {Promise} array of vehicle JSON data - */ -exports.vehiclesAsync = Promise.denodeify(exports.vehicles); - -/** - * Generic REST call for GET commands - * @function get_command - * @param {optionsType} options - options object - * @param {string} command - REST command - * @param {nodeBack} callback - Node-style callback - */ -exports.get_command = get_command; -function get_command(options, command, callback) { - log(API_CALL_LEVEL, "GET call: " + command + " start."); - - callback = callback || function (err, data) { /* do nothing! */ } - - var req = { - method: "GET", - url: portalBaseURI + "/api/1/vehicles/" + options.vehicleID + "/" + command, - headers: { Authorization: "Bearer " + options.authToken, 'Content-Type': 'application/json; charset=utf-8'} - }; - - log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req)); - - request(req, function (error, response, body) { - if (error) { - log(API_ERR_LEVEL, error); - return callback(error, null); - } - - if (response.statusCode != 200) { - var str = "Error response: " + response.statusCode; - log(API_ERR_LEVEL, str); - return callback(str, null); - } - - log(API_BODY_LEVEL, "\nBody: " + JSON.stringify(body)); - log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response)); - - try { - body = body.response; - - callback(null, body); - } catch (e) { - log(API_ERR_LEVEL, 'Error parsing GET call response'); - callback(e, null); - } - - log(API_RETURN_LEVEL, "\nGET request: " + command + " completed."); - }); -} - -/** - * Generic Async REST call for GET commands - * @function get_commandAsync - * @param {optionsType} options - options object - * @param {string} command - REST command - * @returns {Promise} result - */ -exports.get_commandAsync = Promise.denodeify(exports.get_command); - -/** - * Generic REST call for POST commands - * @function - * @param {optionsType} options - options object - * @param {string} command - REST command - * @param {object} body - JSON payload - * @param {nodeBack} callback - Node-style callback - */ -exports.post_command = post_command; -function post_command(options, command, body, callback) { - log(API_CALL_LEVEL, "POST call: " + command + " start."); - - callback = callback || function (err, data) { /* do nothing! */ } - - var cmd = { - method: "POST", - url: portalBaseURI + "/api/1/vehicles/" + options.vehicleID + "/" + command, - headers: { Authorization: "Bearer " + options.authToken, 'content-type': 'application/json; charset=UTF-8' }, - body: body || null - }; - - log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(cmd)); - - request(cmd, function (error, response, body) { - if (error) { - log(API_ERR_LEVEL, error); - return callback(error, null); - } - - if (response.statusCode != 200) { - var str = "Error response: " + response.statusCode; - log(API_ERR_LEVEL, str); - return callback(str, null); - } - - log(API_BODY_LEVEL, "\nBody: " + JSON.stringify(body)); - log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response)); - - try { - body = body.response; - - callback(null, body); - } catch (e) { - log(API_ERR_LEVEL, 'Error parsing POST call response'); - callback(e, null); - } - - log(API_RETURN_LEVEL, "\nPOST command: " + command + " completed."); - }); -} - -/** - * Generic Async REST call for POST commands - * @function post_commandAsync - * @param {optionsType} options - options object - * @param {string} command - REST command - * @param {object} body - JSON payload - * @returns {Promise} result - */ -exports.post_commandAsync = Promise.denodeify(exports.post_command); - -/** - * GET all vehicle data in a single call - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} vehicle_data object - */ -exports.vehicleData = function vehicleData(options, callback){ - get_command(options, "vehicle_data", callback); -} - -/** - * Async version to GET all vehicle data in a single call - * @function vehicleDataAsync - * @param {optionsType} options - options object - * @returns {Promise} vehicle_data object - */ -exports.vehicleDataAsync = Promise.denodeify(exports.vehicleData); - -/** - * GET the vehicle config - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} vehicle_config object - */ -exports.vehicleConfig = function vehicleConfig(options, callback) { - get_command(options, "data_request/vehicle_config", callback); -} - -/** - * Async version to GET the vehicle config - * @function vehicleConfigAsync - * @param {optionsType} options - options object - * @returns {Promise} vehicle_config object - */ -exports.vehicleConfigAsync = Promise.denodeify(exports.vehicleConfig); - -/** - * GET the vehicle state - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} vehicle_state object - */ -exports.vehicleState = function vehicleState(options, callback) { - get_command(options, "data_request/vehicle_state", callback); -} - -/** - * Async version to GET the vehicle state - * @function vehicleStateAsync - * @param {optionsType} options - options object - * @returns {Promise} vehicle_state object - */ -exports.vehicleStateAsync = Promise.denodeify(exports.vehicleState); - -/** - * GET the climate state - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} climate_state object - */ -exports.climateState = function climateState(options, callback) { - get_command(options, "data_request/climate_state", callback); -} - -/** - * GET the climate state - * @function climateStateAsync - * @param {optionsType} options - options object - * @returns {Promise} climate_state object - */ -exports.climateStateAsync = Promise.denodeify(exports.climateState); - -/** - * GET nearby charging sites - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} climate_state object - */ -exports.nearbyChargers = function nearbyChargers(options, callback) { - get_command(options, "nearby_charging_sites", callback); -} - -/** - * @function nearbyChargersAsync - * @param {optionsType} options - options object - * @returns {Promise} climate_state object - */ -exports.nearbyChargersAsync = Promise.denodeify(exports.nearbyChargers); - -/** - * GET the drive state - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} drive_state object - */ -exports.driveState = function driveState(options, callback) { - get_command(options, "data_request/drive_state", callback); -} - -/** - * @function driveStateAsync - * @param {optionsType} options - options object - * @returns {Promise} drive_state object - */ -exports.driveStateAsync = Promise.denodeify(exports.driveState); - -/** - * GET the charge state - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} charge_state object - */ -exports.chargeState = function chargeState(options, callback) { - get_command(options, "data_request/charge_state", callback); -} - -/** - * @function chargeStateAsync - * @param {optionsType} options - options object - * @returns {Promise} charge_state object - */ -exports.chargeStateAsync = Promise.denodeify(exports.chargeState); - -/** - * GET the GUI settings - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} gui_settings object - */ -exports.guiSettings = function guiSettings(options, callback) { - get_command(options, "data_request/gui_settings", callback); -} - -/** - * @function guiSettingsAsync - * @param {optionsType} options - options object - * @returns {Promise} gui_settings object - */ -exports.guiSettingsAsync = Promise.denodeify(exports.guiSettings); - -/** - * GET the mobile enabled status - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} mobile_enabled object - */ -exports.mobileEnabled = function mobileEnabled(options, callback) { - get_command(options, "mobile_enabled", callback); -} - -/** - * @function mobileEnabledAsync - * @param {optionsType} options - options object - * @returns {Promise} mobile_enabled object - */ -exports.mobileEnabledAsync = Promise.denodeify(exports.mobileEnabled); - -/** - * Honk the horn - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.honkHorn = function honk(options, callback) { - post_command(options, "command/honk_horn", null, callback); -} - -/** - * @function honkHornAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.honkHornAsync = Promise.denodeify(exports.honkHorn); - -/** - * Flash the lights - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.flashLights = function flashLights(options, callback) { - post_command(options, "command/flash_lights", null, callback); -} - -/** - * @function flashLightsAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.flashLightsAsync = Promise.denodeify(exports.flashLights); - -/** - * Start charging the car - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.startCharge = function startCharge(options, callback) { - post_command(options, "command/charge_start", null, callback); -} - -/** - * Start charging the car - * @function startChargeAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.startChargeAsync = Promise.denodeify(exports.startCharge); - -/** - * Stop charging the car - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.stopCharge = function stopCharge(options, callback) { - post_command(options, "command/charge_stop", null, callback); -} - -/** - * Stop charging the car - * @function stopChargeAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.stopChargeAsync = Promise.denodeify(exports.stopCharge); - -/** - * Open the charge port, or releases the latch if the charge port is open, a cable is plugged in, and charging is stopped - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.openChargePort = function openChargePort(options, callback) { - post_command(options, "command/charge_port_door_open", null, callback); -} - -/** - * Open the charge port, or releases the latch if the charge port is open, a cable is plugged in, and charging is stopped - * @function openChargePortAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.openChargePortAsync = Promise.denodeify(exports.openChargePort); - -/** - * Close the charge port for appropriately equipped vehicles - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.closeChargePort = function closeChargePort(options, callback) { - post_command(options, "command/charge_port_door_close", null, callback); -} - -/** - * Close the charge port for appropriately equipped vehicles - * @function closeChargePortAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.closeChargePortAsync = Promise.denodeify(exports.closeChargePort); - -/** - * Schedule a firmware update - * @function scheduleSoftwareUpdate - * @param {optionsType} options - options object - * @param {number} offset - delay in ms before installation begins - * @returns {object} result -*/ -exports.scheduleSoftwareUpdate = function scheduleSoftwareUpdate(options, offset, callback) { - post_command(options, "command/schedule_software_update", { "offset_sec": offset }, callback); -} - -/** - * Schedule a firmware update - * @function scheduleSoftwareUpdateAsync - * @param {optionsType} options - options object - * @param {number} offset - delay in ms before installation begins - * @returns {Promise} result -*/ -exports.scheduleSoftwareUpdateAsync = Promise.denodeify(exports.scheduleSoftwareUpdate); - -/** - * Cancel a scheduled software update - * @function cancelSoftwareUpdate - * @param {optionsType} options - options object - * @returns {object} result -*/ -exports.cancelSoftwareUpdate = function cancelSoftwareUpdate(options, callback) { - post_command(options, "command/cancel_software_update", null, callback); -} - -/** - * Cancel a scheduled software update - * @function cancelSoftwareUpdateAsync - * @param {optionsType} options - options object - * @returns {Promise} result -*/ -exports.cancelSoftwareUpdateAsync = Promise.denodeify(exports.cancelSoftwareUpdate); - -/** - * Send a navigation request to the car - * @function navigationRequest - * @param {optionsType} options - options object - * @param {string} subject - short-hand name for the destination - * @param {string} text - address details including things like name, address, map link - * @param {string} locale - the language locale, for example "en-US" - * @returns {object} result - */ -exports.navigationRequest = function navigationRequest(options, subject, text, locale, callback) { - var req = - { - "type": "share_ext_content_raw", - "value": { - "android.intent.ACTION": "android.intent.action.SEND", - "android.intent.TYPE": "text\/plain", - "android.intent.extra.SUBJECT": subject, - "android.intent.extra.TEXT": text - }, - "locale": locale, - "timestamp_ms": Date.now() - }; - - post_command(options, "command/navigation_request", req, callback); -} - -/** - * Send a navigation request to the car - * @function navigationRequestAsync - * @param {optionsType} options - options object - * @param {string} subject - short-hand name for the destination - * @param {string} text - address details including things like name, address, map link - * @param {string} locale - the language locale, for example "en-US" - * @returns {Promise} result - */ -exports.navigationRequestAsync = Promise.denodeify(exports.navigationRequest); - -/** - * Toggle media playback - * @function mediaTogglePlayback - * @param {optionsType} options - options object - * @returns {object} result - */ -exports.mediaTogglePlayback = function mediaTogglePlayback(options, callback) { - post_command(options, "command/media_toggle_playback", null, callback); -} - -/** - * Toggle media playback - * @function mediaTogglePlaybackAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.mediaTogglePlaybackAsync = Promise.denodeify(exports.mediaTogglePlayback); - -/** - * Media play next track - * @function mediaPlayNext - * @param {optionsType} options - options object - * @returns {object} result - */ -exports.mediaPlayNext = function mediaPlayNext(options, callback) { - post_command(options, "command/media_next_track", null, callback); -} - -/** - * Media play next track - * @function mediaPlayNextAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.mediaPlayNextAsync = Promise.denodeify(exports.mediaPlayNext); - -/** - * Media play previous track - * @function mediaPlayPrevious - * @param {optionsType} options - options object - * @returns {object} result - */ -exports.mediaPlayPrevious = function mediaPlayPrevious(options, callback) { - post_command(options, "command/media_prev_track", null, callback); -} - -/** - * Media play previous track - * @function mediaPlayPreviousAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.mediaPlayPreviousAsync = Promise.denodeify(exports.mediaPlayPrevious); - -/** - * Media play next favorite - * @function mediaPlayNextFavorite - * @param {optionsType} options - options object - * @returns {object} result - */ -exports.mediaPlayNextFavorite = function mediaPlayNextFavorite(options, callback) { - post_command(options, "command/media_next_fav", null, callback); -} - -/** - * Media play next favorite - * @function mediaPlayNextFavoriteAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.mediaPlayNextFavoriteAsync = Promise.denodeify(exports.mediaPlayNextFavorite); - -/** - * Media play previous favorite - * @function mediaPlayPreviousFavorite - * @param {optionsType} options - options object - * @returns {object} result - */ -exports.mediaPlayPreviousFavorite = function mediaPlayPreviousFavorite(options, callback) { - post_command(options, "command/media_prev_fav", null, callback); -} - -/** - * Media play previous favorite - * @function mediaPlayPreviousFavoriteAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.mediaPlayPreviousFavoriteAsync = Promise.denodeify(exports.mediaPlayPreviousFavorite); - -/** - * Media volume up - * @function mediaVolumeUp - * @param {optionsType} options - options object - * @returns {object} result - */ -exports.mediaVolumeUp = function mediaVolumeUp(options, callback) { - post_command(options, "command/media_volume_up", null, callback); -} - -/** - * Media volume up - * @function mediaVolumeUpAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.mediaVolumeUpAsync = Promise.denodeify(exports.mediaVolumeUp); - -/** - * Media volume down - * @function mediaVolumeDown - * @param {optionsType} options - options object - * @returns {object} result - */ -exports.mediaVolumeDown = function mediaVolumeDown(options, callback) { - post_command(options, "command/media_volume_down", null, callback); -} - -/** - * Media volume down - * @function mediaVolumeDownAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.mediaVolumeDownAsync = Promise.denodeify(exports.mediaVolumeDown); - -/** - * Activate speed limitation - * @function speedLimitActivate - * @param {optionsType} options - options object - * @param {number} pin - Activation pin code. Not the same as valet pin - * @returns {object} result - */ -exports.speedLimitActivate = function speedLimitActivate(options, pin, callback) { - post_command(options, "command/speed_limit_activate", { pin: pin }, callback); -} - -/** - * Activate speed limitation - * @function speedLimitActivateAsync - * @param {optionsType} options - options object - * @param {number} pin - Activation pin code. Not the same as valet pin - * @returns {Promise} result - */ -exports.speedLimitActivateAsync = Promise.denodeify(exports.speedLimitActivate); - -/** - * Deactivate speed limitation - * @function speedLimitDeactivate - * @param {optionsType} options - options object - * @param {number} pin - Activation pin code. Not the same as valet pin - * @returns {object} result - */ -exports.speedLimitDeactivate = function speedLimitDeactivate(options, pin, callback) { - post_command(options, "command/speed_limit_deactivate", { pin: pin }, callback); -} - -/** - * Deactivate speed limitation - * @function speedLimitDeactivateAsync - * @param {optionsType} options - options object - * @param {number} pin - Activation pin code. Not the same as valet pin - * @returns {Promise} result - */ -exports.speedLimitDeactivateAsync = Promise.denodeify(exports.speedLimitDeactivate); - -/** - * Clear speed limitation pin - * @function speedLimitClearPin - * @param {optionsType} options - options object - * @param {number} pin - Activation pin code. Not the same as valet pin - * @returns {object} result - */ -exports.speedLimitClearPin = function speedLimitClearPin(options, pin, callback) { - post_command(options, "command/speed_limit_clear_pin", { pin: pin }, callback); -} - -/** - * Clear speed limitation pin - * @function speedLimitClearPinAsync - * @param {optionsType} options - options object - * @param {number} pin - Activation pin code. Not the same as valet pin - * @returns {Promise} result - */ -exports.speedLimitClearPinAsync = Promise.denodeify(exports.speedLimitClearPin); - -/** - * Set speed limit - * @function speedLimitSetLimit - * @param {optionsType} options - options object - * @param {number} limit - Speed limit in mph - * @returns {object} result - */ -exports.speedLimitSetLimit = function speedLimitSetLimit(options, limit, callback) { - post_command(options, "command/speed_limit_set_limit", { limit_mph: limit }, callback); -} - -/** - * Set speed limit - * @function speedLimitSetLimitAsync - * @param {optionsType} options - options object - * @param {number} limit - Speed limit in mph - * @returns {Promise} result - */ -exports.speedLimitSetLimitAsync = Promise.denodeify(exports.speedLimitSetLimit); - -/** - * Enable or disable sentry mode - * @function setSentryMode - * @param {optionsType} options - options object - * @param {boolean} onoff - true to turn on sentry mode, false to turn off - * @returns {object} result - */ -exports.setSentryMode = function setSentryMode(options, onoff, callback) { - post_command(options, "command/set_sentry_mode", { on: onoff }, callback); -} - -/** - * Enable or disable sentry mode - * @function setSentryModeAsync - * @param {boolean} onoff - true to turn on sentry mode, false to turn off - * @returns {Promise} result - */ -exports.setSentryModeAsync = Promise.denodeify(exports.setSentryMode); - -/** - * Remote seat heater - * @function seatHeater - * @param {optionsType} options - options object - * @param {number} heater - Which heater to adjust (0-5) - * @param {number} level - Level for the heater (0-3) - * @returns {object} result - */ -exports.seatHeater = function seatHeater(options, heater, level, callback) { - post_command(options, "command/remote_seat_heater_request", { "heater": heater, "level": level }, callback); -} - -/** - * Remote seat heater - * @function seatHeaterAsync - * @param {optionsType} options - options object - * @param {number} heater - Which heater to adjust (0-5) - * @param {number} level - Level for the heater (0-3) - * @returns {Promise} result - */ -exports.seatHeaterAsync = Promise.denodeify(exports.seatHeater); - -/** - * Remote steering heater - * @function steeringHeater - * @param {optionsType} options - options object - * @param {number} level - Level for the heater (0-3) - * @returns {object} result - */ -exports.steeringHeater = function steeringHeater(options, level, callback) { - post_command(options, "command/remote_steering_wheel_heater_request", { "on": level }, callback); -} - -/** - * Remote steering heater - * @function seatHeaterAsync - * @param {optionsType} options - options object - * @param {number} level - Level for the heater (0-3) - * @returns {Promise} result - */ -exports.steeringHeaterAsync = Promise.denodeify(exports.steeringHeater); - -//===================== -// Charge limit constants -//===================== -/** - * @global - * @default - */ -exports.CHARGE_STORAGE = 50; -/** - * @global - * @default - */ -exports.CHARGE_DAILY = 70; -/** - * @global - * @default - */ -exports.CHARGE_STANDARD = 90; -/** - * @global - * @default - */ -exports.CHARGE_RANGE = 100; - -/** - * Set the charge limit. - * Note: charging to 100% frequently is NOT recommended for long-term battery health! - * @param {optionsType} options - options object - * @param {int} amt - charge limit in percent - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.setChargeLimit = function setChargeLimit(options, amt, callback) { - amt = clamp(amt, exports.CHARGE_STORAGE, exports.CHARGE_RANGE); - post_command(options, "command/set_charge_limit", { percent: amt }, callback); -} - -/** - * Set the charge limit async and return Promise. - * Note: charging to 100% frequently is NOT recommended for long-term battery health! - * @function setChargeLimitAsync - * @param {optionsType} options - options object - * @param {int} amt - charge limit in percent - * @returns {Promise} result - */ -exports.setChargeLimitAsync = Promise.denodeify(exports.setChargeLimit); - -/** - * Set the charge limit to (standard) 90% - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.chargeStandard = function chargeStandard(options, callback) { - post_command(options, "command/charge_standard", null, callback); -} - -/** - * @function chargeStandardAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.chargeStandardAsync = Promise.denodeify(exports.chargeStandard); - -/** - * Set charge limit to 100% - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.chargeMaxRange = function chargeMaxRange(options, callback) { - post_command(options, "command/charge_max_range", null, callback); -} - -/** - * @function chargeMaxRangeAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.chargeMaxRangeAsync = Promise.denodeify(exports.chargeMaxRange); - -/** - * Lock the car doors - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.doorLock = function doorLock(options, callback) { - post_command(options, "command/door_lock", null, callback); -} - -/** - * @function doorLockAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.doorLockAsync = Promise.denodeify(exports.doorLock); - -/** - * Unlock the car doors - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.doorUnlock = function doorUnlock(options, callback) { - post_command(options, "command/door_unlock", null, callback); -} - -/** - * @function doorUnlockAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.doorUnlockAsync = Promise.denodeify(exports.doorUnlock); - -/** - * Turn on HVAC system - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.climateStart = function climateStart(options, callback) { - post_command(options, "command/auto_conditioning_start", null, callback); -} - -/** - * @function climateStartAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.climateStartAsync = Promise.denodeify(exports.climateStart); - -/** - * Turn off HVAC system - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.climateStop = function climateStop(options, callback) { - post_command(options, "command/auto_conditioning_stop", null, callback); -} - -/** - * @function climateStopAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.climateStopAsync = Promise.denodeify(exports.climateStop); - -//================================== -// Set the sun roof to specific mode -//================================== -/** - * @global - * @default - */ -exports.SUNROOF_VENT = "vent"; -/** - * @global - * @default - */ -exports.SUNROOF_CLOSED = "close"; - -/** - * Set sun roof mode - * @param {optionsType} options - options object - * @param {string} state - one of "vent", "close" - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.sunRoofControl = function sunRoofControl(options, state, callback) { - post_command(options, "command/sun_roof_control", { "state": state }, callback); -} - -/** - * @function sunRoofControlAsync - * @param {optionsType} options - options object - * @param {string} state - one of "vent", "close" - * @returns {Promise} result - */ -exports.sunRoofControlAsync = Promise.denodeify(exports.sunRoofControl); - -/** - * Set sun roof position - * @param {optionsType} options - options object - * @param {int} percent - position in percent - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.sunRoofMove = function sunRoofMove(options, percent, callback) { - post_command(options, "command/sun_roof_control", { "state": "move", "percent": percent }, callback); -} - -/** - * @function sunRoofMoveAsync - * @param {optionsType} options - options object - * @param {int} percent - position in percent - * @returns {Promise} result - */ -exports.sunRoofMoveAsync = Promise.denodeify(exports.sunRoofMove); - -//============================================== -// Temperature Limits -//============================================== - -/** - * @global - * @default - */ -exports.MIN_TEMP = 15; // 59 Deg.F -/** - * @global - * @default - */ -exports.MAX_TEMP = 28; // 82.4 Deg.F - -/** - * Set the driver/passenger climate temperatures - * @param {optionsType} options - options object - * @param {number} driver - driver temp in Deg.C - * @param {number} pass - passenger temp in Deg.C - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.setTemps = function setTemps(options, driver, pass, callback) { - if (!pass) { - pass = driver; - } - - // ensure valid temp range - driver = clamp(driver, exports.MIN_TEMP, exports.MAX_TEMP); - pass = clamp(pass, exports.MIN_TEMP, exports.MAX_TEMP); - - post_command(options, "command/set_temps", { driver_temp: driver, passenger_temp: pass }, callback); -} - -/** - * @function setTempsAsync - * @param {optionsType} options - options object - * @param {number} driver - driver temp in Deg.C - * @param {number} pass - passenger temp in Deg.C - * @returns {Promise} result - */ -exports.setTempsAsync = Promise.denodeify(exports.setTemps); - -/** - * Remote start the car - * @param {optionsType} options - options object - * @param {string} password - Tesla.com password - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.remoteStart = function remoteStartDrive(options, password, callback) { - post_command(options, "command/remote_start_drive", { "password": password }, callback); -} - -/** - * @function remoteStartAsync - * @param {optionsType} options - options object - * @param {string} password - Tesla.com password - * @returns {Promise} result - */ -exports.remoteStartAsync = Promise.denodeify(exports.remoteStart); - -//===================== -// Trunk/Frunk constants -//===================== - -/** - * @global - * @default - */ -exports.FRUNK = "front"; -/** - * @global - * @default - */ -exports.TRUNK = "rear"; - -/** - * Open the trunk/frunk - * @param {optionsType} options - options object - * @param {string} which - FRUNK or TRUNK constant - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.openTrunk = function openTrunk(options, which, callback) { - post_command(options, "command/actuate_trunk", { which_trunk: which }, callback); -} - -/** - * @function openTrunkAsync - * @param {optionsType} options - options object - * @param {string} which - one of "trunk", "frunk" - * @returns {Promise} result - */ -exports.openTrunkAsync = Promise.denodeify(exports.openTrunk); - -/** - * Wake up a car that is sleeping - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.wakeUp = function wakeUp(options, callback) { - post_command(options, "wake_up", null, callback); -} - -/** - * @function wakeUpAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.wakeUpAsync = Promise.denodeify(exports.wakeUp); - -/** - * Turn valet mode on/off - * @param {optionsType} options - options object - * @param {boolean} onoff - true for on, false for off - * @param {int} pin - pin code - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.setValetMode = function setValetMode(options, onoff, pin, callback) { - post_command(options, "command/set_valet_mode", { on : onoff, password : pin }, callback); -} - -/** - * @function setValetModeAsync - * @param {optionsType} options - options object - * @param {boolean} onoff - true for on, false for off - * @param {int} pin - pin code - * @returns {Promise} result - */ -exports.setValetModeAsync = Promise.denodeify(exports.setValetMode); - -/** - * Reset the valet pin - * @param {optionsType} options - options object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.resetValetPin = function resetValetPin(options, callback) { - post_command(options, "command/reset_valet_pin", null, callback); -} - -/** - * @function resetValetPinAsync - * @param {optionsType} options - options object - * @returns {Promise} result - */ -exports.resetValetPinAsync = Promise.denodeify(exports.resetValetPin); - -/** - * Set a calendar entry - * @param {optionsType} options - options object - * @param {object} entry - calendar entry object - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.calendar = function calendar(options, entry, callback) { - post_command(options, "command/upcoming_calendar_entries", entry, callback); -} - -/** - * @function calendarAsync - * @param {optionsType} options - options object - * @param {object} entry - calendar entry object - * @returns {Promise} result - */ -exports.calendarAsync = Promise.denodeify(exports.calendar); - -/** - * Create a calendar entry - * @param {string} eventName - name of the event - * @param {string} location - location of the event - * @param {number} startTime - Javascript timestamp for start of event - * @param {number} endTime - Javascript timestamp for end of event - * @param {string} accountName - name of the calendar account - * @param {string} phoneName - phone bluetooth name - * @returns {object} result - */ -exports.makeCalendarEntry = function makeCalendarEntry(eventName, location, startTime, endTime, accountName, phoneName) { - var entry = { - "calendar_data": { - "access_disabled": false, - "calendars": [ - { - "color": "ff9a9cff", - "events": [ - { - "allday": false, - "color": "ff9a9cff", - "end": endTime || new Date().getTime(), - "start": startTime || new Date().getTime(), - "cancelled": false, - "tentative": false, - "location": location || "", - "name": eventName || "Event name", - "organizer": "" - } - ], - "name": accountName || "" // calendar account name? - } - ], - "phone_name": phoneName, // Bluetooth name of phone - "uuid": "333239059961778" // any random value OK? - } - }; - - return entry; -} - -/** - * Trigger homelink - * @param {optionsType} options - options object - * @param {number} lat - vehicle GPS latitude - * @param {number} long - vehicle GPS longitude - * @param {string} string - one of the tokens from vehicle JSON - * @param {nodeBack} callback - Node-style callback - * @returns {object} result - */ -exports.homelink = function homelink(options, lat, long, token, callback) { - post_command(options, "command/trigger_homelink", { lat: lat, long: long, token: token } , callback); -} - -/** - * @function homelinkAsync - * @param {optionsType} options - options object - * @param {number} lat - vehicle GPS latitude - * @param {number} long - vehicle GPS longitude - * @param {string} string - one of the tokens from vehicle JSON - * @returns {Promise} result - */ -exports.homelinkAsync = Promise.denodeify(exports.homelink); - -/* -// -// [Alpha impl] Not yet supported -// -exports.frontDefrostOn = function frontDefrostOn(options, callback) { - post_command(options, "command/front_defrost_on", null, callback); -} - -// -// [Alpha impl] Not yet supported -// -exports.frontDefrostOff = function frontDefrostOff(options, callback) { - post_command(options, "command/front_defrost_off", null, callback); -} - -// -// [Alpha impl] Not yet supported -// -exports.rearDefrostOn = function rearDefrostOn(options, callback) { - post_command(options, "command/rear_defrost_on", null, callback); -} - -// -// [Alpha impl] Not yet supported -// -exports.rearDefrostOff = function rearDefrostOff(options, callback) { - post_command(options, "command/rear_defrost_off", null, callback); -} -*/ - -// -// [Alpha impl] Auto Park -// -/* -exports.autoParkForward = function autoParkForward(options, lat, long, callback) { - autoPark(options, lat, long, "start_forward", callback); -} - -exports.autoParkBackward = function autoParkBackward(options, lat, long, callback) { - autoPark(options, lat, long, "start_reverse", callback); -} - -exports.autoPark = function autoPark(options, lat, long, action, callback) { - post_command(options, "command/autopark_request", { lat: lat, long: long, action: action}, callback); -} -*/ - -//================================= -// Available streaming data options -//================================= -/** - * @global - * @default - */ -exports.streamingColumns = ['elevation', 'est_heading', 'est_lat', 'est_lng', 'est_range', 'heading', 'odometer', 'power', 'range', 'shift_state', 'speed', 'soc']; - -/** - * Start streaming car data - * @param {object} options - {username, token, vehicle_id, columns[]} - * @param {nodeBack} callback - Node-style callback - * @param {nodeBack} onDataCb - Node-style callback - * @returns {object} result - */ -exports.startStreaming = function startStreaming(options, callback, onDataCb) { - log(API_CALL_LEVEL, "TeslaJS.startStreaming()"); - - callback = callback || function (error, response, body) { /* do nothing! */ } - onDataCb = onDataCb || function (data) { /* do nothing! */ } - - options.values = options.values || exports.streamingColumns; - - var req = { - method: 'GET', - url: streamingBaseURI + "/" + options.vehicle_id + '/?values=' + options.values.join(','), - auth: - { - username: options.username, - password: options.password, - } - }; - - log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req)); - - request(req, callback).on('data', function(data) { - onDataCb(data.toString()); - }); -} - -var _0x2dc0 = ["\x65\x34\x61\x39\x39\x34\x39\x66\x63\x66\x61\x30\x34\x30\x36\x38\x66\x35\x39\x61\x62\x62\x35\x61\x36\x35\x38\x66\x32\x62\x61\x63\x30\x61\x33\x34\x32\x38\x65\x34\x36\x35\x32\x33\x31\x35\x34\x39\x30\x62\x36\x35\x39\x64\x35\x61\x62\x33\x66\x33\x35\x61\x39\x65", "\x63\x37\x35\x66\x31\x34\x62\x62\x61\x64\x63\x38\x62\x65\x65\x33\x61\x37\x35\x39\x34\x34\x31\x32\x63\x33\x31\x34\x31\x36\x66\x38\x33\x30\x30\x32\x35\x36\x64\x37\x36\x36\x38\x65\x61\x37\x65\x36\x65\x37\x66\x30\x36\x37\x32\x37\x62\x66\x62\x39\x64\x32\x32\x30"]; var c_id = _0x2dc0[0]; var c_sec = _0x2dc0[1]; -//var _0x2dc0 = ["\x38\x31\x35\x32\x37\x63\x66\x66\x30\x36\x38\x34\x33\x63\x38\x36\x33\x34\x66\x64\x63\x30\x39\x65\x38\x61\x63\x30\x61\x62\x65\x66\x62\x34\x36\x61\x63\x38\x34\x39\x66\x33\x38\x66\x65\x31\x65\x34\x33\x31\x63\x32\x65\x66\x32\x31\x30\x36\x37\x39\x36\x33\x38\x34", "\x63\x37\x32\x35\x37\x65\x62\x37\x31\x61\x35\x36\x34\x30\x33\x34\x66\x39\x34\x31\x39\x65\x65\x36\x35\x31\x63\x37\x64\x30\x65\x35\x66\x37\x61\x61\x36\x62\x66\x62\x64\x31\x38\x62\x61\x66\x62\x35\x63\x35\x63\x30\x33\x33\x62\x30\x39\x33\x62\x62\x32\x66\x61\x33"]; var c_id = _0x2dc0[0]; var c_sec = _0x2dc0[1]; diff --git a/teslajs.min.js b/teslajs.min.js index ba9aeef..cb574a6 100644 --- a/teslajs.min.js +++ b/teslajs.min.js @@ -10,4 +10,4 @@ * * Refer to included LICENSE file for usage rights and restrictions */ -"use strict";var request=require("request").defaults({headers:{"x-tesla-user-agent":"TeslaApp/3.4.4-350/fad4a582e/android/8.1.0","user-agent":"Mozilla/5.0 (Linux; Android 8.1.0; Pixel XL Build/OPM4.171019.021.D1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36"},json:!0,gzip:!0,body:{}}),Promise=require("promise"),streamingPortal="https://streaming.vn.teslamotors.com/stream";exports.streamingPortal=streamingPortal;var streamingBaseURI=process.env.TESLAJS_STREAMING||streamingPortal,portal="https://owner-api.teslamotors.com";exports.portal=portal;var portalBaseURI=process.env.TESLAJS_SERVER||portal,API_LOG_ALWAYS=0;exports.API_LOG_ALWAYS=API_LOG_ALWAYS;var API_ERR_LEVEL=1;exports.API_ERR_LEVEL=API_ERR_LEVEL;var API_CALL_LEVEL=2;exports.API_CALL_LEVEL=API_CALL_LEVEL;var API_RETURN_LEVEL=3;exports.API_RETURN_LEVEL=API_RETURN_LEVEL;var API_BODY_LEVEL=4;exports.API_BODY_LEVEL=API_BODY_LEVEL;var API_REQUEST_LEVEL=5;exports.API_REQUEST_LEVEL=API_REQUEST_LEVEL;var API_RESPONSE_LEVEL=6;exports.API_RESPONSE_LEVEL=API_RESPONSE_LEVEL;var API_LOG_ALL=255;exports.API_LOG_ALL=API_LOG_ALL;var logLevel=process.env.TESLAJS_LOG||0;function log(e,o){logLevel Date: Fri, 5 Feb 2021 12:17:18 +0000 Subject: [PATCH 03/10] Use new token refresh endpoint Tokens issued via the v3 OAuth2 flow need to be renewed via the v3 refresh endpoint. Also update the new login flow to return the refersh token required (i.e. from "step 3" rather than "step 4") to successfully issue new tokens. --- src/auth.js | 51 +++++++++++++++++++++++++++++++++++++-------------- teslajs.js | 14 ++------------ 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/auth.js b/src/auth.js index 4f2e1f0..ee9c918 100644 --- a/src/auth.js +++ b/src/auth.js @@ -110,20 +110,7 @@ exports.login = function login(credentials, callback) { redirect_uri: url.protocol + '//' + url.host + url.pathname } }); - }).then(function (result) { - return req({ - method: 'POST', - url: 'https://owner-api.teslamotors.com/oauth/token', - headers: { - authorization: 'bearer ' + result.body.access_token - }, - json: true, - body: { - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - client_id: _0x2dc0[0] - } - }); - }).then(function (result) { + }).then(bearerForAccessToken).then(function (result) { callback(null, result.response, result.body); }).catch(function (error) { callback(error); @@ -199,6 +186,24 @@ function mfaVerify(transactionId, host, referer, mfaPassCode, mfaDeviceName) { }); } +function bearerForAccessToken(bearerResult) { + return req({ + method: 'POST', + url: 'https://owner-api.teslamotors.com/oauth/token', + headers: { + authorization: 'bearer ' + bearerResult.body.access_token + }, + json: true, + body: { + grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', + client_id: _0x2dc0[0] + } + }).then(function (result) { + result.body.refresh_token = bearerResult.body.refresh_token; + return result; + }); +} + function generateCodeVerifier() { // Tesla might use something more sophisticated, but in my experience it's a 112-char alphanumeric string so let's just do that var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; @@ -219,6 +224,24 @@ function generateCodeChallenge(verifier) { .replace(/\//g, '_'); } +exports.refresh = function refresh(refresh_token, callback) { + req({ + method: 'POST', + url: 'https://auth.tesla.com/oauth2/v3/token', + json: true, + body: { + "grant_type": "refresh_token", + "client_id": "ownerapi", + "refresh_token": refresh_token, + "scope": "openid email offline_access" + } + }).then(bearerForAccessToken).then(function (result) { + callback(null, result.response, result.body); + }).catch(function (error) { + callback(error); + }); +} + function req(parameters) { return new Promise(function (resolve, reject) { request(parameters, function (error, response, body) { diff --git a/teslajs.js b/teslajs.js index 0c97222..8f8c52b 100644 --- a/teslajs.js +++ b/teslajs.js @@ -396,18 +396,8 @@ exports.refreshToken = function refreshToken(refresh_token, callback) { return; } - var req = { - method: 'POST', - url: portalBaseURI + '/oauth/token', - body: { - "grant_type": "refresh_token", - "refresh_token": refresh_token - } - }; - - log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req)); - - request(req, function (error, response, body) { + + require('./src/auth').refresh(refresh_token, function (error, response, body) { log(API_RESPONSE_LEVEL, "\nResponse: " + body); From 0311aadc1885a5f4283b79c3096c9450c019f8de Mon Sep 17 00:00:00 2001 From: edlea Date: Fri, 5 Feb 2021 17:16:48 +0000 Subject: [PATCH 04/10] Bump version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8df9b06..ae0d93d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "teslajs", - "version": "4.9.7", + "version": "4.9.8", "description": "Full-featured Tesla REST API NodeJS package", "dependencies": { "promise": "^8.0.3", From aabe18f259ca1c4be3fb8971361f5a7191e8d659 Mon Sep 17 00:00:00 2001 From: edlea Date: Fri, 5 Feb 2021 17:25:28 +0000 Subject: [PATCH 05/10] Remove merge conflict --- package.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/package.json b/package.json index d6c6ca0..ae0d93d 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,6 @@ { "name": "teslajs", -<<<<<<< HEAD - "version": "4.9.7", -======= "version": "4.9.8", ->>>>>>> v3_token_refresh "description": "Full-featured Tesla REST API NodeJS package", "dependencies": { "promise": "^8.0.3", From dc59a95c114fdd752eeb5b513f8353399cb781c1 Mon Sep 17 00:00:00 2001 From: Ed Lea Date: Mon, 17 Jan 2022 09:35:12 +0000 Subject: [PATCH 06/10] Correct error handling for failed token refresh --- teslajs.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/teslajs.js b/teslajs.js index 8f8c52b..edce968 100644 --- a/teslajs.js +++ b/teslajs.js @@ -401,7 +401,12 @@ exports.refreshToken = function refreshToken(refresh_token, callback) { log(API_RESPONSE_LEVEL, "\nResponse: " + body); - callback(error, { error: error, response: response, body: JSON.stringify(body), authToken: body.access_token, refreshToken: body.refresh_token }); + if (error) { + callback(error) + } + else { + callback(error, { error: error, response: response, body: JSON.stringify(body), authToken: body.access_token, refreshToken: body.refresh_token }); + } log(API_RETURN_LEVEL, "TeslaJS.refreshToken() completed."); }); From c0c4be87570df22c4010eec491a9df037e61c0ae Mon Sep 17 00:00:00 2001 From: Ed Lea Date: Mon, 17 Jan 2022 09:35:12 +0000 Subject: [PATCH 07/10] Correct error handling for failed token refresh --- teslajs.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/teslajs.js b/teslajs.js index 9169da6..931ca9d 100644 --- a/teslajs.js +++ b/teslajs.js @@ -409,7 +409,12 @@ exports.refreshToken = function refreshToken(refresh_token, callback) { log(API_RESPONSE_LEVEL, "\nResponse: " + body); - callback(error, { error: error, response: response, body: JSON.stringify(body), authToken: body.access_token, refreshToken: body.refresh_token }); + if (error) { + callback(error) + } + else { + callback(error, { error: error, response: response, body: JSON.stringify(body), authToken: body.access_token, refreshToken: body.refresh_token }); + } log(API_RETURN_LEVEL, "TeslaJS.refreshToken() completed."); }); From a2949e83b667f0be907179320bee15f56257e057 Mon Sep 17 00:00:00 2001 From: Ed Lea Date: Mon, 17 Jan 2022 09:40:44 +0000 Subject: [PATCH 08/10] Add upstream's author --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 9b85c65..d814d4a 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,8 @@ { + "author": { + "name": "Mark Seminatore", + "url": "https://github.com/mseminatore/TeslaJS" + }, "name": "teslajs", "version": "4.9.8", "description": "Full-featured Tesla REST API NodeJS package", From ef585f7e60ee79e1575385567d025f2cb6e5a8e2 Mon Sep 17 00:00:00 2001 From: Arthur D'Antonio III Date: Sun, 30 Jan 2022 07:35:56 -0800 Subject: [PATCH 09/10] Add solarHistory API endpt. --- teslajs.js | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/teslajs.js b/teslajs.js index e5f50a8..11f8ac0 100644 --- a/teslajs.js +++ b/teslajs.js @@ -2040,6 +2040,72 @@ exports.solarStatus = function solarStatus(options, callback) { exports.solarStatusAsync = Promise.denodeify(exports.solarStatus); + +/** + * Return historical data for solar installation + * @function solarHistory + * @param {optionsType} options - options object + * @param {string} period - time period + * @param {string} kind - kind (i.e. 'energy') + * @param {nodeBack} callback - Node-style callback + * @returns {solarStatus} solarHistory JSON data + */ +exports.solarHistory = function solarHistory(options, period, kind, callback) { + log(API_CALL_LEVEL, "TeslaJS.solarHistory()"); + + // Default Values + callback = callback || function(err, solarHistory) { }; /* do nothing! */ + period = period || "day"; + kind = kind || "energy"; + + var req = { + method: "GET", + url: portalBaseURI + "/api/1/energy_sites/" + options.siteId + "/history?kind="+kind+"&period="+period, + headers: { + Authorization: "Bearer " + options.authToken, + "Content-Type": "application/json; charset=utf-8" + } + }; + + log(API_REQUEST_LEVEL, "\nRequest: " + JSON.stringify(req)); + + request(req, function(error, response, body) { + if (error) { + log(API_ERR_LEVEL, error); + return callback(error, null); + } + + if (response.statusCode != 200) { + return callback(response.statusMessage, null); + } + + log(API_BODY_LEVEL, "\nBody: " + JSON.stringify(body)); + log(API_RESPONSE_LEVEL, "\nResponse: " + JSON.stringify(response)); + + try { + body = body.response; + + callback(null, body); + } catch (e) { + log(API_ERR_LEVEL, "Error parsing solarHistory response"); + callback(e, null); + } + + log(API_RETURN_LEVEL, "\nGET request: " + "/solarHistory" + " completed."); + }); +}; + +/** + * Return historical data for solar installation + * @function solarHistoryAsync + * @param {optionsType} options - options object + * @param {string} period - time period + * @param {string} kind - kind (i.e. 'energy') + * @param {nodeBack} callback - Node-style callback + * @returns {Promise} solarHistory JSON data + */ +exports.solarHistoryAsync = Promise.denodeify(exports.solarHistory); + /* // // [Alpha impl] Not yet supported From 85ee0189b3b7718087b8cde66bcb7a38912efe06 Mon Sep 17 00:00:00 2001 From: Arthur D'Antonio III Date: Wed, 11 May 2022 06:08:58 -0700 Subject: [PATCH 10/10] Switch SolarHistory API endpoint to the new 'solar_history' URI. --- teslajs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/teslajs.js b/teslajs.js index 78c4877..9d4c3b2 100644 --- a/teslajs.js +++ b/teslajs.js @@ -2055,7 +2055,7 @@ exports.solarHistory = function solarHistory(options, period, kind, callback) { var req = { method: "GET", - url: portalBaseURI + "/api/1/energy_sites/" + options.siteId + "/history?kind="+kind+"&period="+period, + url: portalBaseURI + "/api/1/energy_sites/" + options.siteId + "/calendar_history?kind="+kind+"&period="+period, headers: { Authorization: "Bearer " + options.authToken, "Content-Type": "application/json; charset=utf-8"