tesla-inventory 3.2.0-0 → 3.2.0-10
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 +5 -2
- package/src/codes.json +1 -0
- package/src/index.js +59 -62
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "tesla-inventory",
|
|
3
3
|
"description": "Retrieve real-time data from Tesla Inventory.",
|
|
4
4
|
"homepage": "https://github.com/Kikobeats/tesla-inventory",
|
|
5
|
-
"version": "3.2.0-
|
|
5
|
+
"version": "3.2.0-10",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"author": {
|
|
8
8
|
"email": "josefrancisco.verdu@gmail.com",
|
|
@@ -35,13 +35,14 @@
|
|
|
35
35
|
"teslamotors"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"
|
|
38
|
+
"p-retry": "4"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@commitlint/cli": "latest",
|
|
42
42
|
"@commitlint/config-conventional": "latest",
|
|
43
43
|
"@ksmithut/prettier-standard": "latest",
|
|
44
44
|
"ava": "latest",
|
|
45
|
+
"browserless": "latest",
|
|
45
46
|
"c8": "latest",
|
|
46
47
|
"ci-publish": "latest",
|
|
47
48
|
"conventional-github-releaser": "latest",
|
|
@@ -55,6 +56,8 @@
|
|
|
55
56
|
"markdown-tables-to-json": "latest",
|
|
56
57
|
"nano-staged": "latest",
|
|
57
58
|
"npm-check-updates": "latest",
|
|
59
|
+
"puppeteer": "latest",
|
|
60
|
+
"signal-exit": "latest",
|
|
58
61
|
"simple-git-hooks": "latest",
|
|
59
62
|
"standard": "latest",
|
|
60
63
|
"standard-markdown": "latest",
|
package/src/codes.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,75 +1,72 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const debug = require('debug-logfmt')('tesla-inventory')
|
|
4
|
+
const pRetry = require('p-retry')
|
|
5
|
+
|
|
4
6
|
const inventories = require('./inventories')
|
|
5
7
|
|
|
6
|
-
const
|
|
8
|
+
const timestamp =
|
|
9
|
+
(start = process.hrtime.bigint()) =>
|
|
10
|
+
() =>
|
|
11
|
+
Math.round(Number(process.hrtime.bigint() - start) / 1e6) + 'ms'
|
|
7
12
|
|
|
8
13
|
const uniqBy = (arr, prop) =>
|
|
9
14
|
arr.filter((x, i, self) => i === self.findIndex(y => x[prop] === y[prop]))
|
|
10
15
|
|
|
11
|
-
const
|
|
12
|
-
(start = process.hrtime.bigint()) =>
|
|
13
|
-
() =>
|
|
14
|
-
Math.round(Number(process.hrtime.bigint() - start) / 1e6) + 'ms'
|
|
15
|
-
|
|
16
|
-
const defaults = {
|
|
17
|
-
url: 'https://www.tesla.com/inventory/api/v1/inventory-results',
|
|
18
|
-
responseType: 'json',
|
|
19
|
-
resolveBodyOnly: true,
|
|
20
|
-
headers: { 'user-agent': undefined }
|
|
21
|
-
}
|
|
16
|
+
const ITEMS_PER_PAGE = 50
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (opts.model && !opts.model.startsWith('m')) {
|
|
32
|
-
opts.model = `m${opts.model}`
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const { country, ...query } = { ...inventories[inventory], ...opts }
|
|
36
|
-
|
|
37
|
-
const duration = timestamp()
|
|
38
|
-
|
|
39
|
-
const paginate = async (offset = 0) =>
|
|
40
|
-
got(
|
|
41
|
-
got.mergeOptions(
|
|
42
|
-
got.defaults.options,
|
|
43
|
-
{
|
|
44
|
-
searchParams: {
|
|
45
|
-
query: JSON.stringify({
|
|
46
|
-
query,
|
|
47
|
-
count: ITEMS_PER_PAGE,
|
|
48
|
-
offset,
|
|
49
|
-
outsideOffset: 0,
|
|
50
|
-
outsideSearch: false
|
|
51
|
-
})
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
gotOpts
|
|
55
|
-
)
|
|
56
|
-
).then(({ results }) => ({ items: results }))
|
|
57
|
-
|
|
58
|
-
let offset = 0
|
|
59
|
-
let items = []
|
|
60
|
-
let page
|
|
61
|
-
|
|
62
|
-
do {
|
|
63
|
-
page = await paginate(offset)
|
|
64
|
-
items = uniqBy(items.concat(page.items), 'VIN')
|
|
65
|
-
offset = items.length
|
|
66
|
-
debug({ items: items.length, duration: duration() })
|
|
67
|
-
} while (page.items.length >= ITEMS_PER_PAGE)
|
|
68
|
-
|
|
69
|
-
return items.filter(item => item.Model === opts.model)
|
|
18
|
+
module.exports = fetcher => async (inventory, opts, fetcherOpts) => {
|
|
19
|
+
if (!inventories[inventory]) {
|
|
20
|
+
throw new TypeError(`Tesla inventory \`${inventory}\` not found!`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (opts.model && !opts.model.startsWith('m')) {
|
|
24
|
+
opts.model = `m${opts.model}`
|
|
70
25
|
}
|
|
71
|
-
}
|
|
72
26
|
|
|
73
|
-
|
|
27
|
+
const { country, ...query } = { ...inventories[inventory], ...opts }
|
|
28
|
+
|
|
29
|
+
const duration = timestamp()
|
|
30
|
+
|
|
31
|
+
const paginate = async (offset = 0) => {
|
|
32
|
+
const url = new URL(
|
|
33
|
+
`https://www.tesla.com/inventory/api/v1/inventory-results?${new URLSearchParams({
|
|
34
|
+
query: JSON.stringify({
|
|
35
|
+
query,
|
|
36
|
+
count: ITEMS_PER_PAGE,
|
|
37
|
+
offset,
|
|
38
|
+
outsideOffset: 0,
|
|
39
|
+
outsideSearch: false
|
|
40
|
+
})
|
|
41
|
+
}).toString()}`
|
|
42
|
+
).toString()
|
|
43
|
+
|
|
44
|
+
debug({ url, ...query })
|
|
45
|
+
|
|
46
|
+
const result = await pRetry(
|
|
47
|
+
() =>
|
|
48
|
+
fetcher(url, fetcherOpts).then(async text => {
|
|
49
|
+
const body = JSON.parse(text)
|
|
50
|
+
return { items: body.results ?? [] }
|
|
51
|
+
}),
|
|
52
|
+
{
|
|
53
|
+
onFailedAttempt: debug.error
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return result
|
|
58
|
+
}
|
|
74
59
|
|
|
75
|
-
|
|
60
|
+
let offset = 0
|
|
61
|
+
let items = []
|
|
62
|
+
let page
|
|
63
|
+
|
|
64
|
+
do {
|
|
65
|
+
page = await paginate(offset)
|
|
66
|
+
items = uniqBy(items.concat(page.items), 'VIN')
|
|
67
|
+
offset = items.length
|
|
68
|
+
debug.info({ ...opts, items: items.length, duration: duration() })
|
|
69
|
+
} while (page.items.length >= ITEMS_PER_PAGE)
|
|
70
|
+
|
|
71
|
+
return items.filter(item => item.Model === opts.model)
|
|
72
|
+
}
|