From 3700079989dcd477446f649c17198db1fa923e01 Mon Sep 17 00:00:00 2001 From: Nick Bottomley Date: Fri, 29 Jan 2021 19:26:16 -0800 Subject: [PATCH 1/7] puppeteer transport --- .mocharc.js | 3 + Makefile | 15 +- package.json | 2 + src/PuppeteerTransport.js | 139 +++++++++++++++++ src/data.js | 141 ++++++++--------- src/get-json.js | 39 ++--- src/stats.js | 14 +- src/synergy.js | 8 +- src/transport.js | 11 ++ test/get-json-stub.js | 18 --- test/hooks.js | 11 ++ test/inspect.js | 17 --- test/integration/data.js | 2 +- test/integration/stats.js | 22 ++- test/integration/synergy.js | 6 +- test/nba-api-spy.js | 22 --- test/scratchpad.js | 31 ++++ yarn.lock | 293 ++++++++++++++++++++++++++++++++++-- 18 files changed, 613 insertions(+), 181 deletions(-) create mode 100644 .mocharc.js create mode 100644 src/PuppeteerTransport.js create mode 100644 src/transport.js delete mode 100644 test/get-json-stub.js create mode 100644 test/hooks.js delete mode 100644 test/inspect.js delete mode 100644 test/nba-api-spy.js create mode 100644 test/scratchpad.js diff --git a/.mocharc.js b/.mocharc.js new file mode 100644 index 0000000..781ee8d --- /dev/null +++ b/.mocharc.js @@ -0,0 +1,3 @@ +module.exports = { + require: ["test/hooks.js"] +} \ No newline at end of file diff --git a/Makefile b/Makefile index ddf19d9..e69109c 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,22 @@ .PHONY: test coverage test: - ./node_modules/.bin/mocha --recursive --timeout 10000 --parallel --exit ./test/unit ./test/integration + ./node_modules/.bin/mocha --recursive --timeout 10000 --exit ./test/unit ./test/integration test-bail: - ./node_modules/.bin/mocha --bail --recursive --timeout 10000 ./test/unit ./test/integration + ./node_modules/.bin/mocha --bail --recursive --timeout 10000 --exit ./test/unit ./test/integration test-integration: - ./node_modules/.bin/mocha --recursive --timeout 10000 ./test/integration + ./node_modules/.bin/mocha --recursive --timeout 10000 --exit ./test/integration + +test-stats: + ./node_modules/.bin/mocha --timeout 10000 --exit ./test/integration/stats.js + +test-data: + ./node_modules/.bin/mocha --timeout 60000 --exit --bail ./test/integration/data.js + +test-synergy: + ./node_modules/.bin/mocha --timeout 10000 --exit --bail ./test/integration/synergy.js test-unit: ./node_modules/.bin/mocha --recursive ./test/unit/ diff --git a/package.json b/package.json index 36f6775..4a7fbb3 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "url": "https://github.com/bttmly/nba/issues" }, "dependencies": { + "axios": "^0.21.1", "camel-case": "^3.0.0", "lodash.find": "^3.2.0", "lodash.findwhere": "^3.1.0", @@ -29,6 +30,7 @@ "minimist": "^1.2.0", "nba-client-template": "4.5.0", "node-fetch": "2.6.1", + "puppeteer": "^5.5.0", "url": "^0.11.0" }, "devDependencies": { diff --git a/src/PuppeteerTransport.js b/src/PuppeteerTransport.js new file mode 100644 index 0000000..09d35ef --- /dev/null +++ b/src/PuppeteerTransport.js @@ -0,0 +1,139 @@ +const puppeteer = require("puppeteer"); +const { URL } = require("url"); + +const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"; + +const delay = (ms) => new Promise(r => setTimeout(r, ms)); + +class PuppeteerTransport { + static async create () { + const browser = await puppeteer.launch({ + headless: false, + handleSIGINT: false, + handleSIGTERM: false, + args: [ + "--disable-web-security", + ], + }); + return new PuppeteerTransport(browser); + } + + constructor (browser) { + this.browser = browser; + } + + async _createPage () { + const page = await this.browser.newPage(); + await page.setRequestInterception(true); + page.on("request", req => { + const type = req.resourceType(); + switch (type) { + case "document": + case "fetch": + req.continue(); + break; + default: + req.abort(); + } + }); + page.on("framenavigated", (frame) => { + console.log("NAVIGATION:", frame.url(), "main", frame === page.mainFrame()); + }); + await page.setUserAgent(USER_AGENT); + await page.goto("https://www.nba.com/stats/", { waitUntil: "domcontentloaded", timeout: 8 * 1000 }); + return page; + } + + async _getPage () { + if (this.pageP) { + return this.pageP; + } + this.pageP = this._createPage(); + return this.pageP; + } + + async run (_url) { + const page = await this._getPage(); + const result = await page.evaluate(async (url) => { + const headers = { + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "en,en-US;q=0.9", + Accept: "application/json, text/plain, */*", + Referer: "https://www.nba.com/", + Connection: "keep-alive", + "Cache-Control": "no-cache", + Origin: "http://www.nba.com", + // "x-nba-stats-origin": "stats", + // "x-nba-stats-token": "true", + }; + + try { + const res = await fetch(url, { headers }); + if (res.ok) { + const data = await res.json(); + return { data, ok: true }; + } + const text = await res.text(); + return { + ok: false, + data: { text, status: res.status }, + }; + } catch (err) { + console.log(err); + return { ok: false, data: { text: err.toString() }}; + } + }, _url); + return result; + } + + close () { + console.trace("browser close"); + return this.browser.close(); + } +}; + +let instanceP = null; + +async function transport (baseURL, query = {}) { + if (instanceP == null) { + instanceP = PuppeteerTransport.create(); + await delay(1); + } + const instance = await instanceP; + + const u = new URL(baseURL); + for (const [key, value] of Object.entries(query)) { + u.searchParams.append(key, value); + } + u.protocol = "https:"; + const result = await instance.run(u.toString()); + if (result.ok) return result.data; + throw new Error(`${result.data.text} – ${u.toString()}`); +} + +module.exports.transport = transport; +module.exports.closeTransport = async () => { + if (instanceP == null) return; + const instance = await instanceP; + await instance.browser.close(); +}; +module.exports.PuppeteerTransport = PuppeteerTransport; + +// (async () => { +// const urls = [ +// "https://stats.nba.com/stats/leaguedashteamstats?Conference=&DateFrom=&DateTo=&Division=&GameScope=&GameSegment=&LastNGames=0&LeagueID=00&Location=&MeasureType=Advanced&Month=0&OpponentTeamID=0&Outcome=&PORound=0&PaceAdjust=N&PerMode=PerGame&Period=0&PlayerExperience=&PlayerPosition=&PlusMinus=N&Rank=N&Season=2020-21&SeasonSegment=&SeasonType=Regular+Season&ShotClockRange=&StarterBench=&TeamID=0&TwoWay=0&VsConference=&VsDivision=", +// "http://stats.nba.com/stats/playerprofilev2?LeagueID=00&PerMode=PerGame&PlayerID=201939&Season=2017-18", +// ]; + +// const b = await puppeteer.launch({ +// args: [ +// "--disable-web-security", +// ], +// }); +// const p = new PuppeteerTransport(b); +// for (const u of urls) { +// const { ok, data } = await p.run(u); +// console.log(ok, data.text, u.split("?")[0]); +// } +// await p.close(); +// })(); \ No newline at end of file diff --git a/src/data.js b/src/data.js index f3971be..9f063a2 100644 --- a/src/data.js +++ b/src/data.js @@ -1,78 +1,96 @@ // this includes endpoints at data.nba.com -let transport = require("./get-json"); +const { defaultTransport } = require("./transport"); const { interpolate } = require("./util/string"); -const scoreboardURL = interpolate("http://data.nba.com/data/5s/json/cms/noseason/scoreboard/__date__/games.json"); -const boxScoreURL = interpolate("http://data.nba.com/data/5s/json/cms/noseason/game/__date__/__gameId__/boxscore.json"); -const playByPlayURL = interpolate("http://data.nba.com/data/5s/json/cms/noseason/game/__date__/__gameId__/pbp_all.json"); -const scheduleURL = interpolate("http://data.nba.com/data/10s/prod/v1/__season__/schedule.json"); -const teamScheduleURL = interpolate("http://data.nba.com/data/10s/prod/v1/__season__/teams/__teamId__/schedule.json"); -const previewArticleURL = interpolate("http://data.nba.com/data/10s/prod/v1/__date__/__gameId___preview_article.json"); -const recapArticleURL = interpolate("http://data.nba.com/data/10s/prod/v1/__date__/__gameId___recap_article.json"); -const leadTrackerURL = interpolate("http://data.nba.com/data/10s/prod/v1/__date__/__gameId___lead_tracker___period__.json"); -const playoffsBracketURL = interpolate("http://data.nba.com/data/10s/prod/v1/__season__/playoffsBracket.json"); -const teamLeadersURL = interpolate("http://data.nba.com/data/10s/prod/v1/__season__/teams/__teamId__/leaders.json"); -const teamStatsRankingsURL = interpolate("http://data.nba.com/data/10s/prod/v1/__season__/team_stats_rankings.json"); -const coachesURL = interpolate("http://data.nba.com/data/10s/prod/v1/__season__/coaches.json"); -const teamsURL = interpolate("http://data.nba.net/data/10s/prod/v1/__year__/teams.json"); - -const calendarURL = "http://data.nba.net/data/10s/prod/v1/calendar.json"; -const standingsURL = "http://data.nba.net/data/10s/prod/v1/current/standings_all.json"; - -const withTransport = (newTransport) => { - transport = newTransport; -}; +const scoreboardURL = interpolate("https://data.nba.com/data/5s/json/cms/noseason/scoreboard/__date__/games.json"); +const boxScoreURL = interpolate("https://data.nba.com/data/5s/json/cms/noseason/game/__date__/__gameId__/boxscore.json"); +const playByPlayURL = interpolate("https://data.nba.com/data/5s/json/cms/noseason/game/__date__/__gameId__/pbp_all.json"); +const scheduleURL = interpolate("https://data.nba.com/data/10s/prod/v1/__season__/schedule.json"); +const teamScheduleURL = interpolate("https://data.nba.com/data/10s/prod/v1/__season__/teams/__teamId__/schedule.json"); +const previewArticleURL = interpolate("https://data.nba.com/data/10s/prod/v1/__date__/__gameId___preview_article.json"); +const recapArticleURL = interpolate("https://data.nba.com/data/10s/prod/v1/__date__/__gameId___recap_article.json"); +const leadTrackerURL = interpolate("https://data.nba.com/data/10s/prod/v1/__date__/__gameId___lead_tracker___period__.json"); +const playoffsBracketURL = interpolate("https://data.nba.com/data/10s/prod/v1/__season__/playoffsBracket.json"); +const teamLeadersURL = interpolate("https://data.nba.com/data/10s/prod/v1/__season__/teams/__teamId__/leaders.json"); +const teamStatsRankingsURL = interpolate("https://data.nba.com/data/10s/prod/v1/__season__/team_stats_rankings.json"); +const coachesURL = interpolate("https://data.nba.com/data/10s/prod/v1/__season__/coaches.json"); +const teamsURL = interpolate("https://data.nba.net/data/10s/prod/v1/__year__/teams.json"); + +const calendarURL = "https://data.nba.net/data/10s/prod/v1/calendar.json"; +const standingsURL = "https://data.nba.net/data/10s/prod/v1/current/standings_all.json"; // NOTE: the 'date' argument should be a string in format like "20181008" (which indicates Oct 8 2018) // You *can* pass a Date object but beware of timezone weirdness! // NOTE: the 'season' argument is the first year of the NBA season e.g. "2018" for the 2018-19 season -const scoreboard = date => transport(scoreboardURL({ date: dateToYYYYMMDD(date) })); -scoreboard.defaults = { date: null }; +const withTransport = (transportOverride) => { + const transport = transportOverride || defaultTransport; + + const scoreboard = date => transport(scoreboardURL({ date: dateToYYYYMMDD(date) })); + scoreboard.defaults = { date: null }; -const boxScore = (date, gameId) => transport(boxScoreURL({ date: dateToYYYYMMDD(date), gameId })); -boxScore.defaults = { date: null, gameId: null }; + const boxScore = (date, gameId) => transport(boxScoreURL({ date: dateToYYYYMMDD(date), gameId })); + boxScore.defaults = { date: null, gameId: null }; -const playByPlay = (date, gameId) => transport(playByPlayURL({ date: dateToYYYYMMDD(date), gameId })); -playByPlay.defaults = { date: null, gameId: null }; + const playByPlay = (date, gameId) => transport(playByPlayURL({ date: dateToYYYYMMDD(date), gameId })); + playByPlay.defaults = { date: null, gameId: null }; -const schedule = (season) => transport(scheduleURL({ season })); -schedule.defaults = { season: null }; + const schedule = (season) => transport(scheduleURL({ season })); + schedule.defaults = { season: null }; -const teamSchedule = (season, teamId) => transport(teamScheduleURL({ season, teamId })); -teamSchedule.defaults = { season: null, teamId: null }; + const teamSchedule = (season, teamId) => transport(teamScheduleURL({ season, teamId })); + teamSchedule.defaults = { season: null, teamId: null }; -const previewArticle = (date, gameId) => transport(previewArticleURL({date: dateToYYYYMMDD(date), gameId })); -previewArticle.defaults = { date: null, gameId: null }; + const previewArticle = (date, gameId) => transport(previewArticleURL({date: dateToYYYYMMDD(date), gameId })); + previewArticle.defaults = { date: null, gameId: null }; -const recapArticle = (date, gameId) => transport(recapArticleURL({date: dateToYYYYMMDD(date), gameId })); -recapArticle.defaults = { date: null, gameId: null }; + const recapArticle = (date, gameId) => transport(recapArticleURL({date: dateToYYYYMMDD(date), gameId })); + recapArticle.defaults = { date: null, gameId: null }; -const leadTracker = (date, gameId, period) => transport(leadTrackerURL({date: dateToYYYYMMDD(date), gameId, period })); -leadTracker.defaults = { date: null, gameId: null, period: null }; + const leadTracker = (date, gameId, period) => transport(leadTrackerURL({date: dateToYYYYMMDD(date), gameId, period })); + leadTracker.defaults = { date: null, gameId: null, period: null }; -const playoffsBracket = (season) => transport(playoffsBracketURL({ season })); -playoffsBracket.defaults = { season: null }; + const playoffsBracket = (season) => transport(playoffsBracketURL({ season })); + playoffsBracket.defaults = { season: null }; -const teamLeaders = (season, teamId) => transport(teamLeadersURL({ season, teamId })); -teamLeaders.defaults = { season: null, teamId: null }; + const teamLeaders = (season, teamId) => transport(teamLeadersURL({ season, teamId })); + teamLeaders.defaults = { season: null, teamId: null }; -const teamStatsRankings = (season) => transport(teamStatsRankingsURL({ season })); -teamStatsRankings.defaults = { season: null }; + const teamStatsRankings = (season) => transport(teamStatsRankingsURL({ season })); + teamStatsRankings.defaults = { season: null }; -const coaches = (season) => transport(coachesURL({ season })); -coaches.defaults = { season: null }; + const coaches = (season) => transport(coachesURL({ season })); + coaches.defaults = { season: null }; -const teams = (year = "2019") => transport(teamsURL({ year })); -teams.defaults = { year: null }; + const teams = (year = "2019") => transport(teamsURL({ year })); + teams.defaults = { year: null }; -const calendar = () => transport(calendarURL); -calendar.defaults = {}; + const calendar = () => transport(calendarURL); + calendar.defaults = {}; -const standings = () => transport(standingsURL); -standings.defaults = {}; + const standings = () => transport(standingsURL); + standings.defaults = {}; + + return { + scoreboard, + boxScore, + playByPlay, + schedule, + teamSchedule, + previewArticle, + recapArticle, + leadTracker, + playoffsBracket, + teamLeaders, + teamStatsRankings, + coaches, + teams, + calendar, + standings, + }; +}; function dateToYYYYMMDD (date) { if (date instanceof Date) { @@ -82,27 +100,12 @@ function dateToYYYYMMDD (date) { String(date.getDate()).padStart(2, 0), ].join(""); } - - // TODO: better checking here? - return date; } +const client = withTransport(); + module.exports = { - scoreboard, - boxScore, - playByPlay, - schedule, - teamSchedule, - previewArticle, - recapArticle, - leadTracker, - playoffsBracket, - teamLeaders, - teamStatsRankings, - coaches, - teams, - calendar, - standings, + ...client, withTransport, }; \ No newline at end of file diff --git a/src/get-json.js b/src/get-json.js index c9c2989..585bfbd 100644 --- a/src/get-json.js +++ b/src/get-json.js @@ -1,16 +1,16 @@ const url = require("url"); const template = require("nba-client-template"); -const fetch = require("node-fetch"); +const axios = require("axios"); const HEADERS = { - "Accept-Encoding": "gzip, deflate", - "Accept-Language": "en-US", - Accept: "*/*", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "en,en-US;q=0.9", + Accept: "application/json, text/plain, */*", "User-Agent": template.user_agent, - Referer: template.referrer, + Referer: "www.nba.com", Connection: "keep-alive", "Cache-Control": "no-cache", - Origin: "http://stats.nba.com", + Origin: "https://www.nba.com", }; function createUrlString (_url, query) { @@ -19,22 +19,23 @@ function createUrlString (_url, query) { return urlObj.format(); } -module.exports = function getJson (_url, query, _options = {}) { - const urlStr = createUrlString(_url, query); - +async function getJsonAxios (_url, params, _options = {}) { const options = { ..._options, - headers: { ..._options.headers, ...HEADERS }, + headers: { ...HEADERS, ..._options.headers }, }; - return fetch(urlStr, options) - .then(resp => { - if (resp.ok) return resp.json(); - - return resp.text().then(function (text) { - throw new Error(`${resp.status} ${resp.statusText} – ${text}`); - }); - }); + const urlStr = createUrlString(_url, params); + try { + const res = await axios.get(urlStr, options); + return res.data; + } catch (err) { + const { response } = err; + if (response) { + throw new Error(`${response.status} ${response.data}`); + } + throw new Error(`Unknown HTTP error for ${url}`); + } }; - +module.exports = getJsonAxios; \ No newline at end of file diff --git a/src/stats.js b/src/stats.js index 3ce014d..49ec7a1 100644 --- a/src/stats.js +++ b/src/stats.js @@ -46,13 +46,14 @@ function makeStatsMethod (endpoint, transport) { const ccName = camelCase(endpoint.name); const transform = transformMap[ccName]; - function statsMethod (query = {}) { - const reqParams = Object.assign({}, defaults, query); + async function statsMethod (query = {}) { + const reqParams = { ...defaults, ...query }; const options = { headers: { - "x-nba-stats-origin": "stats", - "x-nba-stats-token": "true", + // "x-nba-stats-origin": "stats", + // "x-nba-stats-token": "true", + // "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36", }, }; @@ -80,4 +81,7 @@ function makeStatsClient (transport) { return client; } -module.exports = makeStatsClient(require("./get-json")); +const { defaultTransport } = require("./transport"); + +module.exports = makeStatsClient(defaultTransport); + diff --git a/src/synergy.js b/src/synergy.js index 75bb3f3..34dd421 100644 --- a/src/synergy.js +++ b/src/synergy.js @@ -1,4 +1,5 @@ const camelCase = require("camel-case"); +const { defaultTransport } = require("./transport"); const parameters = [ { @@ -44,8 +45,8 @@ const parameters = [ ]; const synergyEndpoints = [ - { name: "player_play_type", url: "http://stats-prod.nba.com/wp-json/statscms/v1/synergy/player/" }, - { name: "team_play_type", url: "http://stats-prod.nba.com/wp-json/statscms/v1/synergy/team/" }, + { name: "player_play_type", url: "https://stats-prod.nba.com/wp-json/statscms/v1/synergy/player/" }, + { name: "team_play_type", url: "https://stats-prod.nba.com/wp-json/statscms/v1/synergy/team/" }, ]; const defaults = {}; @@ -76,4 +77,5 @@ function makeSynergyClient (transport) { return client; } -module.exports = makeSynergyClient(require("./get-json")); + +module.exports = makeSynergyClient(defaultTransport); diff --git a/src/transport.js b/src/transport.js new file mode 100644 index 0000000..a5bb5df --- /dev/null +++ b/src/transport.js @@ -0,0 +1,11 @@ +let _defaultTransport = require("./get-json"); + +function defaultTransport (...args) { + return _defaultTransport(...args); +} + +function setDefaultTransport (t) { + _defaultTransport = t; +} + +module.exports = { defaultTransport, setDefaultTransport }; \ No newline at end of file diff --git a/test/get-json-stub.js b/test/get-json-stub.js deleted file mode 100644 index 31121bd..0000000 --- a/test/get-json-stub.js +++ /dev/null @@ -1,18 +0,0 @@ -var DELAY = 10; - -function jsonStub (url, settings) { - return new Promise(function (resolve) { - setTimeout(() => resolve(), DELAY); - }); -} - -function jsonFailStub (url, settings, callback) { - return new Promise(function (__, reject) { - setTimeout(() => reject(new Error()), DELAY) - }); -} - -module.exports = { - success: jsonStub, - fail: jsonFailStub, -}; diff --git a/test/hooks.js b/test/hooks.js new file mode 100644 index 0000000..8aa46e4 --- /dev/null +++ b/test/hooks.js @@ -0,0 +1,11 @@ +const { setDefaultTransport } = require("../src/transport"); +const p = require("../src/PuppeteerTransport"); + +exports.mochaHooks = { + beforeAll () { + // setDefaultTransport(p.transport); + }, + async afterAll () { + // await p.closeTransport(); + }, +}; \ No newline at end of file diff --git a/test/inspect.js b/test/inspect.js deleted file mode 100644 index 079221b..0000000 --- a/test/inspect.js +++ /dev/null @@ -1,17 +0,0 @@ -const path = require("path"); -const { REPLServer } = require("repl"); - -const Mocha = require("mocha"); -const mocha = new Mocha({ timeout: 30000 }); - -mocha.addFile(path.join(__dirname, "integration/stats.js")); -mocha.addFile(path.join(__dirname, "integration/sport-vu.js")); - -const repl = new REPLServer(); - -mocha.run(function(failures) { - console.log("responses are loaded into global `StatsData` and `SportVuData` objects... Enjoy!"); - repl.start({ prompt: "🏀 > " }); -}); - -module.exports = repl; diff --git a/test/integration/data.js b/test/integration/data.js index 9d9ced6..fd9c1ce 100644 --- a/test/integration/data.js +++ b/test/integration/data.js @@ -1,7 +1,7 @@ const nba = require("../../"); describe("nba data methods", function () { - describe("#scoreboard", async () => { + describe("#scoreboard", () => { it("works with a direct date string", async () => { log(await nba.data.scoreboard("20181008")); }); diff --git a/test/integration/stats.js b/test/integration/stats.js index 5aae6c6..3602b41 100644 --- a/test/integration/stats.js +++ b/test/integration/stats.js @@ -83,17 +83,23 @@ describe("nba stats methods", function () { it("#playerCompare", callMethod("playerCompare", { PlayerIDList: _steph, VsPlayerIDList: _steph })); - after(function () { - return Promise.all(Object.keys(global.StatsData).map(k => - pify(fs.writeFile)( - path.join(__dirname, "../../responses", `stats-${k}.json`), - JSON.stringify(global.StatsData[k], null, 2) - ) - )) - .catch(console.error); + after(async () => { + for (const [key, value] of Object.entries(global.StatsData)) { + await writeResponse(key, value); + } }); }); +const writeFile = pify(fs.writeFile); +async function writeResponse (key, value) { + try { + await writeFile( + path.join(__dirname, "../../responses", `stats-${key}.json`), + JSON.stringify(value, null, 2) + ); + } catch (e) {} +} + // describe("tested all methods", function () { // it("did test all methods", () => { // try { diff --git a/test/integration/synergy.js b/test/integration/synergy.js index a2b3bcf..1b5da84 100644 --- a/test/integration/synergy.js +++ b/test/integration/synergy.js @@ -7,15 +7,15 @@ const writeFile = pify(require("fs").writeFile); const dir = path.join(__dirname, "../../responses"); function writeData (name, data) { const str = JSON.stringify(data, null, 2); - return writeFile(path.join(dir, `synergy-${name}.json`), str); + return writeFile(path.join(dir, `synergy-${name}.json`), str).catch(() => {}); } global.SynergyData = {}; // stub for now, will add response shape verification for self-documenting responses -const verifyShape = shape => response => response; +// const verifyShape = shape => response => response; -const callMethod = (name, params = {}, shape) => () => { +const callMethod = (name, params = {}) => () => { params.season = 2016; return nba.synergy[name](params) .then(function (resp) { diff --git a/test/nba-api-spy.js b/test/nba-api-spy.js deleted file mode 100644 index ff712db..0000000 --- a/test/nba-api-spy.js +++ /dev/null @@ -1,22 +0,0 @@ -var sinon = require("sinon"); - -var optionPosition = 1; -var urlPosition = 0; - -module.exports = function (...args) { - var spy = sinon.spy(...args); - spy.lastCalledWithOption = function (option, value) { - var opts = spy.lastCall.args[optionPosition]; - if (opts[option] == null) { - return false; - } - if (value) { - return opts[option] === value; - } - return true; - }; - spy.lastCalledWithUrl = function (url) { - return spy.lastCall.args[urlPosition] === url; - }; - return spy; -}; diff --git a/test/scratchpad.js b/test/scratchpad.js new file mode 100644 index 0000000..83392bc --- /dev/null +++ b/test/scratchpad.js @@ -0,0 +1,31 @@ +const { getJsonNodeFetch, getJsonAxios } = require("../src/get-json"); + +async function main () { + const url = "https://stats.nba.com/stats/leagueLeaders"; + const query = { + "ActiveFlag": "No", + "LeagueID": "00", + "PerMode": "Totals", + "Scope": "S", + "Season": "All Time", + "SeasonType": "Regular Season", + "StatCategory": "PTS", + }; + let err, result; + + ({ err, result } = await settle(getJsonNodeFetch(url, query))); + console.log({ err, result }); + ({ err, result } = await settle(getJsonAxios(url, query))); + console.log({ err, result }); +} + +async function settle (p) { + try { + const result = await p; + return { result }; + } catch (err) { + return { err }; + } +} + +main(); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index ce0214a..fbdaa63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,11 +23,23 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== +"@types/node@*": + version "14.14.22" + resolved "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz#0d29f382472c4ccf3bd96ff0ce47daf5b7b84b18" + integrity sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw== + "@types/node@^12.6.9": version "12.7.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.0.tgz#545dde2a1a5c27d281cfb8308d6736e0708f5d6c" integrity sha512-vqcj1MVm2Sla4PpMfYKh1MyDN4D2f/mPIZD7RdAGqEsbE+JxfeqQHHVbRDQ0Nqn8i73gJa1HQ1Pu3+nH4Q0Yiw== +"@types/yauzl@^2.9.1": + version "2.9.1" + resolved "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz#d10f69f9f522eef3cf98e30afb684a1e1ec923af" + integrity sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA== + dependencies: + "@types/node" "*" + "@ungap/promise-all-settled@1.1.2": version "1.1.2" resolved "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" @@ -43,6 +55,11 @@ acorn@^6.0.7, acorn@^6.2.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== +agent-base@5: + version "5.1.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" + integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== + ajv@^6.10.0, ajv@^6.9.1: version "6.10.1" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.1.tgz#ebf8d3af22552df9dd049bfbe50cc2390e823593" @@ -107,16 +124,37 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +axios@^0.21.1: + version "0.21.1" + resolved "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + dependencies: + follow-redirects "^1.10.0" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +bl@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489" + integrity sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -137,6 +175,19 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + +buffer@^5.2.1, buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -197,6 +248,11 @@ chokidar@3.4.3: optionalDependencies: fsevents "~2.1.2" +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -263,6 +319,13 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" +debug@4, debug@^4.1.0, debug@^4.1.1: + version "4.3.1" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + debug@4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" @@ -300,6 +363,11 @@ define-properties@^1.1.1, define-properties@~1.1.2: foreach "^2.0.5" object-keys "^1.0.8" +devtools-protocol@0.0.818844: + version "0.0.818844" + resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.818844.tgz#d1947278ec85b53e4c8ca598f607a28fa785ba9e" + integrity sha512-AD1hi7iVJ8OD0aMLQU5VK0XH9LDlA1+BcPIgrAxPfaibx2DbWucuyOhc4oyQCbnvDDO68nN6/LcKfqTP343Jjg== + diff@4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -317,6 +385,13 @@ emoji-regex@^7.0.1: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + es-abstract@^1.3.2: version "1.6.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.6.1.tgz#bb8a2064120abcf928a086ea3d9043114285ec99" @@ -468,6 +543,17 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" +extract-zip@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== + dependencies: + debug "^4.1.1" + get-stream "^5.1.0" + yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" + fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -483,6 +569,13 @@ fast-levenshtein@~2.0.4: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -519,6 +612,14 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + flat-cache@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" @@ -538,6 +639,11 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== +follow-redirects@^1.10.0: + version "1.13.2" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz#dd73c8effc12728ba5cf4259d760ea5fb83e3147" + integrity sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA== + foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" @@ -550,6 +656,11 @@ formatio@1.1.1: dependencies: samsam "~1.1" +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -575,6 +686,13 @@ get-caller-file@^2.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -646,6 +764,14 @@ he@1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +https-proxy-agent@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b" + integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg== + dependencies: + agent-base "5" + debug "4" + iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -653,6 +779,11 @@ iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -689,6 +820,11 @@ inherits@2.0.1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= +inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + inquirer@^6.2.2: version "6.4.1" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.4.1.tgz#7bd9e5ab0567cd23b41b0180b68e0cfa82fc3c0b" @@ -870,6 +1006,13 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -1132,6 +1275,11 @@ minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.3.tgz#3db5c0765545ab8637be71f333a104a965a9ca3f" integrity sha512-+bMdgqjMN/Z77a6NlY/I3U5LlRDbnmaAk6lDveAPKwSpcPM4tKAuYsvYF8xjhOPXhOYGe/73vVLVez5PW+jqhw== +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -1212,15 +1360,7 @@ no-case@^2.2.0: dependencies: lower-case "^1.1.1" -node-environment-flags@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" - integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== - dependencies: - object.getownpropertydescriptors "^2.0.3" - semver "^5.7.0" - -node-fetch@2.6.1: +node-fetch@2.6.1, node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== @@ -1259,7 +1399,7 @@ object.entries@^1.0.3: function-bind "^1.0.2" has "^1.0.1" -once@^1.3.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -1305,6 +1445,13 @@ p-limit@^2.0.0: dependencies: p-try "^2.0.0" +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -1319,6 +1466,13 @@ p-locate@^3.0.0: dependencies: p-limit "^2.0.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-locate@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -1363,6 +1517,11 @@ path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + picomatch@^2.0.4, picomatch@^2.2.1: version "2.2.2" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" @@ -1373,16 +1532,36 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -progress@^2.0.0: +progress@^2.0.0, progress@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +proxy-from-env@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -1393,6 +1572,24 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +puppeteer@^5.5.0: + version "5.5.0" + resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-5.5.0.tgz#331a7edd212ca06b4a556156435f58cbae08af00" + integrity sha512-OM8ZvTXAhfgFA7wBIIGlPQzvyEETzDjeRa4mZRCRHxYL+GNH5WAuYUQdja3rpWZvkX/JKqmuVgbsxDNsDFjMEg== + dependencies: + debug "^4.1.0" + devtools-protocol "0.0.818844" + extract-zip "^2.0.0" + https-proxy-agent "^4.0.0" + node-fetch "^2.6.1" + pkg-dir "^4.2.0" + progress "^2.0.1" + proxy-from-env "^1.0.0" + rimraf "^3.0.2" + tar-fs "^2.0.0" + unbzip2-stream "^1.3.3" + ws "^7.2.3" + querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" @@ -1405,6 +1602,15 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" +readable-stream@^3.1.1, readable-stream@^3.4.0: + version "3.6.0" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@~3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" @@ -1447,6 +1653,13 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + rollup@^1.19.3: version "1.19.3" resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.19.3.tgz#77e59426faa6d8399e7b75c129e81447cf9db317" @@ -1470,7 +1683,7 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" -safe-buffer@^5.1.0: +safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -1560,6 +1773,13 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" @@ -1608,12 +1828,33 @@ table@^5.2.3: slice-ansi "^2.1.0" string-width "^3.0.0" +tar-fs@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -through@^2.3.6: +through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -1649,6 +1890,14 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +unbzip2-stream@^1.3.3: + version "1.4.3" + resolved "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" + integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== + dependencies: + buffer "^5.2.1" + through "^2.3.8" + upper-case@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" @@ -1669,6 +1918,11 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + "util@>=0.10.3 <1": version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" @@ -1738,6 +1992,11 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" +ws@^7.2.3: + version "7.4.2" + resolved "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz#782100048e54eb36fe9843363ab1c68672b261dd" + integrity sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA== + y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" @@ -1777,6 +2036,14 @@ yargs@13.3.2: y18n "^4.0.0" yargs-parser "^13.1.2" +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" From e948c8f0884642aeca5cac631fa6e62be1d5084c Mon Sep 17 00:00:00 2001 From: Nick Bottomley Date: Fri, 29 Jan 2021 19:36:43 -0800 Subject: [PATCH 2/7] wonder if itll work on travis --- Makefile | 2 +- test/hooks.js | 4 ++-- test/integration/stats.js | 11 +---------- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index e69109c..10bea05 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ test-integration: ./node_modules/.bin/mocha --recursive --timeout 10000 --exit ./test/integration test-stats: - ./node_modules/.bin/mocha --timeout 10000 --exit ./test/integration/stats.js + ./node_modules/.bin/mocha --timeout 30000 ./test/integration/stats.js test-data: ./node_modules/.bin/mocha --timeout 60000 --exit --bail ./test/integration/data.js diff --git a/test/hooks.js b/test/hooks.js index 8aa46e4..8dd8efa 100644 --- a/test/hooks.js +++ b/test/hooks.js @@ -3,9 +3,9 @@ const p = require("../src/PuppeteerTransport"); exports.mochaHooks = { beforeAll () { - // setDefaultTransport(p.transport); + setDefaultTransport(p.transport); }, async afterAll () { - // await p.closeTransport(); + await p.closeTransport(); }, }; \ No newline at end of file diff --git a/test/integration/stats.js b/test/integration/stats.js index 3602b41..19df509 100644 --- a/test/integration/stats.js +++ b/test/integration/stats.js @@ -6,8 +6,6 @@ const pify = require("pify"); const nba = require("../../"); -// for interactive inspection, particularly in browser -global.StatsData = {}; const tested = {}; const methods = {}; @@ -33,7 +31,7 @@ const callMethod = (name, params = {}, shape) => async () => { params.Season = "2017-18"; const r = await stats[name](params); verifyShape(shape, r); - global.StatsData[name] = r; + await writeResponse(name, r); }; const _steph = 201939; @@ -81,13 +79,6 @@ describe("nba stats methods", function () { it("#leagueStandings", callMethod("leagueStandings")); it("#teamPlayerOnOffDetails", callMethod("teamPlayerOnOffDetails", { TeamID: _dubs })); it("#playerCompare", callMethod("playerCompare", { PlayerIDList: _steph, VsPlayerIDList: _steph })); - - - after(async () => { - for (const [key, value] of Object.entries(global.StatsData)) { - await writeResponse(key, value); - } - }); }); const writeFile = pify(fs.writeFile); From 14ed1bd526eb2bfd7c04a6361d2796794a80a1c1 Mon Sep 17 00:00:00 2001 From: Nick Bottomley Date: Fri, 29 Jan 2021 19:38:55 -0800 Subject: [PATCH 3/7] node 14 travis --- .travis.yml | 4 +--- src/PuppeteerTransport.js | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ec6dafd..28b3165 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,6 @@ language: 'node_js' node_js: -- '7' -- '6' -- '5' +- '14' install: 'npm install' script: 'sh travis.sh' sudo: false diff --git a/src/PuppeteerTransport.js b/src/PuppeteerTransport.js index 09d35ef..7d78cf3 100644 --- a/src/PuppeteerTransport.js +++ b/src/PuppeteerTransport.js @@ -8,7 +8,6 @@ const delay = (ms) => new Promise(r => setTimeout(r, ms)); class PuppeteerTransport { static async create () { const browser = await puppeteer.launch({ - headless: false, handleSIGINT: false, handleSIGTERM: false, args: [ From 5a8f41484a42a4ec6edb1ca3761f944da529e880 Mon Sep 17 00:00:00 2001 From: Nick Bottomley Date: Fri, 29 Jan 2021 19:26:16 -0800 Subject: [PATCH 4/7] puppeteer transport --- .mocharc.js | 3 + Makefile | 13 +- package.json | 2 + src/PuppeteerTransport.js | 139 +++++++++++++++++ src/data.js | 141 ++++++++--------- src/get-json.js | 39 ++--- src/stats.js | 14 +- src/synergy.js | 8 +- src/transport.js | 11 ++ test/get-json-stub.js | 18 --- test/hooks.js | 11 ++ test/inspect.js | 17 --- test/integration/data.js | 2 +- test/integration/stats.js | 22 ++- test/integration/synergy.js | 6 +- test/nba-api-spy.js | 22 --- test/scratchpad.js | 31 ++++ yarn.lock | 293 ++++++++++++++++++++++++++++++++++-- 18 files changed, 612 insertions(+), 180 deletions(-) create mode 100644 .mocharc.js create mode 100644 src/PuppeteerTransport.js create mode 100644 src/transport.js delete mode 100644 test/get-json-stub.js create mode 100644 test/hooks.js delete mode 100644 test/inspect.js delete mode 100644 test/nba-api-spy.js create mode 100644 test/scratchpad.js diff --git a/.mocharc.js b/.mocharc.js new file mode 100644 index 0000000..781ee8d --- /dev/null +++ b/.mocharc.js @@ -0,0 +1,3 @@ +module.exports = { + require: ["test/hooks.js"] +} \ No newline at end of file diff --git a/Makefile b/Makefile index 990a227..e69109c 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,19 @@ test: ./node_modules/.bin/mocha --recursive --timeout 10000 --exit ./test/unit ./test/integration test-bail: - ./node_modules/.bin/mocha --bail --recursive --timeout 10000 ./test/unit ./test/integration + ./node_modules/.bin/mocha --bail --recursive --timeout 10000 --exit ./test/unit ./test/integration test-integration: - ./node_modules/.bin/mocha --recursive --timeout 10000 ./test/integration + ./node_modules/.bin/mocha --recursive --timeout 10000 --exit ./test/integration + +test-stats: + ./node_modules/.bin/mocha --timeout 10000 --exit ./test/integration/stats.js + +test-data: + ./node_modules/.bin/mocha --timeout 60000 --exit --bail ./test/integration/data.js + +test-synergy: + ./node_modules/.bin/mocha --timeout 10000 --exit --bail ./test/integration/synergy.js test-unit: ./node_modules/.bin/mocha --recursive ./test/unit/ diff --git a/package.json b/package.json index 36f6775..4a7fbb3 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "url": "https://github.com/bttmly/nba/issues" }, "dependencies": { + "axios": "^0.21.1", "camel-case": "^3.0.0", "lodash.find": "^3.2.0", "lodash.findwhere": "^3.1.0", @@ -29,6 +30,7 @@ "minimist": "^1.2.0", "nba-client-template": "4.5.0", "node-fetch": "2.6.1", + "puppeteer": "^5.5.0", "url": "^0.11.0" }, "devDependencies": { diff --git a/src/PuppeteerTransport.js b/src/PuppeteerTransport.js new file mode 100644 index 0000000..09d35ef --- /dev/null +++ b/src/PuppeteerTransport.js @@ -0,0 +1,139 @@ +const puppeteer = require("puppeteer"); +const { URL } = require("url"); + +const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"; + +const delay = (ms) => new Promise(r => setTimeout(r, ms)); + +class PuppeteerTransport { + static async create () { + const browser = await puppeteer.launch({ + headless: false, + handleSIGINT: false, + handleSIGTERM: false, + args: [ + "--disable-web-security", + ], + }); + return new PuppeteerTransport(browser); + } + + constructor (browser) { + this.browser = browser; + } + + async _createPage () { + const page = await this.browser.newPage(); + await page.setRequestInterception(true); + page.on("request", req => { + const type = req.resourceType(); + switch (type) { + case "document": + case "fetch": + req.continue(); + break; + default: + req.abort(); + } + }); + page.on("framenavigated", (frame) => { + console.log("NAVIGATION:", frame.url(), "main", frame === page.mainFrame()); + }); + await page.setUserAgent(USER_AGENT); + await page.goto("https://www.nba.com/stats/", { waitUntil: "domcontentloaded", timeout: 8 * 1000 }); + return page; + } + + async _getPage () { + if (this.pageP) { + return this.pageP; + } + this.pageP = this._createPage(); + return this.pageP; + } + + async run (_url) { + const page = await this._getPage(); + const result = await page.evaluate(async (url) => { + const headers = { + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "en,en-US;q=0.9", + Accept: "application/json, text/plain, */*", + Referer: "https://www.nba.com/", + Connection: "keep-alive", + "Cache-Control": "no-cache", + Origin: "http://www.nba.com", + // "x-nba-stats-origin": "stats", + // "x-nba-stats-token": "true", + }; + + try { + const res = await fetch(url, { headers }); + if (res.ok) { + const data = await res.json(); + return { data, ok: true }; + } + const text = await res.text(); + return { + ok: false, + data: { text, status: res.status }, + }; + } catch (err) { + console.log(err); + return { ok: false, data: { text: err.toString() }}; + } + }, _url); + return result; + } + + close () { + console.trace("browser close"); + return this.browser.close(); + } +}; + +let instanceP = null; + +async function transport (baseURL, query = {}) { + if (instanceP == null) { + instanceP = PuppeteerTransport.create(); + await delay(1); + } + const instance = await instanceP; + + const u = new URL(baseURL); + for (const [key, value] of Object.entries(query)) { + u.searchParams.append(key, value); + } + u.protocol = "https:"; + const result = await instance.run(u.toString()); + if (result.ok) return result.data; + throw new Error(`${result.data.text} – ${u.toString()}`); +} + +module.exports.transport = transport; +module.exports.closeTransport = async () => { + if (instanceP == null) return; + const instance = await instanceP; + await instance.browser.close(); +}; +module.exports.PuppeteerTransport = PuppeteerTransport; + +// (async () => { +// const urls = [ +// "https://stats.nba.com/stats/leaguedashteamstats?Conference=&DateFrom=&DateTo=&Division=&GameScope=&GameSegment=&LastNGames=0&LeagueID=00&Location=&MeasureType=Advanced&Month=0&OpponentTeamID=0&Outcome=&PORound=0&PaceAdjust=N&PerMode=PerGame&Period=0&PlayerExperience=&PlayerPosition=&PlusMinus=N&Rank=N&Season=2020-21&SeasonSegment=&SeasonType=Regular+Season&ShotClockRange=&StarterBench=&TeamID=0&TwoWay=0&VsConference=&VsDivision=", +// "http://stats.nba.com/stats/playerprofilev2?LeagueID=00&PerMode=PerGame&PlayerID=201939&Season=2017-18", +// ]; + +// const b = await puppeteer.launch({ +// args: [ +// "--disable-web-security", +// ], +// }); +// const p = new PuppeteerTransport(b); +// for (const u of urls) { +// const { ok, data } = await p.run(u); +// console.log(ok, data.text, u.split("?")[0]); +// } +// await p.close(); +// })(); \ No newline at end of file diff --git a/src/data.js b/src/data.js index f3971be..9f063a2 100644 --- a/src/data.js +++ b/src/data.js @@ -1,78 +1,96 @@ // this includes endpoints at data.nba.com -let transport = require("./get-json"); +const { defaultTransport } = require("./transport"); const { interpolate } = require("./util/string"); -const scoreboardURL = interpolate("http://data.nba.com/data/5s/json/cms/noseason/scoreboard/__date__/games.json"); -const boxScoreURL = interpolate("http://data.nba.com/data/5s/json/cms/noseason/game/__date__/__gameId__/boxscore.json"); -const playByPlayURL = interpolate("http://data.nba.com/data/5s/json/cms/noseason/game/__date__/__gameId__/pbp_all.json"); -const scheduleURL = interpolate("http://data.nba.com/data/10s/prod/v1/__season__/schedule.json"); -const teamScheduleURL = interpolate("http://data.nba.com/data/10s/prod/v1/__season__/teams/__teamId__/schedule.json"); -const previewArticleURL = interpolate("http://data.nba.com/data/10s/prod/v1/__date__/__gameId___preview_article.json"); -const recapArticleURL = interpolate("http://data.nba.com/data/10s/prod/v1/__date__/__gameId___recap_article.json"); -const leadTrackerURL = interpolate("http://data.nba.com/data/10s/prod/v1/__date__/__gameId___lead_tracker___period__.json"); -const playoffsBracketURL = interpolate("http://data.nba.com/data/10s/prod/v1/__season__/playoffsBracket.json"); -const teamLeadersURL = interpolate("http://data.nba.com/data/10s/prod/v1/__season__/teams/__teamId__/leaders.json"); -const teamStatsRankingsURL = interpolate("http://data.nba.com/data/10s/prod/v1/__season__/team_stats_rankings.json"); -const coachesURL = interpolate("http://data.nba.com/data/10s/prod/v1/__season__/coaches.json"); -const teamsURL = interpolate("http://data.nba.net/data/10s/prod/v1/__year__/teams.json"); - -const calendarURL = "http://data.nba.net/data/10s/prod/v1/calendar.json"; -const standingsURL = "http://data.nba.net/data/10s/prod/v1/current/standings_all.json"; - -const withTransport = (newTransport) => { - transport = newTransport; -}; +const scoreboardURL = interpolate("https://data.nba.com/data/5s/json/cms/noseason/scoreboard/__date__/games.json"); +const boxScoreURL = interpolate("https://data.nba.com/data/5s/json/cms/noseason/game/__date__/__gameId__/boxscore.json"); +const playByPlayURL = interpolate("https://data.nba.com/data/5s/json/cms/noseason/game/__date__/__gameId__/pbp_all.json"); +const scheduleURL = interpolate("https://data.nba.com/data/10s/prod/v1/__season__/schedule.json"); +const teamScheduleURL = interpolate("https://data.nba.com/data/10s/prod/v1/__season__/teams/__teamId__/schedule.json"); +const previewArticleURL = interpolate("https://data.nba.com/data/10s/prod/v1/__date__/__gameId___preview_article.json"); +const recapArticleURL = interpolate("https://data.nba.com/data/10s/prod/v1/__date__/__gameId___recap_article.json"); +const leadTrackerURL = interpolate("https://data.nba.com/data/10s/prod/v1/__date__/__gameId___lead_tracker___period__.json"); +const playoffsBracketURL = interpolate("https://data.nba.com/data/10s/prod/v1/__season__/playoffsBracket.json"); +const teamLeadersURL = interpolate("https://data.nba.com/data/10s/prod/v1/__season__/teams/__teamId__/leaders.json"); +const teamStatsRankingsURL = interpolate("https://data.nba.com/data/10s/prod/v1/__season__/team_stats_rankings.json"); +const coachesURL = interpolate("https://data.nba.com/data/10s/prod/v1/__season__/coaches.json"); +const teamsURL = interpolate("https://data.nba.net/data/10s/prod/v1/__year__/teams.json"); + +const calendarURL = "https://data.nba.net/data/10s/prod/v1/calendar.json"; +const standingsURL = "https://data.nba.net/data/10s/prod/v1/current/standings_all.json"; // NOTE: the 'date' argument should be a string in format like "20181008" (which indicates Oct 8 2018) // You *can* pass a Date object but beware of timezone weirdness! // NOTE: the 'season' argument is the first year of the NBA season e.g. "2018" for the 2018-19 season -const scoreboard = date => transport(scoreboardURL({ date: dateToYYYYMMDD(date) })); -scoreboard.defaults = { date: null }; +const withTransport = (transportOverride) => { + const transport = transportOverride || defaultTransport; + + const scoreboard = date => transport(scoreboardURL({ date: dateToYYYYMMDD(date) })); + scoreboard.defaults = { date: null }; -const boxScore = (date, gameId) => transport(boxScoreURL({ date: dateToYYYYMMDD(date), gameId })); -boxScore.defaults = { date: null, gameId: null }; + const boxScore = (date, gameId) => transport(boxScoreURL({ date: dateToYYYYMMDD(date), gameId })); + boxScore.defaults = { date: null, gameId: null }; -const playByPlay = (date, gameId) => transport(playByPlayURL({ date: dateToYYYYMMDD(date), gameId })); -playByPlay.defaults = { date: null, gameId: null }; + const playByPlay = (date, gameId) => transport(playByPlayURL({ date: dateToYYYYMMDD(date), gameId })); + playByPlay.defaults = { date: null, gameId: null }; -const schedule = (season) => transport(scheduleURL({ season })); -schedule.defaults = { season: null }; + const schedule = (season) => transport(scheduleURL({ season })); + schedule.defaults = { season: null }; -const teamSchedule = (season, teamId) => transport(teamScheduleURL({ season, teamId })); -teamSchedule.defaults = { season: null, teamId: null }; + const teamSchedule = (season, teamId) => transport(teamScheduleURL({ season, teamId })); + teamSchedule.defaults = { season: null, teamId: null }; -const previewArticle = (date, gameId) => transport(previewArticleURL({date: dateToYYYYMMDD(date), gameId })); -previewArticle.defaults = { date: null, gameId: null }; + const previewArticle = (date, gameId) => transport(previewArticleURL({date: dateToYYYYMMDD(date), gameId })); + previewArticle.defaults = { date: null, gameId: null }; -const recapArticle = (date, gameId) => transport(recapArticleURL({date: dateToYYYYMMDD(date), gameId })); -recapArticle.defaults = { date: null, gameId: null }; + const recapArticle = (date, gameId) => transport(recapArticleURL({date: dateToYYYYMMDD(date), gameId })); + recapArticle.defaults = { date: null, gameId: null }; -const leadTracker = (date, gameId, period) => transport(leadTrackerURL({date: dateToYYYYMMDD(date), gameId, period })); -leadTracker.defaults = { date: null, gameId: null, period: null }; + const leadTracker = (date, gameId, period) => transport(leadTrackerURL({date: dateToYYYYMMDD(date), gameId, period })); + leadTracker.defaults = { date: null, gameId: null, period: null }; -const playoffsBracket = (season) => transport(playoffsBracketURL({ season })); -playoffsBracket.defaults = { season: null }; + const playoffsBracket = (season) => transport(playoffsBracketURL({ season })); + playoffsBracket.defaults = { season: null }; -const teamLeaders = (season, teamId) => transport(teamLeadersURL({ season, teamId })); -teamLeaders.defaults = { season: null, teamId: null }; + const teamLeaders = (season, teamId) => transport(teamLeadersURL({ season, teamId })); + teamLeaders.defaults = { season: null, teamId: null }; -const teamStatsRankings = (season) => transport(teamStatsRankingsURL({ season })); -teamStatsRankings.defaults = { season: null }; + const teamStatsRankings = (season) => transport(teamStatsRankingsURL({ season })); + teamStatsRankings.defaults = { season: null }; -const coaches = (season) => transport(coachesURL({ season })); -coaches.defaults = { season: null }; + const coaches = (season) => transport(coachesURL({ season })); + coaches.defaults = { season: null }; -const teams = (year = "2019") => transport(teamsURL({ year })); -teams.defaults = { year: null }; + const teams = (year = "2019") => transport(teamsURL({ year })); + teams.defaults = { year: null }; -const calendar = () => transport(calendarURL); -calendar.defaults = {}; + const calendar = () => transport(calendarURL); + calendar.defaults = {}; -const standings = () => transport(standingsURL); -standings.defaults = {}; + const standings = () => transport(standingsURL); + standings.defaults = {}; + + return { + scoreboard, + boxScore, + playByPlay, + schedule, + teamSchedule, + previewArticle, + recapArticle, + leadTracker, + playoffsBracket, + teamLeaders, + teamStatsRankings, + coaches, + teams, + calendar, + standings, + }; +}; function dateToYYYYMMDD (date) { if (date instanceof Date) { @@ -82,27 +100,12 @@ function dateToYYYYMMDD (date) { String(date.getDate()).padStart(2, 0), ].join(""); } - - // TODO: better checking here? - return date; } +const client = withTransport(); + module.exports = { - scoreboard, - boxScore, - playByPlay, - schedule, - teamSchedule, - previewArticle, - recapArticle, - leadTracker, - playoffsBracket, - teamLeaders, - teamStatsRankings, - coaches, - teams, - calendar, - standings, + ...client, withTransport, }; \ No newline at end of file diff --git a/src/get-json.js b/src/get-json.js index c9c2989..585bfbd 100644 --- a/src/get-json.js +++ b/src/get-json.js @@ -1,16 +1,16 @@ const url = require("url"); const template = require("nba-client-template"); -const fetch = require("node-fetch"); +const axios = require("axios"); const HEADERS = { - "Accept-Encoding": "gzip, deflate", - "Accept-Language": "en-US", - Accept: "*/*", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "en,en-US;q=0.9", + Accept: "application/json, text/plain, */*", "User-Agent": template.user_agent, - Referer: template.referrer, + Referer: "www.nba.com", Connection: "keep-alive", "Cache-Control": "no-cache", - Origin: "http://stats.nba.com", + Origin: "https://www.nba.com", }; function createUrlString (_url, query) { @@ -19,22 +19,23 @@ function createUrlString (_url, query) { return urlObj.format(); } -module.exports = function getJson (_url, query, _options = {}) { - const urlStr = createUrlString(_url, query); - +async function getJsonAxios (_url, params, _options = {}) { const options = { ..._options, - headers: { ..._options.headers, ...HEADERS }, + headers: { ...HEADERS, ..._options.headers }, }; - return fetch(urlStr, options) - .then(resp => { - if (resp.ok) return resp.json(); - - return resp.text().then(function (text) { - throw new Error(`${resp.status} ${resp.statusText} – ${text}`); - }); - }); + const urlStr = createUrlString(_url, params); + try { + const res = await axios.get(urlStr, options); + return res.data; + } catch (err) { + const { response } = err; + if (response) { + throw new Error(`${response.status} ${response.data}`); + } + throw new Error(`Unknown HTTP error for ${url}`); + } }; - +module.exports = getJsonAxios; \ No newline at end of file diff --git a/src/stats.js b/src/stats.js index 3ce014d..49ec7a1 100644 --- a/src/stats.js +++ b/src/stats.js @@ -46,13 +46,14 @@ function makeStatsMethod (endpoint, transport) { const ccName = camelCase(endpoint.name); const transform = transformMap[ccName]; - function statsMethod (query = {}) { - const reqParams = Object.assign({}, defaults, query); + async function statsMethod (query = {}) { + const reqParams = { ...defaults, ...query }; const options = { headers: { - "x-nba-stats-origin": "stats", - "x-nba-stats-token": "true", + // "x-nba-stats-origin": "stats", + // "x-nba-stats-token": "true", + // "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36", }, }; @@ -80,4 +81,7 @@ function makeStatsClient (transport) { return client; } -module.exports = makeStatsClient(require("./get-json")); +const { defaultTransport } = require("./transport"); + +module.exports = makeStatsClient(defaultTransport); + diff --git a/src/synergy.js b/src/synergy.js index 75bb3f3..34dd421 100644 --- a/src/synergy.js +++ b/src/synergy.js @@ -1,4 +1,5 @@ const camelCase = require("camel-case"); +const { defaultTransport } = require("./transport"); const parameters = [ { @@ -44,8 +45,8 @@ const parameters = [ ]; const synergyEndpoints = [ - { name: "player_play_type", url: "http://stats-prod.nba.com/wp-json/statscms/v1/synergy/player/" }, - { name: "team_play_type", url: "http://stats-prod.nba.com/wp-json/statscms/v1/synergy/team/" }, + { name: "player_play_type", url: "https://stats-prod.nba.com/wp-json/statscms/v1/synergy/player/" }, + { name: "team_play_type", url: "https://stats-prod.nba.com/wp-json/statscms/v1/synergy/team/" }, ]; const defaults = {}; @@ -76,4 +77,5 @@ function makeSynergyClient (transport) { return client; } -module.exports = makeSynergyClient(require("./get-json")); + +module.exports = makeSynergyClient(defaultTransport); diff --git a/src/transport.js b/src/transport.js new file mode 100644 index 0000000..a5bb5df --- /dev/null +++ b/src/transport.js @@ -0,0 +1,11 @@ +let _defaultTransport = require("./get-json"); + +function defaultTransport (...args) { + return _defaultTransport(...args); +} + +function setDefaultTransport (t) { + _defaultTransport = t; +} + +module.exports = { defaultTransport, setDefaultTransport }; \ No newline at end of file diff --git a/test/get-json-stub.js b/test/get-json-stub.js deleted file mode 100644 index 31121bd..0000000 --- a/test/get-json-stub.js +++ /dev/null @@ -1,18 +0,0 @@ -var DELAY = 10; - -function jsonStub (url, settings) { - return new Promise(function (resolve) { - setTimeout(() => resolve(), DELAY); - }); -} - -function jsonFailStub (url, settings, callback) { - return new Promise(function (__, reject) { - setTimeout(() => reject(new Error()), DELAY) - }); -} - -module.exports = { - success: jsonStub, - fail: jsonFailStub, -}; diff --git a/test/hooks.js b/test/hooks.js new file mode 100644 index 0000000..8aa46e4 --- /dev/null +++ b/test/hooks.js @@ -0,0 +1,11 @@ +const { setDefaultTransport } = require("../src/transport"); +const p = require("../src/PuppeteerTransport"); + +exports.mochaHooks = { + beforeAll () { + // setDefaultTransport(p.transport); + }, + async afterAll () { + // await p.closeTransport(); + }, +}; \ No newline at end of file diff --git a/test/inspect.js b/test/inspect.js deleted file mode 100644 index 079221b..0000000 --- a/test/inspect.js +++ /dev/null @@ -1,17 +0,0 @@ -const path = require("path"); -const { REPLServer } = require("repl"); - -const Mocha = require("mocha"); -const mocha = new Mocha({ timeout: 30000 }); - -mocha.addFile(path.join(__dirname, "integration/stats.js")); -mocha.addFile(path.join(__dirname, "integration/sport-vu.js")); - -const repl = new REPLServer(); - -mocha.run(function(failures) { - console.log("responses are loaded into global `StatsData` and `SportVuData` objects... Enjoy!"); - repl.start({ prompt: "🏀 > " }); -}); - -module.exports = repl; diff --git a/test/integration/data.js b/test/integration/data.js index 9d9ced6..fd9c1ce 100644 --- a/test/integration/data.js +++ b/test/integration/data.js @@ -1,7 +1,7 @@ const nba = require("../../"); describe("nba data methods", function () { - describe("#scoreboard", async () => { + describe("#scoreboard", () => { it("works with a direct date string", async () => { log(await nba.data.scoreboard("20181008")); }); diff --git a/test/integration/stats.js b/test/integration/stats.js index 5aae6c6..3602b41 100644 --- a/test/integration/stats.js +++ b/test/integration/stats.js @@ -83,17 +83,23 @@ describe("nba stats methods", function () { it("#playerCompare", callMethod("playerCompare", { PlayerIDList: _steph, VsPlayerIDList: _steph })); - after(function () { - return Promise.all(Object.keys(global.StatsData).map(k => - pify(fs.writeFile)( - path.join(__dirname, "../../responses", `stats-${k}.json`), - JSON.stringify(global.StatsData[k], null, 2) - ) - )) - .catch(console.error); + after(async () => { + for (const [key, value] of Object.entries(global.StatsData)) { + await writeResponse(key, value); + } }); }); +const writeFile = pify(fs.writeFile); +async function writeResponse (key, value) { + try { + await writeFile( + path.join(__dirname, "../../responses", `stats-${key}.json`), + JSON.stringify(value, null, 2) + ); + } catch (e) {} +} + // describe("tested all methods", function () { // it("did test all methods", () => { // try { diff --git a/test/integration/synergy.js b/test/integration/synergy.js index a2b3bcf..1b5da84 100644 --- a/test/integration/synergy.js +++ b/test/integration/synergy.js @@ -7,15 +7,15 @@ const writeFile = pify(require("fs").writeFile); const dir = path.join(__dirname, "../../responses"); function writeData (name, data) { const str = JSON.stringify(data, null, 2); - return writeFile(path.join(dir, `synergy-${name}.json`), str); + return writeFile(path.join(dir, `synergy-${name}.json`), str).catch(() => {}); } global.SynergyData = {}; // stub for now, will add response shape verification for self-documenting responses -const verifyShape = shape => response => response; +// const verifyShape = shape => response => response; -const callMethod = (name, params = {}, shape) => () => { +const callMethod = (name, params = {}) => () => { params.season = 2016; return nba.synergy[name](params) .then(function (resp) { diff --git a/test/nba-api-spy.js b/test/nba-api-spy.js deleted file mode 100644 index ff712db..0000000 --- a/test/nba-api-spy.js +++ /dev/null @@ -1,22 +0,0 @@ -var sinon = require("sinon"); - -var optionPosition = 1; -var urlPosition = 0; - -module.exports = function (...args) { - var spy = sinon.spy(...args); - spy.lastCalledWithOption = function (option, value) { - var opts = spy.lastCall.args[optionPosition]; - if (opts[option] == null) { - return false; - } - if (value) { - return opts[option] === value; - } - return true; - }; - spy.lastCalledWithUrl = function (url) { - return spy.lastCall.args[urlPosition] === url; - }; - return spy; -}; diff --git a/test/scratchpad.js b/test/scratchpad.js new file mode 100644 index 0000000..83392bc --- /dev/null +++ b/test/scratchpad.js @@ -0,0 +1,31 @@ +const { getJsonNodeFetch, getJsonAxios } = require("../src/get-json"); + +async function main () { + const url = "https://stats.nba.com/stats/leagueLeaders"; + const query = { + "ActiveFlag": "No", + "LeagueID": "00", + "PerMode": "Totals", + "Scope": "S", + "Season": "All Time", + "SeasonType": "Regular Season", + "StatCategory": "PTS", + }; + let err, result; + + ({ err, result } = await settle(getJsonNodeFetch(url, query))); + console.log({ err, result }); + ({ err, result } = await settle(getJsonAxios(url, query))); + console.log({ err, result }); +} + +async function settle (p) { + try { + const result = await p; + return { result }; + } catch (err) { + return { err }; + } +} + +main(); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index ce0214a..fbdaa63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,11 +23,23 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== +"@types/node@*": + version "14.14.22" + resolved "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz#0d29f382472c4ccf3bd96ff0ce47daf5b7b84b18" + integrity sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw== + "@types/node@^12.6.9": version "12.7.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.0.tgz#545dde2a1a5c27d281cfb8308d6736e0708f5d6c" integrity sha512-vqcj1MVm2Sla4PpMfYKh1MyDN4D2f/mPIZD7RdAGqEsbE+JxfeqQHHVbRDQ0Nqn8i73gJa1HQ1Pu3+nH4Q0Yiw== +"@types/yauzl@^2.9.1": + version "2.9.1" + resolved "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz#d10f69f9f522eef3cf98e30afb684a1e1ec923af" + integrity sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA== + dependencies: + "@types/node" "*" + "@ungap/promise-all-settled@1.1.2": version "1.1.2" resolved "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" @@ -43,6 +55,11 @@ acorn@^6.0.7, acorn@^6.2.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== +agent-base@5: + version "5.1.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" + integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== + ajv@^6.10.0, ajv@^6.9.1: version "6.10.1" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.1.tgz#ebf8d3af22552df9dd049bfbe50cc2390e823593" @@ -107,16 +124,37 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +axios@^0.21.1: + version "0.21.1" + resolved "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + dependencies: + follow-redirects "^1.10.0" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +bl@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489" + integrity sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -137,6 +175,19 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + +buffer@^5.2.1, buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -197,6 +248,11 @@ chokidar@3.4.3: optionalDependencies: fsevents "~2.1.2" +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -263,6 +319,13 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" +debug@4, debug@^4.1.0, debug@^4.1.1: + version "4.3.1" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + debug@4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" @@ -300,6 +363,11 @@ define-properties@^1.1.1, define-properties@~1.1.2: foreach "^2.0.5" object-keys "^1.0.8" +devtools-protocol@0.0.818844: + version "0.0.818844" + resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.818844.tgz#d1947278ec85b53e4c8ca598f607a28fa785ba9e" + integrity sha512-AD1hi7iVJ8OD0aMLQU5VK0XH9LDlA1+BcPIgrAxPfaibx2DbWucuyOhc4oyQCbnvDDO68nN6/LcKfqTP343Jjg== + diff@4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -317,6 +385,13 @@ emoji-regex@^7.0.1: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + es-abstract@^1.3.2: version "1.6.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.6.1.tgz#bb8a2064120abcf928a086ea3d9043114285ec99" @@ -468,6 +543,17 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" +extract-zip@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== + dependencies: + debug "^4.1.1" + get-stream "^5.1.0" + yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" + fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -483,6 +569,13 @@ fast-levenshtein@~2.0.4: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -519,6 +612,14 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + flat-cache@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" @@ -538,6 +639,11 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== +follow-redirects@^1.10.0: + version "1.13.2" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz#dd73c8effc12728ba5cf4259d760ea5fb83e3147" + integrity sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA== + foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" @@ -550,6 +656,11 @@ formatio@1.1.1: dependencies: samsam "~1.1" +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -575,6 +686,13 @@ get-caller-file@^2.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -646,6 +764,14 @@ he@1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +https-proxy-agent@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b" + integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg== + dependencies: + agent-base "5" + debug "4" + iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -653,6 +779,11 @@ iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -689,6 +820,11 @@ inherits@2.0.1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= +inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + inquirer@^6.2.2: version "6.4.1" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.4.1.tgz#7bd9e5ab0567cd23b41b0180b68e0cfa82fc3c0b" @@ -870,6 +1006,13 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -1132,6 +1275,11 @@ minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.3.tgz#3db5c0765545ab8637be71f333a104a965a9ca3f" integrity sha512-+bMdgqjMN/Z77a6NlY/I3U5LlRDbnmaAk6lDveAPKwSpcPM4tKAuYsvYF8xjhOPXhOYGe/73vVLVez5PW+jqhw== +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -1212,15 +1360,7 @@ no-case@^2.2.0: dependencies: lower-case "^1.1.1" -node-environment-flags@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" - integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== - dependencies: - object.getownpropertydescriptors "^2.0.3" - semver "^5.7.0" - -node-fetch@2.6.1: +node-fetch@2.6.1, node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== @@ -1259,7 +1399,7 @@ object.entries@^1.0.3: function-bind "^1.0.2" has "^1.0.1" -once@^1.3.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -1305,6 +1445,13 @@ p-limit@^2.0.0: dependencies: p-try "^2.0.0" +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -1319,6 +1466,13 @@ p-locate@^3.0.0: dependencies: p-limit "^2.0.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-locate@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -1363,6 +1517,11 @@ path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + picomatch@^2.0.4, picomatch@^2.2.1: version "2.2.2" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" @@ -1373,16 +1532,36 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -progress@^2.0.0: +progress@^2.0.0, progress@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +proxy-from-env@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -1393,6 +1572,24 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +puppeteer@^5.5.0: + version "5.5.0" + resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-5.5.0.tgz#331a7edd212ca06b4a556156435f58cbae08af00" + integrity sha512-OM8ZvTXAhfgFA7wBIIGlPQzvyEETzDjeRa4mZRCRHxYL+GNH5WAuYUQdja3rpWZvkX/JKqmuVgbsxDNsDFjMEg== + dependencies: + debug "^4.1.0" + devtools-protocol "0.0.818844" + extract-zip "^2.0.0" + https-proxy-agent "^4.0.0" + node-fetch "^2.6.1" + pkg-dir "^4.2.0" + progress "^2.0.1" + proxy-from-env "^1.0.0" + rimraf "^3.0.2" + tar-fs "^2.0.0" + unbzip2-stream "^1.3.3" + ws "^7.2.3" + querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" @@ -1405,6 +1602,15 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" +readable-stream@^3.1.1, readable-stream@^3.4.0: + version "3.6.0" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@~3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" @@ -1447,6 +1653,13 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + rollup@^1.19.3: version "1.19.3" resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.19.3.tgz#77e59426faa6d8399e7b75c129e81447cf9db317" @@ -1470,7 +1683,7 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" -safe-buffer@^5.1.0: +safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -1560,6 +1773,13 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" @@ -1608,12 +1828,33 @@ table@^5.2.3: slice-ansi "^2.1.0" string-width "^3.0.0" +tar-fs@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -through@^2.3.6: +through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -1649,6 +1890,14 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +unbzip2-stream@^1.3.3: + version "1.4.3" + resolved "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" + integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== + dependencies: + buffer "^5.2.1" + through "^2.3.8" + upper-case@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" @@ -1669,6 +1918,11 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + "util@>=0.10.3 <1": version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" @@ -1738,6 +1992,11 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" +ws@^7.2.3: + version "7.4.2" + resolved "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz#782100048e54eb36fe9843363ab1c68672b261dd" + integrity sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA== + y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" @@ -1777,6 +2036,14 @@ yargs@13.3.2: y18n "^4.0.0" yargs-parser "^13.1.2" +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" From b7b630d44249e3bf29b83ed7ed6256b7b3a671e2 Mon Sep 17 00:00:00 2001 From: Nick Bottomley Date: Fri, 29 Jan 2021 19:36:43 -0800 Subject: [PATCH 5/7] wonder if itll work on travis --- Makefile | 2 +- test/hooks.js | 4 ++-- test/integration/stats.js | 11 +---------- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index e69109c..10bea05 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ test-integration: ./node_modules/.bin/mocha --recursive --timeout 10000 --exit ./test/integration test-stats: - ./node_modules/.bin/mocha --timeout 10000 --exit ./test/integration/stats.js + ./node_modules/.bin/mocha --timeout 30000 ./test/integration/stats.js test-data: ./node_modules/.bin/mocha --timeout 60000 --exit --bail ./test/integration/data.js diff --git a/test/hooks.js b/test/hooks.js index 8aa46e4..8dd8efa 100644 --- a/test/hooks.js +++ b/test/hooks.js @@ -3,9 +3,9 @@ const p = require("../src/PuppeteerTransport"); exports.mochaHooks = { beforeAll () { - // setDefaultTransport(p.transport); + setDefaultTransport(p.transport); }, async afterAll () { - // await p.closeTransport(); + await p.closeTransport(); }, }; \ No newline at end of file diff --git a/test/integration/stats.js b/test/integration/stats.js index 3602b41..19df509 100644 --- a/test/integration/stats.js +++ b/test/integration/stats.js @@ -6,8 +6,6 @@ const pify = require("pify"); const nba = require("../../"); -// for interactive inspection, particularly in browser -global.StatsData = {}; const tested = {}; const methods = {}; @@ -33,7 +31,7 @@ const callMethod = (name, params = {}, shape) => async () => { params.Season = "2017-18"; const r = await stats[name](params); verifyShape(shape, r); - global.StatsData[name] = r; + await writeResponse(name, r); }; const _steph = 201939; @@ -81,13 +79,6 @@ describe("nba stats methods", function () { it("#leagueStandings", callMethod("leagueStandings")); it("#teamPlayerOnOffDetails", callMethod("teamPlayerOnOffDetails", { TeamID: _dubs })); it("#playerCompare", callMethod("playerCompare", { PlayerIDList: _steph, VsPlayerIDList: _steph })); - - - after(async () => { - for (const [key, value] of Object.entries(global.StatsData)) { - await writeResponse(key, value); - } - }); }); const writeFile = pify(fs.writeFile); From ac1b6c99226cbe67a516de42bcd20ddcd5e341e4 Mon Sep 17 00:00:00 2001 From: Nick Bottomley Date: Fri, 29 Jan 2021 19:38:55 -0800 Subject: [PATCH 6/7] node 14 travis --- src/PuppeteerTransport.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PuppeteerTransport.js b/src/PuppeteerTransport.js index 09d35ef..7d78cf3 100644 --- a/src/PuppeteerTransport.js +++ b/src/PuppeteerTransport.js @@ -8,7 +8,6 @@ const delay = (ms) => new Promise(r => setTimeout(r, ms)); class PuppeteerTransport { static async create () { const browser = await puppeteer.launch({ - headless: false, handleSIGINT: false, handleSIGTERM: false, args: [ From 15fa041beff9edeb1d0e83281835b3b2d74b3404 Mon Sep 17 00:00:00 2001 From: Nick Bottomley Date: Sat, 30 Jan 2021 00:25:42 -0800 Subject: [PATCH 7/7] run transport --- scripts/run-transport.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 scripts/run-transport.js diff --git a/scripts/run-transport.js b/scripts/run-transport.js new file mode 100644 index 0000000..4e399e0 --- /dev/null +++ b/scripts/run-transport.js @@ -0,0 +1,20 @@ +const { NBA_URL, TRANSPORT = "basic" } = process.env; +const { defaultTransport, setDefaultTransport } = require("../src/transport"); +const { transport: puppeteerTransport } = require("../src/PuppeteerTransport"); +const { URL } = require("url"); +const transforms = require("../src/transforms"); + +if (!NBA_URL) throw new Error("must provide NBA_URL"); + +(async () => { + if (TRANSPORT !== "basic") { + setDefaultTransport(puppeteerTransport); + } + + + let url = new URL(NBA_URL).toString(); + url = url.split("\\").join(""); + const result = await defaultTransport(url); + console.log(transforms.general(result)); + // console.log(JSON.stringify(result)); +})();