tesla-inventory 1.8.46 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "name": "tesla-inventory",
3
3
  "description": "Retrieve real-time data from Tesla Inventory.",
4
4
  "homepage": "https://nicedoc.io/Kikobeats/tesla-inventory",
5
- "version": "1.8.46",
6
- "main": "index.js",
5
+ "version": "2.0.1",
6
+ "main": "src/index.js",
7
7
  "author": {
8
8
  "email": "josefrancisco.verdu@gmail.com",
9
9
  "name": "Kiko Beats",
@@ -52,6 +52,7 @@
52
52
  "json-future": "latest",
53
53
  "lodash": "latest",
54
54
  "markdown-tables-to-json": "latest",
55
+ "meow": "9",
55
56
  "nano-staged": "latest",
56
57
  "npm-check-updates": "latest",
57
58
  "prettier-standard": "latest",
@@ -64,25 +65,15 @@
64
65
  "node": ">= 14"
65
66
  },
66
67
  "files": [
67
- "codes.json",
68
- "index.js",
69
- "inventories.js",
70
- "prices",
71
- "scripts"
68
+ "src"
72
69
  ],
73
70
  "scripts": {
74
71
  "clean": "rm -rf node_modules",
75
- "codes": "(node scripts/codes.js && git add codes.json && git commit -m 'build(update): codes' --no-verify && git push) || true",
76
72
  "contributors": "(git-authors-cli && finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true",
77
- "cronjob": "npm run prices && npm run codes && npm run healthcheck",
78
- "healthcheck": "curl -sL https://hc-ping.com/b0792794-6548-42d5-9981-b50a401d7667",
79
73
  "lint": "standard-markdown README.md && standard",
80
74
  "postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)",
81
75
  "prerelease": "npm run update:check && npm run contributors",
82
76
  "pretest": "npm run lint",
83
- "prices": "npm run prices:europe && npm run prices:america",
84
- "prices:america": "(DEBUG=tesla-inventory* node scripts/prices/america.js && git add prices/america.json && git commit -m 'build(update): prices for North America' --no-verify && git push) || true",
85
- "prices:europe": "(DEBUG=tesla-inventory* node scripts/prices/europe.js && git add prices/europe.json && git commit -m 'build(update): prices for Europe' --no-verify && git push) || true",
86
77
  "release": "standard-version -a",
87
78
  "release:github": "conventional-github-releaser -p angular",
88
79
  "release:tags": "git push --follow-tags origin HEAD:master",
@@ -97,6 +88,16 @@
97
88
  "@commitlint/config-conventional"
98
89
  ]
99
90
  },
91
+ "exports": {
92
+ ".": "./src/index.js",
93
+ "./codes": "./src/codes.json",
94
+ "./inventories": "./src/inventories/index.js",
95
+ "./inventories/euro": "./src/inventories/euro.js",
96
+ "./package.json": "./package.json",
97
+ "./prices/cad": "./src/prices/cad.json",
98
+ "./prices/eur": "./src/prices/eur.json",
99
+ "./prices/usd": "./src/prices/usd.json"
100
+ },
100
101
  "nano-staged": {
101
102
  "*.js": [
102
103
  "prettier-standard"
@@ -306,58 +306,62 @@
306
306
  "MS04": "Model S",
307
307
  "MS05": "Model S",
308
308
  "MS06": "Model S",
309
- "MT300": "Standard Range Rear-Wheel Drive",
310
- "MT301": "Standard Range Plus Rear-Wheel Drive",
311
- "MT302": "Long Range Rear-Wheel Drive",
312
- "MT303": "Long Range All-Wheel Drive",
313
- "MT304": "Long Range All-Wheel Drive Performance",
314
- "MT305": "Mid Range Rear-Wheel Drive",
315
- "MT307": "Mid Range Rear-Wheel Drive",
316
- "MT308": "Standard Range Plus Rear-Wheel Drive",
317
- "MT309": "Standard Range Plus Rear-Wheel Drive",
318
- "MT310": "Long Range All-Wheel Drive",
319
- "MT311": "Long Range All-Wheel Drive Performance",
320
- "MT314": "Standard Range Plus Rear-Wheel Drive",
321
- "MT315": "Long Range All-Wheel Drive",
322
- "MT316": "Long Range All-Wheel Drive",
323
- "MT317": "Long Range All-Wheel Drive Performance",
324
- "MT320": "Standard Range Plus Rear-Wheel Drive",
325
- "MT321": "Long Range All-Wheel Drive",
326
- "MT322": "Standard Range Plus Rear-Wheel Drive",
327
- "MT323": "Long Range All-Wheel Drive",
328
- "MT324": "Long Range All-Wheel Drive",
329
- "MT328": "Long Range All-Wheel Drive",
330
- "MT336": "Standard Range Plus Rear-Wheel Drive",
331
- "MT337": "Standard Range Plus Rear-Wheel Drive",
332
- "MT340": "Long Range All-Wheel Drive Performance",
333
- "MTS01": "Standard Range",
334
- "MTS03": "Long Range",
335
- "MTS04": "Performance",
336
- "MTS05": "Long Range",
337
- "MTS06": "Performance",
338
- "MTS07": "Long Range Plus",
339
- "MTS08": "Performance",
340
- "MTS09": "Plaid+",
341
- "MTS10": "Long Range",
342
- "MTS11": "Plaid",
343
- "MTS13": "Long Range",
344
- "MTS14": "Plaid",
345
- "MTX01": "Standard Range",
346
- "MTX03": "Long Range",
347
- "MTX04": "Performance",
348
- "MTX05": "Long Range Plus",
349
- "MTX06": "Performance",
350
- "MTX07": "Long Range Plus",
351
- "MTX08": "Performance",
352
- "MTX10": "Long Range",
353
- "MTX11": "Plaid",
354
- "MTY01": "Standard Range Rear-Wheel Drive",
355
- "MTY02": "Long Range Rear-Wheel Drive",
356
- "MTY03": "Long Range All-Wheel Drive",
357
- "MTY04": "Long Range All-Wheel Drive Performance",
358
- "MTY05": "Long Range All-Wheel Drive Performance",
359
- "MTY07": "Long Range All-Wheel Drive",
360
- "MTY09": "Long Range All-Wheel Drive",
309
+ "MT300": "Model 3 Standard Range Rear-Wheel Drive",
310
+ "MT301": "Model 3 Standard Range Plus Rear-Wheel Drive",
311
+ "MT302": "Model 3 Long Range Rear-Wheel Drive",
312
+ "MT303": "Model 3 Long Range All-Wheel Drive",
313
+ "MT304": "Model 3 Long Range All-Wheel Drive Performance",
314
+ "MT305": "Model 3 Mid Range Rear-Wheel Drive",
315
+ "MT307": "Model 3 Mid Range Rear-Wheel Drive",
316
+ "MT308": "Model 3 Standard Range Plus Rear-Wheel Drive",
317
+ "MT309": "Model 3 Standard Range Plus Rear-Wheel Drive",
318
+ "MT310": "Model 3 Long Range All-Wheel Drive",
319
+ "MT311": "Model 3 Long Range All-Wheel Drive Performance",
320
+ "MT314": "Model 3 Standard Range Plus Rear-Wheel Drive",
321
+ "MT315": "Model 3 Long Range All-Wheel Drive",
322
+ "MT316": "Model 3 Long Range All-Wheel Drive",
323
+ "MT317": "Model 3 Long Range All-Wheel Drive Performance",
324
+ "MT320": "Model 3 Standard Range Plus Rear-Wheel Drive",
325
+ "MT321": "Model 3 Long Range All-Wheel Drive",
326
+ "MT322": "Model 3 Standard Range Plus Rear-Wheel Drive",
327
+ "MT323": "Model 3 Long Range All-Wheel Drive",
328
+ "MT324": "Model 3 Long Range All-Wheel Drive",
329
+ "MT328": "Model 3 Long Range All-Wheel Drive",
330
+ "MT336": "Model 3 Standard Range Plus Rear-Wheel Drive",
331
+ "MT337": "Model 3 Standard Range Plus Rear-Wheel Drive",
332
+ "MT340": "Model 3 Long Range All-Wheel Drive Performance",
333
+ "MTS01": "Model S Standard Range",
334
+ "MTS03": "Model S Long Range",
335
+ "MTS04": "Model S Performance",
336
+ "MTS05": "Model S Long Range",
337
+ "MTS06": "Model S Performance",
338
+ "MTS07": "Model S Long Range Plus",
339
+ "MTS08": "Model S Performance",
340
+ "MTS09": "Model S Plaid+",
341
+ "MTS10": "Model S Long Range",
342
+ "MTS11": "Model S Plaid",
343
+ "MTS13": "Model S Dual Motor All-Wheel Drive",
344
+ "MTS14": "Model S Plaid Tri Motor All-Wheel Drive",
345
+ "MTX01": "Model X Standard Range",
346
+ "MTX03": "Model X Long Range",
347
+ "MTX04": "Model X Performance",
348
+ "MTX05": "Model X Long Range Plus",
349
+ "MTX06": "Model X Performance",
350
+ "MTX07": "Model X Long Range Plus",
351
+ "MTX08": "Model X Performance",
352
+ "MTX09": "Model X Plaid+",
353
+ "MTX10": "Model X Long Range",
354
+ "MTX11": "Model X Plaid",
355
+ "MTX13": "Model X Plaid Dual Motor All-Wheel Drive",
356
+ "MTX14": "Model X Plaid Tri Motor All-Wheel Drive",
357
+ "MTY01": "Model Y Standard Range Rear-Wheel Drive",
358
+ "MTY02": "Model Y Long Range Rear-Wheel Drive",
359
+ "MTY03": "Model Y Long Range All-Wheel Drive",
360
+ "MTY04": "Model Y Long Range All-Wheel Drive Performance",
361
+ "MTY05": "Model Y Long Range All-Wheel Drive Performance",
362
+ "MTY07": "Model Y Long Range All-Wheel Drive",
363
+ "MTY09": "Model Y Long Range All-Wheel Drive",
364
+ "MTY11": "Model Y Long Range All-Wheel Drive",
361
365
  "MX06": "Model X 2021+",
362
366
  "MY01": "Model Y Austin?",
363
367
  "MY02": "Model Y Berlin?",
package/src/index.js ADDED
@@ -0,0 +1,52 @@
1
+ 'use strict'
2
+
3
+ const inventories = require('./inventories')
4
+
5
+ const got = require('got').extend({
6
+ url: 'https://www.tesla.com/inventory/api/v1/inventory-results',
7
+ responseType: 'json',
8
+ resolveBodyOnly: true
9
+ })
10
+
11
+ const toLowerCase = ({ results: items, total_matches_found: totalMatchesFound }) => ({
12
+ items,
13
+ total: Number(totalMatchesFound)
14
+ })
15
+
16
+ const ITEMS_PER_PAGE = 50
17
+
18
+ module.exports = async (inventory, opts, { headers, ...gotOpts } = {}) => {
19
+ if (!inventories[inventory]) {
20
+ throw new TypeError(`Tesla inventory \`${inventory}\` not found!`)
21
+ }
22
+
23
+ const inventoryProps = inventories[inventory]
24
+
25
+ if (opts.model && !opts.model.startsWith('m')) {
26
+ opts.model = `m${opts.model}`
27
+ }
28
+
29
+ const paginate = (outsideOffset = 0) =>
30
+ got({
31
+ searchParams: {
32
+ query: JSON.stringify({
33
+ outsideOffset,
34
+ count: 0,
35
+ query: {
36
+ ...inventoryProps,
37
+ ...opts
38
+ }
39
+ })
40
+ },
41
+ ...gotOpts,
42
+ headers: { 'user-agent': undefined, ...headers }
43
+ }).then(toLowerCase)
44
+
45
+ const page = await paginate()
46
+ if (page.total < ITEMS_PER_PAGE) return page.items
47
+
48
+ const nRequests = Math.ceil(page.total / ITEMS_PER_PAGE) - 1
49
+ const offsets = [...Array(nRequests).keys()].map(n => (n + 1) * page.items.length)
50
+ const pages = await Promise.all(offsets.map(paginate))
51
+ return pages.reduce((acc, { items }) => acc.concat(items), page.items)
52
+ }
@@ -0,0 +1,20 @@
1
+ 'use strict'
2
+
3
+ const EURO_COUNTRIES = [
4
+ 'Österreich',
5
+ 'Belgium',
6
+ 'Deutschland',
7
+ 'Spain',
8
+ 'Finland',
9
+ 'France',
10
+ 'Ireland',
11
+ 'Italy',
12
+ 'Luxembourg',
13
+ 'Netherlands',
14
+ 'Portugal',
15
+ 'România'
16
+ ]
17
+
18
+ module.exports = Object.fromEntries(
19
+ Object.entries(require('.')).filter(([, { country }]) => EURO_COUNTRIES.includes(country))
20
+ )
@@ -0,0 +1,26 @@
1
+ module.exports = {
2
+ at: { country: 'Österreich', language: 'de', market: 'AT', super_region: 'europe' },
3
+ be: { country: 'Belgium', language: 'nl', market: 'BE', super_region: 'europe' },
4
+ ca: { country: 'Canada', language: 'en', market: 'CA', super_region: 'north america' },
5
+ ch: { country: 'Switzerland', language: 'de', market: 'CH', super_region: 'europe' },
6
+ cz: { country: 'Česko', language: 'cs', market: 'CZ', super_region: 'europe' },
7
+ de: { country: 'Deutschland', language: 'de', market: 'DE', super_region: 'europe' },
8
+ dk: { country: 'Danmark', language: 'da', market: 'DK', super_region: 'europe' },
9
+ es: { country: 'Spain', language: 'es', market: 'ES', super_region: 'europe' },
10
+ fi: { country: 'Finland', language: 'fi', market: 'FI', super_region: 'europe' },
11
+ fr: { country: 'France', language: 'fr', market: 'FR', super_region: 'europe' },
12
+ gb: { country: 'United Kingdom', language: 'en', market: 'GB', super_region: 'europe' },
13
+ hu: { country: 'Magyarország', language: 'hu', market: 'HU', super_region: 'europe' },
14
+ ie: { country: 'Ireland', language: 'en', market: 'IE', super_region: 'europe' },
15
+ is: { country: 'Island', language: 'is', market: 'IS', super_region: 'europe' },
16
+ it: { country: 'Italy', language: 'it', market: 'IT', super_region: 'europe' },
17
+ lu: { country: 'Luxembourg', language: 'fr', market: 'LU', super_region: 'europe' },
18
+ mx: { country: 'Mexico', language: 'es', market: 'MX', super_region: 'north america' },
19
+ nl: { country: 'Netherlands', language: 'nl', market: 'NL', super_region: 'europe' },
20
+ no: { country: 'Norway', language: 'no', market: 'NO', super_region: 'europe' },
21
+ pr: { country: 'Puerto Rico', language: 'es', market: 'PR', super_region: 'north america' },
22
+ pt: { country: 'Portugal', language: 'pt', market: 'PT', super_region: 'europe' },
23
+ ro: { country: 'România', language: 'ro', market: 'RO', super_region: 'europe' },
24
+ se: { country: 'Sweden', language: 'sv', market: 'SE', super_region: 'europe' },
25
+ us: { country: 'United States', language: 'en', market: 'US', super_region: 'north america' }
26
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "APF2": 12800,
3
+ "IWC00": 2600,
4
+ "MTS11": 86000,
5
+ "MTS14": 86000,
6
+ "PBSB": 2000,
7
+ "PMNG": 2000,
8
+ "PPMR": 3300,
9
+ "PPSB": 2000,
10
+ "WS10": 5900
11
+ }
File without changes
File without changes
package/index.js DELETED
@@ -1,37 +0,0 @@
1
- 'use strict'
2
-
3
- const got = require('got')
4
-
5
- const inventories = require('./inventories')
6
-
7
- const TESLA_INVENTORY_API =
8
- 'https://www.tesla.com/inventory/api/v1/inventory-results'
9
-
10
- module.exports = async (inventory, opts, { headers, ...gotOpts } = {}) => {
11
- const inventoryProps = inventories[inventory]
12
-
13
- if (!inventoryProps) {
14
- throw new TypeError(`Tesla inventory \`${inventory}\` not found!`)
15
- }
16
-
17
- if (opts.model && !opts.model.startsWith('m')) {
18
- opts.model = `m${opts.model}`
19
- }
20
-
21
- const { body } = await got(TESLA_INVENTORY_API, {
22
- responseType: 'json',
23
- searchParams: {
24
- query: JSON.stringify({
25
- count: 0,
26
- query: {
27
- ...inventoryProps,
28
- ...opts
29
- }
30
- })
31
- },
32
- ...gotOpts,
33
- headers: { 'user-agent': undefined, ...headers }
34
- })
35
-
36
- return body.results.filter(result => result.Model === opts.model)
37
- }
package/inventories.js DELETED
@@ -1,26 +0,0 @@
1
- module.exports = {
2
- at: { country: 'Österreich', language: 'de', market: 'AT', region: 'Europe' },
3
- be: { country: 'Belgium', language: 'nl', market: 'BE', region: 'Europe' },
4
- ca: { country: 'Canada', language: 'en', market: 'CA', region: 'North America' },
5
- ch: { country: 'Switzerland', language: 'de', market: 'CH', region: 'Europe' },
6
- cz: { country: 'Česko', language: 'cs', market: 'CZ', region: 'Europe' },
7
- de: { country: 'Deutschland', language: 'de', market: 'DE', region: 'Europe' },
8
- dk: { country: 'Danmark', language: 'da', market: 'DK', region: 'Europe' },
9
- es: { country: 'Spain', language: 'es', market: 'ES', region: 'Europe' },
10
- fi: { country: 'Finland', language: 'fi', market: 'FI', region: 'Europe' },
11
- fr: { country: 'France', language: 'fr', market: 'FR', region: 'Europe' },
12
- gb: { country: 'United Kingdom', language: 'en', market: 'GB', region: 'Europe' },
13
- hu: { country: 'Magyarország', language: 'hu', market: 'HU', region: 'Europe' },
14
- ie: { country: 'Ireland', language: 'en', market: 'IE', region: 'Europe' },
15
- is: { country: 'Island', language: 'is', market: 'IS', region: 'Europe' },
16
- it: { country: 'Italy', language: 'it', market: 'IT', region: 'Europe' },
17
- lu: { country: 'Luxembourg', language: 'fr', market: 'LU', region: 'Europe' },
18
- mx: { country: 'Mexico', language: 'es', market: 'MX', region: 'North America' },
19
- nl: { country: 'Netherlands', language: 'nl', market: 'NL', region: 'Europe' },
20
- no: { country: 'Norway', language: 'no', market: 'NO', region: 'Europe' },
21
- pr: { country: 'Puerto Rico', language: 'es', market: 'PR', region: 'North America' },
22
- pt: { country: 'Portugal', language: 'pt', market: 'PT', region: 'Europe' },
23
- ro: { country: 'România', language: 'ro', market: 'RO', region: 'Europe' },
24
- se: { country: 'Sweden', language: 'sv', market: 'SE', region: 'Europe' },
25
- us: { country: 'United States', language: 'en', market: 'US', region: 'North America' }
26
- }
package/scripts/codes.js DELETED
@@ -1,35 +0,0 @@
1
- 'use strict'
2
-
3
- const { Extractor } = require('markdown-tables-to-json')
4
- const { decodeHTML } = require('entities')
5
-
6
- const jsonFuture = require('json-future')
7
- const { chain } = require('lodash')
8
- const got = require('got')
9
-
10
- const sortObjectByKey = obj =>
11
- chain(obj)
12
- .toPairs()
13
- .sortBy(0)
14
- .fromPairs()
15
- .value()
16
-
17
- const main = async () => {
18
- const markdown = await got(
19
- 'https://raw.githubusercontent.com/timdorr/tesla-api/master/docs/vehicle/optioncodes.md',
20
- { resolveBodyOnly: true }
21
- )
22
-
23
- const json = Extractor.extractObject(markdown, 'rows', false)
24
-
25
- const optionCodes = Object.keys(json).reduce((acc, code) => {
26
- const { Title: title, Description: description } = json[code]
27
- return { ...acc, [code]: decodeHTML(title || description) }
28
- }, {})
29
-
30
- jsonFuture.save('codes.json', sortObjectByKey(optionCodes))
31
- }
32
-
33
- main()
34
- .catch(err => console.error(err) && process.exit(1))
35
- .then(process.exit)
@@ -1,14 +0,0 @@
1
- 'use strict'
2
-
3
- const path = require('path')
4
-
5
- const inventories = Object.fromEntries(
6
- Object.entries(require('../../inventories')).filter(
7
- ([, { region }]) => region === 'North America'
8
- )
9
- )
10
-
11
- require('.')({
12
- filepath: path.resolve(__dirname, '../../prices/america.json'),
13
- inventories
14
- })
@@ -1,16 +0,0 @@
1
- 'use strict'
2
-
3
- const path = require('path')
4
-
5
- const NON_EURO_COUNTRIES = ['cz', 'se', 'dk', 'hu', 'is', 'ch', 'gb', 'no']
6
-
7
- const inventories = Object.fromEntries(
8
- Object.entries(require('../../inventories')).filter(
9
- ([code, { region }]) => region === 'Europe' && !NON_EURO_COUNTRIES.includes(code)
10
- )
11
- )
12
-
13
- require('.')({
14
- filepath: path.resolve(__dirname, '../../prices/europe.json'),
15
- inventories
16
- })
@@ -1,76 +0,0 @@
1
- 'use strict'
2
-
3
- const debug = require('debug-logfmt')('tesla-inventory:price')
4
- const jsonFuture = require('json-future')
5
- const { chain } = require('lodash')
6
-
7
- const teslaInventory = require('../..')
8
-
9
- const GOT_OPTS = {
10
- headers: {
11
- 'user-agent': 'googlebot'
12
- }
13
- }
14
-
15
- const MODEL_LETTER = ['s', '3', 'x', 'y']
16
-
17
- const MODEL_CONDITION = ['used', 'new']
18
-
19
- const sortObjectByKey = obj =>
20
- chain(obj)
21
- .toPairs()
22
- .sortBy(0)
23
- .fromPairs()
24
- .value()
25
-
26
- const run = async ({ pricesByCode, inventories }) => {
27
- const addItem = item => {
28
- if (item.price) {
29
- const trimCode = item.code.replace('$', '')
30
- if (!trimCode.startsWith('MDL')) {
31
- if (!pricesByCode[trimCode] || pricesByCode[trimCode] > item.price) {
32
- debug('adding', { code: trimCode, price: item.price })
33
- pricesByCode[trimCode] = item.price
34
- debug(item)
35
- }
36
- }
37
- }
38
- }
39
-
40
- for (const inventoryCode in inventories) {
41
- for (const model of MODEL_LETTER) {
42
- for (const condition of MODEL_CONDITION) {
43
- try {
44
- const results = await teslaInventory(
45
- inventoryCode,
46
- {
47
- model,
48
- condition
49
- },
50
- GOT_OPTS
51
- )
52
-
53
- debug({ inventoryCode, model, condition })
54
-
55
- results.forEach(result => {
56
- result.FlexibleOptionsData.forEach(addItem)
57
- result.OptionCodeData.forEach(addItem)
58
- })
59
- } catch (err) {
60
- debug.error(err.message || err, { inventoryCode, model, condition })
61
- }
62
- }
63
- }
64
- }
65
-
66
- return pricesByCode
67
- }
68
-
69
- module.exports = ({ inventories, filepath }) => {
70
- const pricesByCode = require(filepath)
71
-
72
- run({ pricesByCode, inventories }).then(data => {
73
- jsonFuture.save(filepath, sortObjectByKey(data))
74
- process.exit()
75
- })
76
- }