mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
- Fix some bugs about bad conditions Signed-off-by: Sebastian Malton <sebastian@malton.name>
154 lines
4.5 KiB
TypeScript
154 lines
4.5 KiB
TypeScript
/**
|
|
* 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 http from "http";
|
|
import type httpProxy from "http-proxy";
|
|
import type { LensApiResultContentType } from "./router-content-types";
|
|
import type { URLSearchParams } from "url";
|
|
import type { SafeParseReturnType } from "zod";
|
|
|
|
declare const emptyObjectSymbol: unique symbol;
|
|
|
|
export interface EmptyObject {[emptyObjectSymbol]?: never}
|
|
|
|
export type InferParam<
|
|
T extends string,
|
|
PathParams,
|
|
> =
|
|
T extends `{${infer P}?}`
|
|
? PathParams & Partial<Record<P, string>>
|
|
: T extends `{${infer P}}`
|
|
? PathParams & Record<P, string>
|
|
: PathParams;
|
|
|
|
export type InferParamFromPath<P extends string> =
|
|
P extends `${string}/{${infer B}*}${infer Tail}`
|
|
? Tail extends ""
|
|
? Record<B, string>
|
|
: never
|
|
: P extends `${infer A}/${infer B}`
|
|
? InferParam<A, InferParamFromPath<B>>
|
|
: InferParam<P, EmptyObject>;
|
|
|
|
export interface LensApiRequest<Path extends string> {
|
|
path: Path;
|
|
payload: unknown;
|
|
params: string extends Path
|
|
? Partial<Record<string, string>>
|
|
: InferParamFromPath<Path>;
|
|
cluster: Cluster | undefined;
|
|
query: URLSearchParams;
|
|
raw: {
|
|
req: http.IncomingMessage;
|
|
res: http.ServerResponse;
|
|
};
|
|
}
|
|
|
|
export interface ClusterLensApiRequest<Path extends string> extends LensApiRequest<Path> {
|
|
cluster: Cluster;
|
|
}
|
|
|
|
export interface LensApiResult<Response> {
|
|
statusCode?: number;
|
|
response?: Response;
|
|
error?: string | Error;
|
|
contentType?: LensApiResultContentType;
|
|
headers?: Partial<Record<string, string>>;
|
|
proxy?: httpProxy;
|
|
}
|
|
|
|
export type RouteResponse<Response> =
|
|
| LensApiResult<Response>
|
|
| void;
|
|
|
|
export interface RouteHandler<TResponse, Path extends string>{
|
|
(request: LensApiRequest<Path>): RouteResponse<TResponse> | Promise<RouteResponse<TResponse>>;
|
|
}
|
|
|
|
export interface BaseRoutePaths<Path extends string> {
|
|
path: Path;
|
|
method: "get" | "post" | "put" | "patch" | "delete";
|
|
}
|
|
|
|
export interface PayloadValidator<Payload> {
|
|
safeParse(payload: unknown): SafeParseReturnType<unknown, Payload>;
|
|
}
|
|
|
|
export interface ValidatorBaseRoutePaths<Path extends string, Payload> extends BaseRoutePaths<Path> {
|
|
payloadSchema: PayloadValidator<Payload>;
|
|
}
|
|
|
|
export interface Route<TResponse, Path extends string> extends BaseRoutePaths<Path> {
|
|
handler: RouteHandler<TResponse, Path>;
|
|
}
|
|
|
|
export interface BindHandler<Path extends string> {
|
|
<TResponse>(handler: RouteHandler<TResponse, Path>): Route<TResponse, Path>;
|
|
}
|
|
|
|
export function route<Path extends string>(parts: BaseRoutePaths<Path>): BindHandler<Path> {
|
|
return (handler) => ({
|
|
...parts,
|
|
handler,
|
|
});
|
|
}
|
|
|
|
export interface ClusterRouteHandler<Response, Path extends string>{
|
|
(request: ClusterLensApiRequest<Path>): RouteResponse<Response> | Promise<RouteResponse<Response>>;
|
|
}
|
|
|
|
export interface BindClusterHandler<Path extends string> {
|
|
<TResponse>(handler: ClusterRouteHandler<TResponse, Path>): Route<TResponse, Path>;
|
|
}
|
|
|
|
export function clusterRoute<Path extends string>(parts: BaseRoutePaths<Path>): BindClusterHandler<Path> {
|
|
return (handler) => ({
|
|
...parts,
|
|
handler: ({ cluster, ...rest }) => {
|
|
if (!cluster) {
|
|
return {
|
|
error: "Cluster missing",
|
|
statusCode: 400,
|
|
};
|
|
}
|
|
|
|
return handler({ cluster, ...rest });
|
|
},
|
|
});
|
|
}
|
|
|
|
export interface ValidatedClusterLensApiRequest<Path extends string, Payload> extends ClusterLensApiRequest<Path> {
|
|
payload: Payload;
|
|
}
|
|
|
|
export interface ValidatedClusterRouteHandler<Payload, Response, Path extends string> {
|
|
(request: ValidatedClusterLensApiRequest<Path, Payload>): RouteResponse<Response> | Promise<RouteResponse<Response>>;
|
|
}
|
|
|
|
export interface BindValidatedClusterHandler<Path extends string, Payload> {
|
|
<Response>(handler: ValidatedClusterRouteHandler<Payload, Response, Path>): Route<Response, Path>;
|
|
}
|
|
|
|
export function payloadWithSchemaClusterRoute<Path extends string, Payload>({ payloadSchema: payloadValidator, ...parts }: ValidatorBaseRoutePaths<Path, Payload>): BindValidatedClusterHandler<Path, Payload> {
|
|
const boundClusterRoute = clusterRoute(parts);
|
|
|
|
return (handler) => boundClusterRoute(({ payload, ...rest }) => {
|
|
const validationResult = payloadValidator.safeParse(payload);
|
|
|
|
if (!validationResult.success) {
|
|
return {
|
|
error: validationResult.error,
|
|
statusCode: 400,
|
|
};
|
|
}
|
|
|
|
return handler({
|
|
payload: validationResult.data,
|
|
...rest,
|
|
});
|
|
});
|
|
}
|