///
import { IncomingHttpHeaders } from 'http';
import { ClientDuplexStream, ClientReadableStream, ClientWritableStream, type ServiceError } from '@grpc/grpc-js';
import { HandlerType } from '@grpc/grpc-js/build/src/server-call';
import { AxiosInterceptorManager, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { IAxiosRetryConfig } from 'axios-retry';
import type { Request, Response } from 'express';
import * as protobufjs from 'protobufjs';
import type { GrpcContext } from '../components/grpc';
import { Lang } from '../constants';
import { GatewayContext } from './context';
import { AppErrorConstructor } from './error';
export interface GatewayRequest extends Request {
id: string;
ctx: Context;
}
export interface GatewayResponse extends Response {
}
export interface Headers {
[key: string]: any;
}
export interface EndpointsConfig {
[key: string]: ActionEndpoint;
}
export type AuthHeadersFunc = (serviceName: string) => Record | undefined;
export interface ApiActionConfig {
requestId: string;
headers: Headers;
args: TRequestData;
ctx: Context;
timeout?: number;
retries?: number;
callback?: (response: TResponseData) => void;
authArgs?: Record;
userId?: string;
abortSignal?: AbortSignal;
}
export interface GRPCActionData {
[key: string]: unknown;
}
export type SendStats = (stats: Stats, headers: IncomingHttpHeaders, ctx: Context, meta: {
debugHeaders: Headers;
}) => void;
export interface Stats {
service: string;
action: string;
restStatus: number;
grpcStatus?: number;
responseSize: number;
requestId: string;
requestTime: number;
requestMethod: string;
requestUrl: string;
timestamp: number;
userId?: string;
traceId: string;
}
export type ControllerType = 'rest' | 'grpc';
export interface GatewayError {
status: number;
message: string;
code: string;
details?: {
title?: string;
description?: string;
} & Record;
debug?: any;
requestId?: string;
}
export type GrpcRetryCondition = (error: ServiceError) => boolean;
export type AxiosRetryCondition = IAxiosRetryConfig['retryCondition'];
export type ProxyHeadersFunctionExtra = {
service: string;
action: string;
protopath?: string;
protokey?: string;
};
export type ProxyHeadersFunction = (headers: IncomingHttpHeaders, type: ControllerType, extra: ProxyHeadersFunctionExtra) => IncomingHttpHeaders;
export type ProxyHeaders = string[] | ProxyHeadersFunction;
export type ProxyResponseHeadersFunction = (headers: Headers, type: ControllerType) => Headers;
export type ProxyResponseHeaders = string[] | ProxyResponseHeadersFunction;
export type GetAuthHeadersParams> = {
actionType: ControllerType;
serviceName: string;
requestHeaders: Headers;
authArgs: AuthArgs | undefined;
};
export type GetAuthHeaders> = (params: GetAuthHeadersParams) => Record | undefined;
export type ResponseContentType = AxiosResponse['headers']['Content-Type'];
export interface GatewayApiOptions {
serviceName: string;
timeout?: number;
grpcRetryCondition?: GrpcRetryCondition;
axiosRetryCondition?: AxiosRetryCondition;
sendStats?: SendStats;
grpcOptions?: object;
grpcRecreateService?: boolean;
axiosConfig?: AxiosRequestConfig;
axiosInterceptors?: AxiosInterceptorsConfig;
proxyHeaders?: ProxyHeaders;
proxyDebugHeaders?: ProxyHeaders;
validationSchema?: object;
encodePathArgs?: boolean;
expectedResponseContentType?: ResponseContentType | ResponseContentType[];
getAuthHeaders: GetAuthHeaders;
}
export interface ParamsOutput {
body?: any;
query?: {
[key: string]: any;
};
headers?: Headers;
}
export interface ResponseError extends AxiosResponse {
}
export interface ExtendedBaseActionEndpoint {
path: string;
}
export interface ExtendedGrpcActionEndpoint extends ExtendedBaseActionEndpoint {
insecure?: boolean;
secureWithoutRootCert?: boolean;
caCertificatePath?: string;
clientCertificatePath?: string;
clientKeyPath?: string;
grpcOptions?: object;
}
export interface ExtendedRestActionEndpoint extends ExtendedBaseActionEndpoint {
axiosConfig?: AxiosRequestConfig;
}
export type ExtendedActionEndpoint = ExtendedGrpcActionEndpoint | ExtendedRestActionEndpoint;
export type ActionEndpoint = string | ExtendedActionEndpoint;
export interface ApiServiceBaseActionConfig {
getAuthHeaders?: GetAuthHeaders;
params?: (args: TParams, headers: Headers, config: ApiParamsConfig) => Promise | ParamsOutput;
endpoint?: string | ((endpoints: EndpointsConfig | undefined, args: TParams) => string);
transformResponseData?: (data: TOutput, config: ApiTransformResponseDataConfig) => Promise | TTransformed;
transformResponseError?: (error: ResponseError, config: ApiTransformResponseErrorConfig) => Promise | GatewayError;
validationSchema?: object;
timeout?: number;
retries?: number;
idempotency?: boolean;
proxyHeaders?: ProxyHeaders;
proxyResponseHeaders?: ProxyResponseHeaders;
metadata?: Record;
abortOnClientDisconnect?: boolean;
}
export interface ApiServiceRestActionConfig extends ApiServiceBaseActionConfig {
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
path: (args: TParams) => string;
paramsSerializer?: AxiosRequestConfig['paramsSerializer'];
responseType?: AxiosRequestConfig['responseType'];
expectedResponseContentType?: ResponseContentType | ResponseContentType[];
maxRedirects?: number;
axiosRetryCondition?: AxiosRetryCondition;
}
export interface ApiServiceBaseGrpcActionConfig extends ApiServiceBaseActionConfig {
action: string;
protoKey: string;
insecure?: boolean;
secureWithoutRootCert?: boolean;
caCertificatePath?: string;
clientCertificatePath?: string;
clientKeyPath?: string;
encodedFields?: string[];
type?: HandlerType;
decodeAnyMessageProtoLoaderOptions?: protobufjs.IConversionOptions;
}
export interface ApiServiceFileGrpcActionConfig extends ApiServiceBaseGrpcActionConfig {
protoPath: string;
}
export declare enum GrpcReflection {
OnFirstRequest = 0,
OnEveryRequest = 1
}
export interface ApiServiceReflectGrpcActionConfig extends ApiServiceBaseGrpcActionConfig {
reflection: GrpcReflection;
reflectionRefreshSec?: number;
}
export type ApiServiceGrpcActionConfig = ApiServiceFileGrpcActionConfig | ApiServiceReflectGrpcActionConfig;
export interface ApiServiceMixedExtra, Res extends GatewayResponse> {
headers: Headers;
lang: Lang;
ctx: Context;
config: GatewayConfig;
grpcContext: GrpcContext;
abortSignal?: AbortSignal;
}
export type ApiServiceMixedActionConfig, Res extends GatewayResponse, TOutput, TParams = undefined, TTransformed = TOutput> = (api: unknown, args: TParams, extra: ApiServiceMixedExtra) => Promise;
export type ApiServiceActionConfig, Res extends GatewayResponse, TOutput, TParams = undefined, TTransformed = TOutput> = ApiServiceRestActionConfig | ApiServiceGrpcActionConfig | ApiServiceMixedActionConfig;
export type ApiActionResponseType = T extends ApiServiceActionConfig ? R : never;
export type ApiActionParams = T extends ApiServiceActionConfig ? R : never;
export interface ApiParamsConfig {
ctx: Context;
}
export interface ApiTransformResponseDataConfig {
args: TParams;
ctx: Context;
headers?: Headers;
}
export interface ApiTransformResponseErrorConfig {
args: TParams;
ctx: Context;
}
export interface BaseSchema {
[key: string]: {
actions: Record>;
serviceName?: string;
endpoints?: Record>;
getAuthHeaders?: GetAuthHeaders;
getAuthArgs?: (req: Request, res: Response) => Record | undefined;
};
}
export interface SchemasByScope {
[scope: string]: BaseSchema;
}
export type ApiByScope, Res extends GatewayResponse> = {
[scope in keyof R]: GatewayApi;
};
export type ApiWithRoot, Res extends GatewayResponse> = ApiByScope['root'] & ApiByScope;
export interface GatewayActionHeaders {
debugHeaders: Headers;
}
export interface GatewayActionUnaryResponse extends GatewayActionHeaders {
responseData: ApiActionResponseType;
responseHeaders?: Headers;
}
export interface GatewayActionClientStreamResponse extends GatewayActionHeaders {
stream: ClientWritableStream>;
}
export interface GatewayActionServerStreamResponse extends GatewayActionHeaders {
stream: ClientReadableStream>;
}
export interface GatewayActionDuplexStreamResponse extends GatewayActionHeaders {
stream: ClientDuplexStream, ApiActionResponseType>;
}
export type GatewayActionResponseData, Res extends GatewayResponse, TAction extends ApiServiceActionConfig> = TAction extends ApiServiceGrpcActionConfig ? TAction['type'] extends 'clientStream' ? GatewayActionClientStreamResponse : TAction['type'] extends 'serverStream' ? GatewayActionServerStreamResponse : TAction['type'] extends 'bidi' ? GatewayActionDuplexStreamResponse : GatewayActionUnaryResponse : GatewayActionUnaryResponse;
type GatewayAction, Res extends GatewayResponse, TAction extends ApiServiceActionConfig> = undefined extends ApiActionParams ? (params?: ApiActionConfig, ApiActionResponseType>) => Promise> : (params: ApiActionConfig, ApiActionResponseType>) => Promise>;
export type GatewayApi, Res extends GatewayResponse> = {
[S in keyof T]: {
[A in keyof T[S]['actions']]: GatewayAction;
};
};
type ContextAction = undefined extends ApiActionParams ? (params?: ApiActionParams) => Promise> : (params: ApiActionParams) => Promise>;
export type ContextApi = {
[S in keyof T]: {
[A in keyof T[S]['actions']]: ContextAction;
};
};
export type ContextApiByScope = {
[scope in keyof R]: ContextApi;
};
export type ContextApiWithRoot = ContextApiByScope['root'] & ContextApiByScope;
interface OnUnknownActionData {
service?: string;
action?: string;
}
type AxiosInterceptorUseParams = Parameters['use']>;
interface AxiosInterceptorConfig {
callback: AxiosInterceptorUseParams[0];
errorCallback?: AxiosInterceptorUseParams[1];
}
export interface AxiosInterceptorsConfig {
request?: AxiosInterceptorConfig>[];
response?: AxiosInterceptorConfig>[];
}
export interface GatewayConfig, Res extends GatewayResponse> {
installation?: string;
env?: string;
actions?: string[];
timeout?: number;
grpcRetryCondition?: GrpcRetryCondition;
axiosRetryCondition?: AxiosRetryCondition;
grpcOptions?: object;
grpcRecreateService?: boolean;
axiosConfig?: AxiosRequestConfig;
axiosInterceptors?: AxiosInterceptorsConfig;
onUnknownAction?: (req: Req, res: Res, data: OnUnknownActionData) => any;
onBeforeAction?: (req: Req, res: Res, scope: string, service: string, action: string, config?: ApiServiceActionConfig) => any;
onRequestSuccess?: (req: Req, res: Res, data: any) => any;
onRequestFailed?: (req: Req, res: Res, error: any) => any;
sendStats?: SendStats;
includeProtoRoots?: string[];
caCertificatePath: string | null;
clientCertificatePath?: string | null;
clientKeyPath?: string | null;
proxyHeaders: ProxyHeaders;
proxyDebugHeaders?: ProxyHeaders;
withDebugHeaders?: boolean | ((req: Req, res: Res) => boolean);
validationSchema?: object;
encodePathArgs?: boolean;
getAuthArgs: (req: Req, res: Res) => Record | undefined;
getAuthHeaders: GetAuthHeaders;
ErrorConstructor: AppErrorConstructor;
}
export {};