UNPKG

tesla-inventory

Version:

Retrieve real-time data from Tesla Inventory.

85 lines (68 loc) 2.45 kB
'use strict' const timeSpan = require('@kikobeats/time-span')({ format: n => `${Math.round(n)}ms` }) const debug = require('debug-logfmt')('tesla-inventory') const pRetry = require('p-retry') const inventories = require('./inventories') const ITEMS_PER_PAGE = 24 const uniqBy = (arr, prop) => arr.filter((x, i, self) => i === self.findIndex(y => x[prop] === y[prop])) const onFailedAttemptDefault = (error, debug) => debug.error(error) module.exports = fetcher => async ( inventory, opts, { retries = 2, onFailedAttempt = onFailedAttemptDefault, ...fetcherOpts } = {} ) => { if (!inventories[inventory]) { throw new TypeError(`Tesla inventory \`${inventory}\` not found!`) } if (opts.model && !opts.model.startsWith('m')) { opts.model = `m${opts.model}` } const { country, ...query } = { ...inventories[inventory], ...opts } const domain = inventory === 'cn' ? 'cn' : 'com' const duration = timeSpan() const paginate = async (offset = 0) => { const url = new URL( `https://www.tesla.${domain}/inventory/api/v4/inventory-results?${new URLSearchParams({ query: JSON.stringify({ query, count: ITEMS_PER_PAGE, outsideOffset: offset, outsideSearch: true }) }).toString()}` ).toString() debug({ url, offset, ...query }) const result = await pRetry( () => fetcher(url, fetcherOpts).then(async body => { try { const data = JSON.parse(body) return { items: data.results ?? [], total: Number(data.total_matches_found) } } catch (error) { error.body = body throw error } }), { onFailedAttempt: error => onFailedAttempt(error, debug), retries } ) return result } let offset = 0 let items = [] let page let pageIndex = 0 do { page = await paginate(offset) ++pageIndex items = uniqBy(items.concat(page.items), 'VIN') offset = pageIndex * ITEMS_PER_PAGE } while (page.items.length > 0 && items.length < page.total) debug.info({ inventory, ...opts, items: items.length, duration: duration() }) return items.filter(item => item.Model === opts.model) }