diff --git a/package.json b/package.json index e575e48520..6a6bbc3fb4 100644 --- a/package.json +++ b/package.json @@ -187,6 +187,7 @@ "@hapi/call": "^8.0.0", "@hapi/subtext": "^7.0.3", "@kubernetes/client-node": "^0.12.0", + "@types/url-parse": "^1.4.3", "array-move": "^3.0.0", "await-lock": "^2.1.0", "byline": "^5.0.0", @@ -232,6 +233,7 @@ "tar": "^6.0.5", "tcp-port-used": "^1.0.1", "tempy": "^0.5.0", + "url-parse": "^1.5.1", "uuid": "^8.3.2", "win-ca": "^3.2.0", "winston": "^3.2.1", diff --git a/src/renderer/api/endpoints/helm-charts.api.ts b/src/renderer/api/endpoints/helm-charts.api.ts index 8beff01779..b62747df69 100644 --- a/src/renderer/api/endpoints/helm-charts.api.ts +++ b/src/renderer/api/endpoints/helm-charts.api.ts @@ -1,6 +1,6 @@ import { compile } from "path-to-regexp"; import { apiBase } from "../index"; -import { stringify } from "querystring"; +import * as querystring from "querystring"; import { autobind } from "../../utils"; interface IHelmChartList { @@ -19,39 +19,44 @@ const endpoint = compile(`/v2/charts/:repo?/:name?`) as (params?: { name?: string; }) => string; -export const helmChartsApi = { - list() { - return apiBase - .get(endpoint()) - .then(data => { - return Object - .values(data) - .reduce((allCharts, repoCharts) => allCharts.concat(Object.values(repoCharts)), []) - .map(HelmChart.create); - }); - }, +export async function list(): Promise { + const data = await apiBase.get(endpoint()); - get(repo: string, name: string, readmeVersion?: string) { - const path = endpoint({ repo, name }); + return Object + .values(data) + .reduce((allCharts, repoCharts) => allCharts.concat(Object.values(repoCharts)), []) + .map(HelmChart.create); +} - return apiBase - .get(`${path}?${stringify({ version: readmeVersion })}`) - .then(data => { - const versions = data.versions.map(HelmChart.create); - const readme = data.readme; +interface GetHelmChartInfoOptions { + readmeVersion?: string; +} - return { - readme, - versions, - }; - }); - }, +export interface HelmChartInfo { + readme: string; + versions: HelmChart[]; +} - getValues(repo: string, name: string, version: string) { - return apiBase - .get(`/v2/charts/${repo}/${name}/values?${stringify({ version })}`); - } -}; +export async function get(repo: string, name: string, { readmeVersion }: GetHelmChartInfoOptions = {}): Promise { + const path = endpoint({ repo, name }); + const qs = querystring.stringify({ version: readmeVersion }); + const url = `${path}?${qs}`; + const { readme, versions: rawVersions } = await apiBase.get(url); + const versions = rawVersions.map(HelmChart.create); + + return { + readme, + versions, + }; +} + +export async function getValues(repo: string, name: string, readmeVersion: string): Promise { + const path = endpoint({ repo, name }); + const qs = querystring.stringify({ version: readmeVersion }); + const url = `${path}/values?${qs}`; + + return apiBase.get(url); +} @autobind() export class HelmChart { diff --git a/src/renderer/api/json-api.ts b/src/renderer/api/json-api.ts index df12b08ab7..0d1e195b66 100644 --- a/src/renderer/api/json-api.ts +++ b/src/renderer/api/json-api.ts @@ -1,9 +1,9 @@ // Base http-service / json-api class -import { stringify } from "querystring"; import { EventEmitter } from "../../common/event-emitter"; import { cancelableFetch } from "../utils/cancelableFetch"; import { randomBytes } from "crypto"; +import Url from "url-parse"; export interface JsonApiData { } @@ -58,19 +58,13 @@ export class JsonApi { getResponse(path: string, params?: P, init: RequestInit = {}): Promise { const reqPath = `${this.config.apiBase}${path}`; const subdomain = randomBytes(2).toString("hex"); - let reqUrl = `http://${subdomain}.${window.location.host}${reqPath}`; // hack around browser connection limits (chromium allows 6 per domain) - const reqInit: RequestInit = { ...init }; - const { query } = params || {} as P; + const reqUrl = new Url(`http://${subdomain}.${window.location.host}${reqPath}`); // hack around browser connection limits (chromium allows 6 per domain) + const reqInit: RequestInit = { ...init, method: "get" }; - if (!reqInit.method) { - reqInit.method = "get"; - } - - if (query) { - const queryString = stringify(query); - - reqUrl += (reqUrl.includes("?") ? "&" : "?") + queryString; - } + reqUrl.set("query", { + ...(params?.query ?? {}), + ...reqUrl.query, + }); const infoLog: JsonApiLog = { method: reqInit.method.toUpperCase(), @@ -80,7 +74,7 @@ export class JsonApi { this.writeLog({ ...infoLog }); - return fetch(reqUrl, reqInit); + return fetch(reqUrl.toString(), reqInit); } post(path: string, params?: P, reqInit: RequestInit = {}) { @@ -100,19 +94,19 @@ export class JsonApi { } protected request(path: string, params?: P, init: RequestInit = {}) { - let reqUrl = this.config.apiBase + path; - const reqInit: RequestInit = { ...this.reqInit, ...init }; - const { data, query } = params || {} as P; + const targetUrl = new Url(this.config.apiBase + path); + const reqInit = { ...this.reqInit, ...init }; - if (data && !reqInit.body) { - reqInit.body = JSON.stringify(data); + if (params?.data && !reqInit.body) { + reqInit.body = JSON.stringify(params?.data); } - if (query) { - const queryString = stringify(query); + targetUrl.set("query", { + ...(params?.query ?? {}), + ...targetUrl.query, + }); - reqUrl += (reqUrl.includes("?") ? "&" : "?") + queryString; - } + const reqUrl = targetUrl.toString(); const infoLog: JsonApiLog = { method: reqInit.method.toUpperCase(), reqUrl, diff --git a/src/renderer/components/dock/install-chart.store.ts b/src/renderer/components/dock/install-chart.store.ts index 4979bb28a0..169e481583 100644 --- a/src/renderer/components/dock/install-chart.store.ts +++ b/src/renderer/components/dock/install-chart.store.ts @@ -1,7 +1,8 @@ import { action, autorun } from "mobx"; import { dockStore, IDockTab, TabId, TabKind } from "./dock.store"; import { DockTabStore } from "./dock-tab.store"; -import { HelmChart, helmChartsApi } from "../../api/endpoints/helm-charts.api"; +import { HelmChart } from "../../api/endpoints/helm-charts.api"; +import * as helmChartsApi from "../../api/endpoints/helm-charts.api"; import { IReleaseUpdateDetails } from "../../api/endpoints/helm-releases.api"; import { Notifications } from "../notifications"; @@ -54,7 +55,7 @@ export class InstallChartStore extends DockTabStore { const { repo, name, version } = this.getData(tabId); this.versions.clearData(tabId); // reset - const charts = await helmChartsApi.get(repo, name, version); + const charts = await helmChartsApi.get(repo, name, { readmeVersion: version }); const versions = charts.versions.map(chartVersion => chartVersion.version); this.versions.setData(tabId, versions); diff --git a/yarn.lock b/yarn.lock index 2cc97b2383..019f35a509 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1771,6 +1771,11 @@ resolved "https://registry.yarnpkg.com/@types/universal-analytics/-/universal-analytics-0.4.4.tgz#496a52b92b599a0112bec7c12414062de6ea8449" integrity sha512-9g3F0SGxVr4UDd6y07bWtFnkpSSX1Ake7U7AGHgSFrwM6pF53/fV85bfxT2JLWS/3sjLCcyzoYzQlCxpkVo7wA== +"@types/url-parse@^1.4.3": + version "1.4.3" + resolved "https://registry.yarnpkg.com/@types/url-parse/-/url-parse-1.4.3.tgz#fba49d90f834951cb000a674efee3d6f20968329" + integrity sha512-4kHAkbV/OfW2kb5BLVUuUMoumB3CP8rHqlw48aHvFy5tf9ER0AfOonBlX29l/DD68G70DmyhRlSYfQPSYpC5Vw== + "@types/uuid@^8.3.0": version "8.3.0" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" @@ -13762,6 +13767,14 @@ url-parse@^1.4.3: querystringify "^2.1.1" requires-port "^1.0.0" +url-parse@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.1.tgz#d5fa9890af8a5e1f274a2c98376510f6425f6e3b" + integrity sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + url-to-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"