import type { Method, MethodOf, OperationParams, OperationResult, PathPattern, UrlParams } from '@rocket.chat/rest-typings'; import type { IUser } from '@rocket.chat/core-typings'; import type { ValidateFunction } from 'ajv'; import type { Request, Response } from 'express'; import type { ITwoFactorOptions } from '../../2fa/server/code'; import type { Logger } from '../../logger/server'; export type SuccessResult = { statusCode: 200; body: T extends object ? { success: true } & T : T; }; export type FailureResult = { statusCode: 400; body: T extends object ? { success: false } & T : { success: false; error?: T; stack?: TStack; errorType?: TErrorType; details?: TErrorDetails; message?: string; } & (undefined extends TErrorType ? object : { errorType: TErrorType }) & (undefined extends TErrorDetails ? object : { details: TErrorDetails extends string ? unknown : TErrorDetails }); }; export type UnauthorizedResult = { statusCode: 403; body: { success: false; error: T | 'unauthorized'; }; }; export type InternalError = { statusCode: 500; body: { error: T | 'Internal error occured'; success: false } }; export type NotFoundResult = { statusCode: 404; body: { success: false; error: string; }; }; export type TOperation = 'hasAll' | 'hasAny'; export type NonEnterpriseTwoFactorOptions = { authRequired: true; forceTwoFactorAuthenticationForNonEnterprise: true; twoFactorRequired: true; permissionsRequired?: string[] | { [key in Method]: string[] } | { [key in Method]: { operation: TOperation; permissions: string[] } }; twoFactorOptions: ITwoFactorOptions; }; export type Options = ( | { permissionsRequired?: | string[] | ({ [key in Method]?: string[] } & { '*'?: string[] }) | ({ [key in Method]?: { operation: TOperation; permissions: string[] } } & { '*'?: { operation: TOperation; permissions: string[] }; }); authRequired?: boolean; forceTwoFactorAuthenticationForNonEnterprise?: boolean; rateLimiterOptions?: | { numRequestsAllowed?: number; intervalTimeInMS?: number; } | boolean; queryOperations?: string[]; queryFields?: string[]; } | { permissionsRequired?: | string[] | ({ [key in Method]?: string[] } & { '*'?: string[] }) | ({ [key in Method]?: { operation: TOperation; permissions: string[] } } & { '*'?: { operation: TOperation; permissions: string[] }; }); authRequired: true; twoFactorRequired: true; twoFactorOptions?: ITwoFactorOptions; rateLimiterOptions?: | { numRequestsAllowed?: number; intervalTimeInMS?: number; } | boolean; queryOperations?: string[]; queryFields?: string[]; } ) & { validateParams?: ValidateFunction | { [key in Method]?: ValidateFunction }; authOrAnonRequired?: true; deprecationVersion?: string; }; export type PartialThis = { readonly request: Request & { query: Record }; readonly response: Response; readonly userId: string; readonly bodyParams: Record; readonly queryParams: Record; readonly queryOperations?: string[]; readonly queryFields?: string[]; readonly logger: Logger; }; export type UserInfo = IUser & { email?: string; settings: { profile: object; preferences: unknown; }; avatarUrl: string; }; export type ActionThis = { readonly requestIp: string; urlParams: UrlParams; readonly response: Response; // TODO make it unsafe readonly queryParams: TMethod extends 'GET' ? TOptions extends { validateParams: ValidateFunction } ? T : TOptions extends { validateParams: { GET: ValidateFunction } } ? T : Partial> & { offset?: number; count?: number } : Record; // TODO make it unsafe readonly bodyParams: TMethod extends 'GET' ? Record : TOptions extends { validateParams: ValidateFunction } ? T : TOptions extends { validateParams: infer V } ? V extends { [key in TMethod]: ValidateFunction } ? T : Partial> : // TODO remove the extra (optionals) params when all the endpoints that use these are typed correctly Partial>; readonly request: Request; readonly queryOperations: TOptions extends { queryOperations: infer T } ? T : never; parseJsonQuery(): Promise<{ sort: Record; fields: Record; query: Record; }>; } & (TOptions extends { authRequired: true } ? { user: IUser; userId: string; readonly token: string; } : TOptions extends { authOrAnonRequired: true } ? { user?: IUser; userId?: string; readonly token?: string; } : { user?: IUser | null; userId?: string | undefined; readonly token?: string; }); export type ResultFor = | SuccessResult> | FailureResult | UnauthorizedResult | NotFoundResult | { statusCode: number; body: unknown; }; export type Action = | ((this: ActionThis) => Promise>) | ((this: ActionThis) => ResultFor); export type Operation = | Action | ({ action: Action; } & { twoFactorRequired: boolean }); export type Operations = { [M in MethodOf as Lowercase]: Operation, TPathPattern, TOptions>; };