diff --git a/open-lens/package.json b/open-lens/package.json index d49e44a3bf..1d5d60f642 100644 --- a/open-lens/package.json +++ b/open-lens/package.json @@ -205,6 +205,7 @@ "@k8slens/react-application": "^1.0.0", "@k8slens/resizing-anchor": "^1.0.0", "@k8slens/resource-templates": "^1.0.0", + "@k8slens/route": "^1.0.0", "@k8slens/routing": "^1.0.0", "@k8slens/run-many": "^1.0.0", "@k8slens/startable-stoppable": "^1.0.0", diff --git a/package-lock.json b/package-lock.json index 35860dbc1d..d4b6313ef7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3817,6 +3817,10 @@ "resolved": "packages/resource-templates", "link": true }, + "node_modules/@k8slens/route": { + "resolved": "packages/utility-features/route", + "link": true + }, "node_modules/@k8slens/routing": { "resolved": "packages/routing", "link": true @@ -3833,10 +3837,6 @@ "resolved": "packages/utility-features/startable-stoppable", "link": true }, - "node_modules/@k8slens/table-tokens": { - "resolved": "packages/table", - "link": true - }, "node_modules/@k8slens/test-utils": { "resolved": "packages/utility-features/test-utils", "link": true @@ -34010,6 +34010,7 @@ "@k8slens/react-application": "^1.0.0", "@k8slens/resizing-anchor": "^1.0.0", "@k8slens/resource-templates": "^1.0.0", + "@k8slens/route": "^1.0.0", "@k8slens/routing": "^1.0.0", "@k8slens/run-many": "^1.0.0", "@k8slens/startable-stoppable": "^1.0.0", @@ -34325,10 +34326,10 @@ "@k8slens/react-application": "^1.0.0-alpha.5", "@k8slens/resizing-anchor": "^1.0.0-alpha.5", "@k8slens/resource-templates": "^1.0.0-alpha.1", + "@k8slens/route": "^1.0.0", "@k8slens/routing": "^1.0.0-alpha.5", "@k8slens/run-many": "^1.0.0-alpha.1", "@k8slens/startable-stoppable": "^1.0.0-alpha.1", - "@k8slens/table-tokens": "^6.5.0-alpha.7", "@k8slens/tooltip": "^1.0.0-alpha.5", "@k8slens/utilities": "^1.0.0-alpha.1", "@kubernetes/client-node": "^0.18.1", @@ -35312,6 +35313,7 @@ "packages/table": { "name": "@k8slens/table-tokens", "version": "6.5.0", + "extraneous": true, "license": "MIT", "devDependencies": { "@k8slens/webpack": "^6.5.0", @@ -35682,6 +35684,21 @@ "@testing-library/react": "^12.1.5" } }, + "packages/utility-features/route": { + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@k8slens/webpack": "^6.5.0-alpha.9" + }, + "peerDependencies": { + "@k8slens/test-utils": "^1.0.0-alpha.3", + "@k8slens/utilities": "^1.0.0-alpha.1", + "@ogre-tools/fp": "^16.1.0", + "@ogre-tools/injectable": "^16.1.0", + "http-proxy": "^1.18.1", + "joi": "^17.9.1" + } + }, "packages/utility-features/run-many": { "name": "@k8slens/run-many", "version": "1.0.0", diff --git a/packages/core/package.json b/packages/core/package.json index 6913a30882..120642a2b5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -227,6 +227,7 @@ "@k8slens/react-application": "^1.0.0-alpha.5", "@k8slens/resizing-anchor": "^1.0.0-alpha.5", "@k8slens/resource-templates": "^1.0.0-alpha.1", + "@k8slens/route": "^1.0.0", "@k8slens/routing": "^1.0.0-alpha.5", "@k8slens/run-many": "^1.0.0-alpha.1", "@k8slens/startable-stoppable": "^1.0.0-alpha.1", diff --git a/packages/core/src/main/__test__/static-file-route.test.ts b/packages/core/src/main/__test__/static-file-route.test.ts index 0186cbea02..b66bc46cd4 100644 --- a/packages/core/src/main/__test__/static-file-route.test.ts +++ b/packages/core/src/main/__test__/static-file-route.test.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { LensApiRequest, Route } from "../router/route"; +import type { LensApiRequest, Route } from "@k8slens/route"; import staticFileRouteInjectable from "../routes/files/static-file-route.injectable"; import { getDiForUnitTesting } from "../getDiForUnitTesting"; diff --git a/packages/core/src/main/router/cluster-route.ts b/packages/core/src/main/router/cluster-route.ts new file mode 100644 index 0000000000..d4d6b37e3d --- /dev/null +++ b/packages/core/src/main/router/cluster-route.ts @@ -0,0 +1,71 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { Cluster } from "../../common/cluster/cluster"; +import type { BaseRoutePaths, LensApiRequest, RouteResponse, ValidatorBaseRoutePaths } from "@k8slens/route"; + +export interface ClusterLensApiRequest extends LensApiRequest { + cluster: Cluster; +} + +export interface ClusterRoute extends BaseRoutePaths { + handler: ClusterRouteHandler; +} + +export interface ClusterRouteHandler{ + (request: ClusterLensApiRequest): RouteResponse | Promise>; +} + +export interface BindClusterHandler { + (handler: ClusterRouteHandler): ClusterRoute; +} + +export function clusterRoute(parts: BaseRoutePaths): BindClusterHandler { + return (handler) => ({ + ...parts, + handler: ({ cluster, ...rest }) => { + if (!cluster) { + return { + error: "Cluster missing", + statusCode: 400, + }; + } + + return handler({ cluster, ...rest }); + }, + }); +} + +export interface ValidatedClusterLensApiRequest extends ClusterLensApiRequest { + payload: Payload; +} + +export interface ValidatedClusterRouteHandler { + (request: ValidatedClusterLensApiRequest): RouteResponse | Promise>; +} + +export interface BindValidatedClusterHandler { + (handler: ValidatedClusterRouteHandler): ClusterRoute; +} + +export function payloadValidatedClusterRoute({ payloadValidator, ...parts }: ValidatorBaseRoutePaths): BindValidatedClusterHandler { + const boundClusterRoute = clusterRoute(parts); + + return (handler) => boundClusterRoute(({ payload, ...rest }) => { + const validationResult = payloadValidator.validate(payload); + + if (validationResult.error) { + return { + error: validationResult.error, + statusCode: 400, + }; + } + + return handler({ + payload: validationResult.value, + ...rest, + }); + }); +} diff --git a/packages/core/src/main/router/create-handler-for-route.injectable.ts b/packages/core/src/main/router/create-handler-for-route.injectable.ts index d01558cfe5..067efd064e 100644 --- a/packages/core/src/main/router/create-handler-for-route.injectable.ts +++ b/packages/core/src/main/router/create-handler-for-route.injectable.ts @@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import type { ServerResponse } from "http"; import { loggerInjectionToken } from "@k8slens/logger"; import { object } from "@k8slens/utilities"; -import type { LensApiRequest, Route } from "./route"; +import type { LensApiRequest, Route } from "@k8slens/route"; import { contentTypes } from "./router-content-types"; export type RouteHandler = (request: LensApiRequest, response: ServerResponse) => Promise; diff --git a/packages/core/src/main/router/router-content-types.ts b/packages/core/src/main/router/router-content-types.ts index 1bc00380b1..1e9803f1d3 100644 --- a/packages/core/src/main/router/router-content-types.ts +++ b/packages/core/src/main/router/router-content-types.ts @@ -2,15 +2,7 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { LensApiResult } from "./route"; - -export interface LensApiResultContentType { - resultMapper: (result: LensApiResult) => ({ - statusCode: number; - content: unknown; - headers: Record; - }); -} +import type { LensApiResult, LensApiResultContentType } from "@k8slens/route"; const resultMapperFor = (contentType: string): LensApiResultContentType["resultMapper"] => diff --git a/packages/core/src/main/router/router.injectable.ts b/packages/core/src/main/router/router.injectable.ts index 896f875332..d63f0e3cc1 100644 --- a/packages/core/src/main/router/router.injectable.ts +++ b/packages/core/src/main/router/router.injectable.ts @@ -3,15 +3,14 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { Injectable, InjectionToken } from "@ogre-tools/injectable"; -import { getInjectable, getInjectionToken } from "@ogre-tools/injectable"; +import { getInjectable } from "@ogre-tools/injectable"; +import { routeInjectionToken } from "@k8slens/route"; +import type { Route } from "@k8slens/route"; import { Router } from "./router"; import parseRequestInjectable from "./parse-request.injectable"; -import type { Route } from "./route"; import createHandlerForRouteInjectable from "./create-handler-for-route.injectable"; +import type { ClusterRoute } from "./cluster-route"; -export const routeInjectionToken = getInjectionToken>({ - id: "route-injection-token", -}); export function getRouteInjectable( opts: Omit, Route, void>, "lifecycle" | "injectionToken">, @@ -22,6 +21,15 @@ export function getRouteInjectable( }); } +export function getClusterRouteInjectable( + opts: Omit, ClusterRoute, void>, "lifecycle" | "injectionToken">, +) { + return getInjectable({ + ...opts, + injectionToken: routeInjectionToken as unknown as InjectionToken, void>, + }); +} + const routerInjectable = getInjectable({ id: "router", diff --git a/packages/core/src/main/router/router.test.ts b/packages/core/src/main/router/router.test.ts index 4f3aee844e..bbec4c52f8 100644 --- a/packages/core/src/main/router/router.test.ts +++ b/packages/core/src/main/router/router.test.ts @@ -3,7 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import routerInjectable, { routeInjectionToken } from "./router.injectable"; +import routerInjectable from "./router.injectable"; +import { routeInjectionToken } from "@k8slens/route"; import { getDiForUnitTesting } from "../getDiForUnitTesting"; import type { Router } from "./router"; import type { Cluster } from "../../common/cluster/cluster"; @@ -14,7 +15,7 @@ import asyncFn from "@async-fn/jest"; import parseRequestInjectable from "./parse-request.injectable"; import { contentTypes } from "./router-content-types"; import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; -import type { Route } from "./route"; +import type { Route } from "@k8slens/route"; import type { SetRequired } from "type-fest"; import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable"; import kubectlBinaryNameInjectable from "../kubectl/binary-name.injectable"; diff --git a/packages/core/src/main/router/router.ts b/packages/core/src/main/router/router.ts index 9cb070ed1d..7ef9521b4e 100644 --- a/packages/core/src/main/router/router.ts +++ b/packages/core/src/main/router/router.ts @@ -6,10 +6,11 @@ import Call from "@hapi/call"; import type http from "http"; import type { Cluster } from "../../common/cluster/cluster"; -import type { LensApiRequest, Route } from "./route"; +import type { LensApiRequest, Route } from "@k8slens/route"; import type { ServerIncomingMessage } from "../lens-proxy/lens-proxy"; import type { ParseRequest } from "./parse-request.injectable"; import type { CreateHandlerForRoute, RouteHandler } from "./create-handler-for-route.injectable"; +import type { ClusterLensApiRequest } from "./cluster-route"; export interface RouterRequestOpts { req: http.IncomingMessage; @@ -51,7 +52,7 @@ export class Router { return true; } - protected async getRequest(opts: RouterRequestOpts): Promise> { + protected async getRequest(opts: RouterRequestOpts): Promise | ClusterLensApiRequest> { const { req, res, url, cluster, params } = opts; const { payload } = await this.dependencies.parseRequest(req, null, { parse: true, diff --git a/packages/core/src/main/routes/files/development.injectable.ts b/packages/core/src/main/routes/files/development.injectable.ts index 98c95c7928..8a69ddab66 100644 --- a/packages/core/src/main/routes/files/development.injectable.ts +++ b/packages/core/src/main/routes/files/development.injectable.ts @@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import httpProxy from "http-proxy"; import path from "path"; import { webpackDevServerPort } from "../../../../webpack/vars"; -import type { LensApiRequest, RouteResponse } from "../../router/route"; +import type { LensApiRequest, RouteResponse } from "@k8slens/route"; const devStaticFileRouteHandlerInjectable = getInjectable({ id: "dev-static-file-route-handler", diff --git a/packages/core/src/main/routes/files/production.injectable.ts b/packages/core/src/main/routes/files/production.injectable.ts index 408f3e98ea..5a0b8866a4 100644 --- a/packages/core/src/main/routes/files/production.injectable.ts +++ b/packages/core/src/main/routes/files/production.injectable.ts @@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import readFileBufferInjectable from "../../../common/fs/read-file-buffer.injectable"; import joinPathsInjectable from "../../../common/path/join-paths.injectable"; import staticFilesDirectoryInjectable from "../../../common/vars/static-files-directory.injectable"; -import type { LensApiRequest } from "../../router/route"; +import type { LensApiRequest } from "@k8slens/route"; import path from "path"; import { contentTypes } from "../../router/router-content-types"; import { prefixedLoggerInjectable } from "@k8slens/logger"; diff --git a/packages/core/src/main/routes/files/static-file-route.injectable.ts b/packages/core/src/main/routes/files/static-file-route.injectable.ts index 0268ac2051..9fda770dc7 100644 --- a/packages/core/src/main/routes/files/static-file-route.injectable.ts +++ b/packages/core/src/main/routes/files/static-file-route.injectable.ts @@ -4,7 +4,7 @@ */ import { getRouteInjectable } from "../../router/router.injectable"; import isDevelopmentInjectable from "../../../common/vars/is-development.injectable"; -import { route } from "../../router/route"; +import { route } from "@k8slens/route"; import prodStaticFileRouteHandlerInjectable from "./production.injectable"; import devStaticFileRouteHandlerInjectable from "./development.injectable"; diff --git a/packages/core/src/main/routes/helm/charts/get-readme-route.injectable.ts b/packages/core/src/main/routes/helm/charts/get-readme-route.injectable.ts index f3b52073c2..2b44ba2045 100644 --- a/packages/core/src/main/routes/helm/charts/get-readme-route.injectable.ts +++ b/packages/core/src/main/routes/helm/charts/get-readme-route.injectable.ts @@ -4,7 +4,7 @@ */ import { getRouteInjectable } from "../../../router/router.injectable"; import { apiPrefix } from "../../../../common/vars"; -import { route } from "../../../router/route"; +import { route } from "@k8slens/route"; import getHelmChartReadmeInjectable from "../../../helm/helm-service/get-helm-chart-readme.injectable"; const getHelmChartReadmeRouteInjectable = getRouteInjectable({ diff --git a/packages/core/src/main/routes/helm/charts/get-values-route.injectable.ts b/packages/core/src/main/routes/helm/charts/get-values-route.injectable.ts index 49efe5fb0c..72d864d8c9 100644 --- a/packages/core/src/main/routes/helm/charts/get-values-route.injectable.ts +++ b/packages/core/src/main/routes/helm/charts/get-values-route.injectable.ts @@ -4,7 +4,7 @@ */ import { getRouteInjectable } from "../../../router/router.injectable"; import { apiPrefix } from "../../../../common/vars"; -import { route } from "../../../router/route"; +import { route } from "@k8slens/route"; import getHelmChartValuesInjectable from "../../../helm/helm-service/get-helm-chart-values.injectable"; const getHelmChartRouteValuesInjectable = getRouteInjectable({ diff --git a/packages/core/src/main/routes/helm/charts/get-versions-route.injectable.ts b/packages/core/src/main/routes/helm/charts/get-versions-route.injectable.ts index 933d94743b..f8f9f3311d 100644 --- a/packages/core/src/main/routes/helm/charts/get-versions-route.injectable.ts +++ b/packages/core/src/main/routes/helm/charts/get-versions-route.injectable.ts @@ -4,7 +4,7 @@ */ import { getRouteInjectable } from "../../../router/router.injectable"; import { apiPrefix } from "../../../../common/vars"; -import { route } from "../../../router/route"; +import { route } from "@k8slens/route"; import getHelmChartVersionsInjectable from "../../../helm/helm-service/get-helm-chart-versions.injectable"; const getHelmChartVersionsRouteInjectable = getRouteInjectable({ diff --git a/packages/core/src/main/routes/helm/charts/list-route.injectable.ts b/packages/core/src/main/routes/helm/charts/list-route.injectable.ts index 402a3d7cd1..14f6a67c86 100644 --- a/packages/core/src/main/routes/helm/charts/list-route.injectable.ts +++ b/packages/core/src/main/routes/helm/charts/list-route.injectable.ts @@ -4,7 +4,7 @@ */ import { getRouteInjectable } from "../../../router/router.injectable"; import { apiPrefix } from "../../../../common/vars"; -import { route } from "../../../router/route"; +import { route } from "@k8slens/route"; import listHelmChartsInjectable from "../../../helm/helm-service/list-helm-charts.injectable"; const listHelmChartsRouteInjectable = getRouteInjectable({ diff --git a/packages/core/src/main/routes/helm/releases/delete-release-route.injectable.ts b/packages/core/src/main/routes/helm/releases/delete-release-route.injectable.ts index 79d3195643..6e630015b5 100644 --- a/packages/core/src/main/routes/helm/releases/delete-release-route.injectable.ts +++ b/packages/core/src/main/routes/helm/releases/delete-release-route.injectable.ts @@ -3,11 +3,11 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { apiPrefix } from "../../../../common/vars"; -import { getRouteInjectable } from "../../../router/router.injectable"; -import { clusterRoute } from "../../../router/route"; +import { getClusterRouteInjectable } from "../../../router/router.injectable"; +import { clusterRoute } from "../../../router/cluster-route"; import deleteClusterHelmReleaseInjectable from "../../../helm/helm-service/delete-helm-release.injectable"; -const deleteReleaseRouteInjectable = getRouteInjectable({ +const deleteReleaseRouteInjectable = getClusterRouteInjectable({ id: "delete-release-route", instantiate: (di) => { diff --git a/packages/core/src/main/routes/helm/releases/get-release-history-route.injectable.ts b/packages/core/src/main/routes/helm/releases/get-release-history-route.injectable.ts index 2ba1349de0..e88b6b4b1e 100644 --- a/packages/core/src/main/routes/helm/releases/get-release-history-route.injectable.ts +++ b/packages/core/src/main/routes/helm/releases/get-release-history-route.injectable.ts @@ -3,11 +3,11 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { apiPrefix } from "../../../../common/vars"; -import { getRouteInjectable } from "../../../router/router.injectable"; -import { clusterRoute } from "../../../router/route"; +import { getClusterRouteInjectable } from "../../../router/router.injectable"; +import { clusterRoute } from "../../../router/cluster-route"; import getClusterHelmReleaseHistoryInjectable from "../../../helm/helm-service/get-helm-release-history.injectable"; -const getReleaseRouteHistoryInjectable = getRouteInjectable({ +const getReleaseRouteHistoryInjectable = getClusterRouteInjectable({ id: "get-release-history-route", instantiate: (di) => { diff --git a/packages/core/src/main/routes/helm/releases/get-release-values-route.injectable.ts b/packages/core/src/main/routes/helm/releases/get-release-values-route.injectable.ts index 78799f3e58..77fe2fd2e1 100644 --- a/packages/core/src/main/routes/helm/releases/get-release-values-route.injectable.ts +++ b/packages/core/src/main/routes/helm/releases/get-release-values-route.injectable.ts @@ -3,13 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { apiPrefix } from "../../../../common/vars"; -import { getRouteInjectable } from "../../../router/router.injectable"; +import { getClusterRouteInjectable } from "../../../router/router.injectable"; import { getBoolean } from "../../../utils/parse-query"; import { contentTypes } from "../../../router/router-content-types"; -import { clusterRoute } from "../../../router/route"; +import { clusterRoute } from "../../../router/cluster-route"; import getClusterHelmReleaseValuesInjectable from "../../../helm/helm-service/get-helm-release-values.injectable"; -const getReleaseRouteValuesInjectable = getRouteInjectable({ +const getReleaseRouteValuesInjectable = getClusterRouteInjectable({ id: "get-release-values-route", instantiate: (di) => { diff --git a/packages/core/src/main/routes/helm/releases/install-chart-route.injectable.ts b/packages/core/src/main/routes/helm/releases/install-chart-route.injectable.ts index e34d54db23..2bd10ced11 100644 --- a/packages/core/src/main/routes/helm/releases/install-chart-route.injectable.ts +++ b/packages/core/src/main/routes/helm/releases/install-chart-route.injectable.ts @@ -3,9 +3,9 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { apiPrefix } from "../../../../common/vars"; -import { getRouteInjectable } from "../../../router/router.injectable"; +import { getClusterRouteInjectable } from "../../../router/router.injectable"; import Joi from "joi"; -import { payloadValidatedClusterRoute } from "../../../router/route"; +import { payloadValidatedClusterRoute } from "../../../router/cluster-route"; import type { InstallChartArgs } from "../../../helm/helm-service/install-helm-chart.injectable"; import installClusterHelmChartInjectable from "../../../helm/helm-service/install-helm-chart.injectable"; @@ -27,7 +27,7 @@ const installChartArgsValidator = Joi.object { diff --git a/packages/core/src/main/routes/helm/releases/rollback-release-route.injectable.ts b/packages/core/src/main/routes/helm/releases/rollback-release-route.injectable.ts index 49a8fddb88..e8af3cf02b 100644 --- a/packages/core/src/main/routes/helm/releases/rollback-release-route.injectable.ts +++ b/packages/core/src/main/routes/helm/releases/rollback-release-route.injectable.ts @@ -3,9 +3,9 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { apiPrefix } from "../../../../common/vars"; -import { getRouteInjectable } from "../../../router/router.injectable"; +import { getClusterRouteInjectable } from "../../../router/router.injectable"; import Joi from "joi"; -import { payloadValidatedClusterRoute } from "../../../router/route"; +import { payloadValidatedClusterRoute } from "../../../router/cluster-route"; import rollbackClusterHelmReleaseInjectable from "../../../helm/helm-service/rollback-helm-release.injectable"; interface RollbackReleasePayload { @@ -18,7 +18,7 @@ const rollbackReleasePayloadValidator = Joi.object { diff --git a/packages/core/src/main/routes/helm/releases/update-release-route.injectable.ts b/packages/core/src/main/routes/helm/releases/update-release-route.injectable.ts index 5993d7922d..f611168451 100644 --- a/packages/core/src/main/routes/helm/releases/update-release-route.injectable.ts +++ b/packages/core/src/main/routes/helm/releases/update-release-route.injectable.ts @@ -3,8 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { apiPrefix } from "../../../../common/vars"; -import { getRouteInjectable } from "../../../router/router.injectable"; -import { payloadValidatedClusterRoute } from "../../../router/route"; +import { getClusterRouteInjectable } from "../../../router/router.injectable"; +import { payloadValidatedClusterRoute } from "../../../router/cluster-route"; import Joi from "joi"; import type { UpdateChartArgs } from "../../../helm/helm-service/update-helm-release.injectable"; import updateHelmReleaseInjectable from "../../../helm/helm-service/update-helm-release.injectable"; @@ -21,7 +21,7 @@ const updateChartArgsValidator = Joi.object { diff --git a/packages/core/src/main/routes/kubeconfig-route/get-service-account-route.injectable.ts b/packages/core/src/main/routes/kubeconfig-route/get-service-account-route.injectable.ts index 267a3eafe7..14b89eafbd 100644 --- a/packages/core/src/main/routes/kubeconfig-route/get-service-account-route.injectable.ts +++ b/packages/core/src/main/routes/kubeconfig-route/get-service-account-route.injectable.ts @@ -4,14 +4,14 @@ */ import { apiPrefix } from "../../../common/vars"; -import { getRouteInjectable } from "../../router/router.injectable"; +import { getClusterRouteInjectable } from "../../router/router.injectable"; import { CoreV1Api } from "@kubernetes/client-node"; -import { clusterRoute } from "../../router/route"; +import { clusterRoute } from "../../router/cluster-route"; import * as yaml from "js-yaml"; import loadProxyKubeconfigInjectable from "../../cluster/load-proxy-kubeconfig.injectable"; import clusterApiUrlInjectable from "../../../features/cluster/connections/main/api-url.injectable"; -const getServiceAccountRouteInjectable = getRouteInjectable({ +const getServiceAccountRouteInjectable = getClusterRouteInjectable({ id: "get-service-account-route", instantiate: (di) => clusterRoute({ diff --git a/packages/core/src/main/routes/metrics/add-metrics-route.injectable.ts b/packages/core/src/main/routes/metrics/add-metrics-route.injectable.ts index bc0071431b..39fd8eb2ea 100644 --- a/packages/core/src/main/routes/metrics/add-metrics-route.injectable.ts +++ b/packages/core/src/main/routes/metrics/add-metrics-route.injectable.ts @@ -4,11 +4,11 @@ */ import { apiPrefix } from "../../../common/vars"; -import { getRouteInjectable } from "../../router/router.injectable"; +import { getClusterRouteInjectable } from "../../router/router.injectable"; import type { ClusterPrometheusMetadata } from "../../../common/cluster-types"; import { ClusterMetadataKey } from "../../../common/cluster-types"; import type { Cluster } from "../../../common/cluster/cluster"; -import { clusterRoute } from "../../router/route"; +import { clusterRoute } from "../../router/cluster-route"; import { isObject } from "lodash"; import { isRequestError, object } from "@k8slens/utilities"; import type { GetMetrics } from "../../get-metrics.injectable"; @@ -54,7 +54,7 @@ const loadMetricsFor = (getMetrics: GetMetrics) => async (promQueries: string[], return Promise.all(queries.map(loadMetric)); }; -const addMetricsRouteInjectable = getRouteInjectable({ +const addMetricsRouteInjectable = getClusterRouteInjectable({ id: "add-metrics-route", instantiate: (di) => { diff --git a/packages/core/src/main/routes/metrics/get-metric-providers-route.injectable.ts b/packages/core/src/main/routes/metrics/get-metric-providers-route.injectable.ts index 54dfd9bb95..baf4835f91 100644 --- a/packages/core/src/main/routes/metrics/get-metric-providers-route.injectable.ts +++ b/packages/core/src/main/routes/metrics/get-metric-providers-route.injectable.ts @@ -5,7 +5,7 @@ import { apiPrefix } from "../../../common/vars"; import { getRouteInjectable } from "../../router/router.injectable"; -import { route } from "../../router/route"; +import { route } from "@k8slens/route"; import prometheusProvidersInjectable from "../../prometheus/providers.injectable"; const getMetricProvidersRouteInjectable = getRouteInjectable({ diff --git a/packages/core/src/main/routes/port-forward/get-current-port-forward-route.injectable.ts b/packages/core/src/main/routes/port-forward/get-current-port-forward-route.injectable.ts index 769046c804..b9af90741a 100644 --- a/packages/core/src/main/routes/port-forward/get-current-port-forward-route.injectable.ts +++ b/packages/core/src/main/routes/port-forward/get-current-port-forward-route.injectable.ts @@ -2,12 +2,12 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getRouteInjectable } from "../../router/router.injectable"; +import { getClusterRouteInjectable } from "../../router/router.injectable"; import { apiPrefix } from "../../../common/vars"; import { PortForward } from "./functionality/port-forward"; -import { clusterRoute } from "../../router/route"; +import { clusterRoute } from "../../router/cluster-route"; -const getCurrentPortForwardRouteInjectable = getRouteInjectable({ +const getCurrentPortForwardRouteInjectable = getClusterRouteInjectable({ id: "get-current-port-forward-route", instantiate: () => clusterRoute({ diff --git a/packages/core/src/main/routes/port-forward/start-port-forward-route.injectable.ts b/packages/core/src/main/routes/port-forward/start-port-forward-route.injectable.ts index ad924cbe72..4ae7041319 100644 --- a/packages/core/src/main/routes/port-forward/start-port-forward-route.injectable.ts +++ b/packages/core/src/main/routes/port-forward/start-port-forward-route.injectable.ts @@ -2,15 +2,15 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getRouteInjectable } from "../../router/router.injectable"; +import { getClusterRouteInjectable } from "../../router/router.injectable"; import { apiPrefix } from "../../../common/vars"; import { PortForward } from "./functionality/port-forward"; import createPortForwardInjectable from "./functionality/create-port-forward.injectable"; -import { clusterRoute } from "../../router/route"; +import { clusterRoute } from "../../router/cluster-route"; import { loggerInjectionToken } from "@k8slens/logger"; import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable"; -const startPortForwardRouteInjectable = getRouteInjectable({ +const startPortForwardRouteInjectable = getClusterRouteInjectable({ id: "start-current-port-forward-route", instantiate: (di) => { diff --git a/packages/core/src/main/routes/port-forward/stop-current-port-forward-route.injectable.ts b/packages/core/src/main/routes/port-forward/stop-current-port-forward-route.injectable.ts index 372dc34aac..519d2bdeda 100644 --- a/packages/core/src/main/routes/port-forward/stop-current-port-forward-route.injectable.ts +++ b/packages/core/src/main/routes/port-forward/stop-current-port-forward-route.injectable.ts @@ -2,13 +2,13 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getRouteInjectable } from "../../router/router.injectable"; +import { getClusterRouteInjectable } from "../../router/router.injectable"; import { apiPrefix } from "../../../common/vars"; import { PortForward } from "./functionality/port-forward"; -import { clusterRoute } from "../../router/route"; +import { clusterRoute } from "../../router/cluster-route"; import { loggerInjectionToken } from "@k8slens/logger"; -const stopCurrentPortForwardRouteInjectable = getRouteInjectable({ +const stopCurrentPortForwardRouteInjectable = getClusterRouteInjectable({ id: "stop-current-port-forward-route", instantiate: (di) => { diff --git a/packages/core/src/main/routes/resource-applier/create-resource-route.injectable.ts b/packages/core/src/main/routes/resource-applier/create-resource-route.injectable.ts index a2d8766170..1652a7e089 100644 --- a/packages/core/src/main/routes/resource-applier/create-resource-route.injectable.ts +++ b/packages/core/src/main/routes/resource-applier/create-resource-route.injectable.ts @@ -2,13 +2,13 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getRouteInjectable } from "../../router/router.injectable"; +import { getClusterRouteInjectable } from "../../router/router.injectable"; import { apiPrefix } from "../../../common/vars"; -import { payloadValidatedClusterRoute } from "../../router/route"; +import { payloadValidatedClusterRoute } from "../../router/cluster-route"; import Joi from "joi"; import resourceApplierInjectable from "../../resource-applier/create-resource-applier.injectable"; -const createResourceRouteInjectable = getRouteInjectable({ +const createResourceRouteInjectable = getClusterRouteInjectable({ id: "create-resource-route", instantiate: (di) => payloadValidatedClusterRoute({ diff --git a/packages/core/src/main/routes/resource-applier/patch-resource-route.injectable.ts b/packages/core/src/main/routes/resource-applier/patch-resource-route.injectable.ts index 6cac0436f5..9ea28ccd32 100644 --- a/packages/core/src/main/routes/resource-applier/patch-resource-route.injectable.ts +++ b/packages/core/src/main/routes/resource-applier/patch-resource-route.injectable.ts @@ -2,9 +2,9 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getRouteInjectable } from "../../router/router.injectable"; +import { getClusterRouteInjectable } from "../../router/router.injectable"; import { apiPrefix } from "../../../common/vars"; -import { payloadValidatedClusterRoute } from "../../router/route"; +import { payloadValidatedClusterRoute } from "../../router/cluster-route"; import Joi from "joi"; import type { Patch } from "rfc6902"; import resourceApplierInjectable from "../../resource-applier/create-resource-applier.injectable"; @@ -37,7 +37,7 @@ const patchResourcePayloadValidator = Joi.object payloadValidatedClusterRoute({ diff --git a/packages/core/src/main/routes/versions/get-version-route.injectable.ts b/packages/core/src/main/routes/versions/get-version-route.injectable.ts index 54f5c4df2a..7451e82714 100644 --- a/packages/core/src/main/routes/versions/get-version-route.injectable.ts +++ b/packages/core/src/main/routes/versions/get-version-route.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getRouteInjectable } from "../../router/router.injectable"; -import { route } from "../../router/route"; +import { route } from "@k8slens/route"; import { buildVersionInitializable } from "../../../features/vars/build-version/common/token"; const getVersionRouteInjectable = getRouteInjectable({ diff --git a/packages/utility-features/route/CHANGELOG.md b/packages/utility-features/route/CHANGELOG.md new file mode 100644 index 0000000000..e4d87c4d45 --- /dev/null +++ b/packages/utility-features/route/CHANGELOG.md @@ -0,0 +1,4 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. diff --git a/packages/utility-features/route/index.ts b/packages/utility-features/route/index.ts new file mode 100644 index 0000000000..12d0dc8b2b --- /dev/null +++ b/packages/utility-features/route/index.ts @@ -0,0 +1,7 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +export * from "./src/route"; +export { routeInjectionToken } from "./src/route-injection-token"; diff --git a/packages/utility-features/route/jest.config.js b/packages/utility-features/route/jest.config.js new file mode 100644 index 0000000000..05dbeacf60 --- /dev/null +++ b/packages/utility-features/route/jest.config.js @@ -0,0 +1,3 @@ +const config = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForReact; + +module.exports = { ...config, coverageThreshold: undefined }; diff --git a/packages/utility-features/route/package.json b/packages/utility-features/route/package.json new file mode 100644 index 0000000000..88eb9f49fa --- /dev/null +++ b/packages/utility-features/route/package.json @@ -0,0 +1,38 @@ +{ + "name": "@k8slens/route", + "version": "1.0.0", + "type": "commonjs", + "description": "Route for Lens", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "private": false, + "files": [ + "dist" + ], + "main": "dist/index.js", + "types": "dist/index.d.ts", + "author": { + "name": "OpenLens Authors", + "email": "info@k8slens.dev" + }, + "license": "MIT", + "homepage": "https://github.com/lensapp/lens", + "scripts": { + "clean": "rimraf dist/", + "build": "lens-webpack-build", + "test:unit": "jest --coverage --runInBand" + }, + "peerDependencies": { + "@k8slens/test-utils": "^1.0.0-alpha.3", + "@k8slens/utilities": "^1.0.0-alpha.1", + "@ogre-tools/fp": "^16.1.0", + "@ogre-tools/injectable": "^16.1.0", + "http-proxy": "^1.18.1", + "joi": "^17.9.1" + }, + "devDependencies": { + "@k8slens/webpack": "^6.5.0-alpha.9" + } +} diff --git a/packages/utility-features/route/src/route-injection-token.ts b/packages/utility-features/route/src/route-injection-token.ts new file mode 100644 index 0000000000..2c22926dc3 --- /dev/null +++ b/packages/utility-features/route/src/route-injection-token.ts @@ -0,0 +1,11 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getInjectionToken } from "@ogre-tools/injectable"; +import type { Route } from "./route"; + +export const routeInjectionToken = getInjectionToken>({ + id: "route-injection-token", +}); diff --git a/packages/core/src/main/router/route.ts b/packages/utility-features/route/src/route.ts similarity index 52% rename from packages/core/src/main/router/route.ts rename to packages/utility-features/route/src/route.ts index 90b0210746..31ea7eeb5c 100644 --- a/packages/core/src/main/router/route.ts +++ b/packages/utility-features/route/src/route.ts @@ -3,13 +3,19 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { Cluster } from "../../common/cluster/cluster"; import type http from "http"; import type httpProxy from "http-proxy"; -import type { LensApiResultContentType } from "./router-content-types"; import type { URLSearchParams } from "url"; import type Joi from "joi"; +export interface LensApiResultContentType { + resultMapper: (result: LensApiResult) => ({ + statusCode: number; + content: unknown; + headers: Record; + }); +} + export type InferParam< T extends string, PathParams extends Record, @@ -33,7 +39,6 @@ export interface LensApiRequest { path: Path; payload: unknown; params: InferParamFromPath; - cluster: Cluster | undefined; query: URLSearchParams; raw: { req: http.IncomingMessage; @@ -41,10 +46,6 @@ export interface LensApiRequest { }; } -export interface ClusterLensApiRequest extends LensApiRequest { - cluster: Cluster; -} - export interface LensApiResult { statusCode?: number; response?: Response; @@ -79,6 +80,7 @@ export interface Route extends BaseRoutePaths; } + export interface BindHandler { (handler: RouteHandler): Route; } @@ -89,59 +91,3 @@ export function route(parts: BaseRoutePaths): BindHan handler, }); } - -export interface ClusterRouteHandler{ - (request: ClusterLensApiRequest): RouteResponse | Promise>; -} - -export interface BindClusterHandler { - (handler: ClusterRouteHandler): Route; -} - -export function clusterRoute(parts: BaseRoutePaths): BindClusterHandler { - return (handler) => ({ - ...parts, - handler: ({ cluster, ...rest }) => { - if (!cluster) { - return { - error: "Cluster missing", - statusCode: 400, - }; - } - - return handler({ cluster, ...rest }); - }, - }); -} - -export interface ValidatedClusterLensApiRequest extends ClusterLensApiRequest { - payload: Payload; -} - -export interface ValidatedClusterRouteHandler { - (request: ValidatedClusterLensApiRequest): RouteResponse | Promise>; -} - -export interface BindValidatedClusterHandler { - (handler: ValidatedClusterRouteHandler): Route; -} - -export function payloadValidatedClusterRoute({ payloadValidator, ...parts }: ValidatorBaseRoutePaths): BindValidatedClusterHandler { - const boundClusterRoute = clusterRoute(parts); - - return (handler) => boundClusterRoute(({ payload, ...rest }) => { - const validationResult = payloadValidator.validate(payload); - - if (validationResult.error) { - return { - error: validationResult.error, - statusCode: 400, - }; - } - - return handler({ - payload: validationResult.value, - ...rest, - }); - }); -} diff --git a/packages/utility-features/route/tsconfig.json b/packages/utility-features/route/tsconfig.json new file mode 100644 index 0000000000..a4f6fa613e --- /dev/null +++ b/packages/utility-features/route/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@k8slens/typescript/config/base.json" +} diff --git a/packages/utility-features/route/webpack.config.js b/packages/utility-features/route/webpack.config.js new file mode 100644 index 0000000000..3183f30179 --- /dev/null +++ b/packages/utility-features/route/webpack.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/webpack").configForNode;