import yargs from 'yargs'; import express from 'express'; import WebSocket from 'ws'; import { Observable, ObservedValueOf } from 'rxjs'; import { IncomingMessage } from 'http'; import * as Joi from 'joi'; import { IAction } from './action'; import { TaggedLogger, BasicLogger } from './logging'; export interface ICommandLineArgs { http: boolean; watch: boolean; cert?: string; key?: string; host?: string; port: number; envFile?: string; } export type ServiceDeps = { logger: BasicLogger; } & D; export type EndpointsHandler = ( app: express.Express, deps: ServiceDeps ) => Promise; export interface IServiceConfig { defaultPort: number; logger?: () => Promise; buildDeps?: () => Promise; endpoints?: EndpointsHandler; sockets?: (deps: ServiceDeps) => Promise; background?: (deps: ServiceDeps) => Promise; spy?: ( spy: ReturnType, deps: ServiceDeps ) => Promise; argsBuilder?: ArgsBuilder; serviceConfigModuleId?: string; watchPatterns?: string[]; shouldUseDefaultBackgroundOperations?: boolean; shouldUseDefaultEndpoints?: boolean; shouldLoadEnvFiles?: boolean; } export interface IBackgroundEpicContext { logger: TaggedLogger; } export interface IBackgroundEpic< I extends IAction = IAction, O extends IAction = IAction, D = {}, R extends unknown[] = unknown[] > { ( events: Observable, ctx: IBackgroundEpicContext & D, ...args: R ): Observable; buildDeps?: () => D; } export type BackgroundEpic< I extends IAction = IAction, O extends IAction = IAction, D = {} > = IBackgroundEpic; export interface ISocketEpicsMap { [path: string]: AnySocketEpic; } export interface ISocketEpicAttributes< O extends IAction | Buffer = IAction | Buffer, D = {} > { send?: (socket: WebSocket, data: O) => Promise; actionSchemaByType?: (type: string) => Joi.ObjectSchema | null; logOnConnection?: ( socket: WebSocket, request: IncomingMessage & { id: string } ) => { [key: string]: string | undefined }; completedSocketWarningTimeout?: number; completedSocketWaitTimeout?: number; watchModeDetachBehaviour?: 'disconnect' | 'unsubscribe'; debugStats?: boolean; buildDeps?: () => D; } export interface ISocketEpicContext { id: string; request: IncomingMessage & { id: string }; binary: Observable; subscribe: () => Observable; publish: () => (events: Observable) => Observable; logger: TaggedLogger; takeUntilClosed: () => (stream: Observable) => Observable; } export interface ISocketEpic< I extends IAction = IAction, O extends IAction | Buffer = IAction | Buffer, D = {}, R extends unknown[] = unknown[] > extends ISocketEpicAttributes { ( commands: Observable, ctx: ISocketEpicContext & D, ...args: R ): Observable; } export const makeSocketEpic = (epic: E): E => epic; export type AnySocketEpic = SocketEpic; export type AnyEpic< T extends IAction = IAction, O extends IAction | Buffer = IAction | Buffer, R extends unknown[] = unknown[] > = ( commands: Observable, ctx: IBackgroundEpicContext | ISocketEpicContext, ...args: R ) => Observable; export type SocketEpic< I extends IAction = IAction, O extends IAction | Buffer = IAction | Buffer, D = {}, R extends unknown[] = unknown[] > = ISocketEpic; type ArgsBuilder = ( args: yargs.Argv ) => yargs.Argv; export type InputOfEpic = ObservedValueOf[0]>; export type OutputOfEpic = ObservedValueOf>; export type DependenciesOfBackgroundEpic = Exclude< Parameters[1], IBackgroundEpicContext > extends never ? {} : Exclude[1], IBackgroundEpicContext>; export type DependenciesOfSocketEpic = Exclude< Parameters[1], ISocketEpicContext > extends never ? {} : Exclude[1], ISocketEpicContext>;