From 86672d490805c8eb301493856c1a3a18bf3b52a3 Mon Sep 17 00:00:00 2001 From: Stanislav Muhametsin <346799+stazz@users.noreply.github.com> Date: Thu, 24 Aug 2023 23:18:20 +0300 Subject: [PATCH 1/3] #14 Updating dependencies first. --- server/package.json | 4 ++-- server/src/middleware.ts | 2 +- server/yarn.lock | 7 +++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/server/package.json b/server/package.json index c89d85b..50e1809 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "@ty-ras/server-express", - "version": "2.0.1", + "version": "2.1.0", "author": { "name": "Stanislav Muhametsin", "email": "346799+stazz@users.noreply.github.com", @@ -31,7 +31,7 @@ } }, "dependencies": { - "@ty-ras/server": "^2.0.0" + "@ty-ras/server": "^2.1.1" }, "peerDependencies": { "express": "^4.18.2" diff --git a/server/src/middleware.ts b/server/src/middleware.ts index 48aa579..74cbbee 100644 --- a/server/src/middleware.ts +++ b/server/src/middleware.ts @@ -9,7 +9,7 @@ import type * as context from "./context.types"; import * as internal from "./internal"; /** - * Creates a new {@link express.Middleware} to server the given TyRAS {@link ep.AppEndpoint}s. + * Creates a new {@link express.Middleware} to serve the given TyRAS {@link ep.AppEndpoint}s. * @param endpoints The TyRAS {@link ep.AppEndpoint}s to serve through this Koa middleware. * @param createState The optional callback to create state for the endpoints. * @param events The optional {@link server.ServerEventHandler} callback to observe server events. diff --git a/server/yarn.lock b/server/yarn.lock index e4cb36d..fb4c01a 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -445,6 +445,13 @@ dependencies: "@ty-ras/endpoint" "^2.0.0" +"@ty-ras/server@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@ty-ras/server/-/server-2.1.1.tgz#ea13ddbe58f3603d6eab396277c1cf97c2171fe7" + integrity sha512-KAiuSEYwXKQIfMSIDCaGjuX/hy42oes/JnyG0blumMNwR0kSA6PYonDfg1ROtBPO9dGQZ/mWiWS3JKbZfMFKoQ== + dependencies: + "@ty-ras/endpoint" "^2.0.0" + "@types/body-parser@*": version "1.19.2" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" From 425097a897eb8634e04645fe1220b44f7b50266b Mon Sep 17 00:00:00 2001 From: Stanislav Muhametsin <346799+stazz@users.noreply.github.com> Date: Fri, 25 Aug 2023 21:59:27 +0300 Subject: [PATCH 2/3] =?UTF-8?q?#14=20Adding=20custom=20listen=20functional?= =?UTF-8?q?ity=20to=20server.=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … --- server/package.json | 1 + server/src/__test__/listen.spec.ts | 27 +++ server/src/__test__/server-node.spec.ts | 111 ++++++++++ server/src/__test__/server.spec.ts | 74 +++---- server/src/index.ts | 3 + server/src/listen.ts | 102 +++++++++ server/src/server-node.ts | 263 ++++++++++++++++++++++++ server/src/server.ts | 251 ++-------------------- server/yarn.lock | 5 + 9 files changed, 559 insertions(+), 278 deletions(-) create mode 100644 server/src/__test__/listen.spec.ts create mode 100644 server/src/__test__/server-node.spec.ts create mode 100644 server/src/listen.ts create mode 100644 server/src/server-node.ts diff --git a/server/package.json b/server/package.json index 50e1809..2b5eaba 100644 --- a/server/package.json +++ b/server/package.json @@ -59,6 +59,7 @@ "madge": "6.1.0", "node-forge": "1.3.1", "prettier": "3.0.1", + "ts-expect": "1.3.0", "ts-node": "10.9.1", "typescript": "5.1.6" }, diff --git a/server/src/__test__/listen.spec.ts b/server/src/__test__/listen.spec.ts new file mode 100644 index 0000000..bd9511d --- /dev/null +++ b/server/src/__test__/listen.spec.ts @@ -0,0 +1,27 @@ +/** + * @file This file contains unit tests for functionality in file `../server-node.ts`. + */ + +import test from "ava"; +import * as spec from "../listen"; +import * as express from "express"; +import getPort from "@ava/get-port"; + +test("Verify that listen overload for host and port works", async (c) => { + c.plan(1); + await c.notThrowsAsync( + async () => + await spec.listenAsync(express.default(), "localhost", await getPort()), + ); +}); + +test("Verify that listen overload for listen options works", async (c) => { + c.plan(1); + await c.notThrowsAsync( + async () => + await spec.listenAsync(express.default(), { + options: {}, + listen: { host: "localhost", port: await getPort() }, + }), + ); +}); diff --git a/server/src/__test__/server-node.spec.ts b/server/src/__test__/server-node.spec.ts new file mode 100644 index 0000000..600b312 --- /dev/null +++ b/server/src/__test__/server-node.spec.ts @@ -0,0 +1,111 @@ +/** + * @file This file contains unit tests for functionality in file `../server-node.ts`. + */ + +import test from "ava"; +import * as spec from "../server-node"; +import * as expect from "ts-expect"; + +import type * as http from "node:http"; +import type * as https from "node:https"; +import type * as http2 from "node:http2"; + +// When these errors fail, it will happen already on compile-time. +// But still need to have this code to actually call the functions. + +test("Validate that non-secure HTTP1 overload of createNodeServer works", (c) => { + expect.expectType(spec.createNodeServer(handler1)); + expect.expectType( + spec.createNodeServer(handler1, { + options: {}, + }), + ); + expect.expectType( + spec.createNodeServer(handler1, { + options: {}, + httpVersion: 1, + secure: false, + }), + ); + c.pass(); +}); + +test("Validate that secure HTTP1 overload of createNodeServer works", (c) => { + expect.expectType( + spec.createNodeServer({ options: { cert: "" } }, handler1), + ); + expect.expectType( + spec.createNodeServer({ options: {} }, handler1), + ); + expect.expectType( + spec.createNodeServer( + { options: {}, httpVersion: 1, secure: true }, + handler1, + ), + ); + c.pass(); +}); + +test("Validate that non-secure HTTP2 overload of createNodeServer works", (c) => { + expect.expectType( + spec.createNodeServer({ httpVersion: 2, options: {} }, handler2), + ); + expect.expectType( + spec.createNodeServer( + { + options: {}, + httpVersion: 2, + secure: false, + }, + handler2, + ), + ); + c.pass(); +}); + +test("Validate that secure HTTP2 overload of createNodeServer works", (c) => { + expect.expectType( + spec.createNodeServer({ httpVersion: 2, options: { cert: "" } }, handler2), + ); + // Notice that simply passing 'options: {}' will not work for secure http2 server overload! + expect.expectType( + spec.createNodeServer( + { options: {}, httpVersion: 2, secure: true }, + handler2, + ), + ); + c.pass(); +}); + +test("Validate that passing invalid parameters is caught", (c) => { + c.plan(2); + c.throws( + () => spec.createNodeServer(undefined as unknown as spec.HTTP1Handler), + { + instanceOf: Error, + message: + "The HTTP server options are mandatory when creating anything other than unsecured HTTP1 server.", + }, + ); + c.throws( + () => + spec.createNodeServer( + { options: {} }, + undefined as unknown as spec.HTTP1Handler, + ), + { + instanceOf: Error, + message: "The HTTP server callback must be specified.", + }, + ); +}); + +/* eslint-disable @typescript-eslint/no-unused-vars */ + +const handler1 = (_req: http.IncomingMessage, _res: http.ServerResponse) => + Promise.resolve(); + +const handler2 = ( + _req: http2.Http2ServerRequest, + _res: http2.Http2ServerResponse, +) => Promise.resolve(); diff --git a/server/src/__test__/server.spec.ts b/server/src/__test__/server.spec.ts index 2c2200c..b6265f5 100644 --- a/server/src/__test__/server.spec.ts +++ b/server/src/__test__/server.spec.ts @@ -6,7 +6,7 @@ import test from "ava"; import * as spec from "../server"; import * as secure from "./secure"; - +import * as serverNode from "../server-node"; import * as testSupport from "@ty-ras/server-test-support"; const createServer: testSupport.CreateServer = ( @@ -14,39 +14,31 @@ const createServer: testSupport.CreateServer = ( info, httpVersion, secure, -) => - httpVersion === 1 - ? secure - ? spec.createServer({ - endpoints, - ...getCreateState(info), - options: { - ...secureInfo, - }, - }) - : spec.createServer({ endpoints, ...getCreateState(info) }) - : httpVersion === 2 - ? secure - ? { - server: spec.createServer({ - endpoints, - ...getCreateState(info), - httpVersion, - options: { - ...secureInfo, - }, - }), - secure, - } - : { - server: spec.createServer({ - endpoints, - ...getCreateState(info), - httpVersion, - }), - secure, - } - : doThrow(`Invalid http version: ${httpVersion}`); +) => { + const server = spec.createServer({ + endpoints, + ...getCreateState(info), + }); + return { + server: serverNode.createNodeServerGeneric( + httpVersion === 2 + ? { + httpVersion: 2, + secure, + options: secure ? secureInfo : {}, + } + : httpVersion === 1 + ? { + httpVersion: 1, + secure, + options: secure ? secureInfo : {}, + } + : doThrow(`Invalid http version: ${httpVersion}`), + server, + ), + secure, + }; +}; const secureInfo = secure.generateKeyAndCert(); const doThrow = (msg: string) => { @@ -71,14 +63,7 @@ testSupport.registerTests(test, createServer, { secure: true, }); -test("HTTP2 support should not work yet until 5.x release", (c) => { - c.plan(1); - c.throws(() => spec.createServer({ endpoints: [], httpVersion: 2 }), { - instanceOf: Error, - message: - "Unfortunately, express v4.x does not support HTTP protocol version 2, and couldn't find any workaround for that (http2-express-bridge didn't work).", - }); -}); +// Express 4.x does not support HTTP2 // testSupport.registerTests(test, createServer, { // ...defaultOpts, @@ -94,10 +79,7 @@ test("HTTP2 support should not work yet until 5.x release", (c) => { const getCreateState = ( info: testSupport.ServerTestAdditionalInfo[0], -): Pick< - spec.ServerCreationOptions, - "createState" -> => +): Pick, "createState"> => info == 500 ? { createState: () => { diff --git a/server/src/index.ts b/server/src/index.ts index 908014c..5a52b6c 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -5,5 +5,8 @@ export type * from "./context.types"; export * from "./middleware"; export * from "./cors"; +export * from "./server"; +export * from "./server-node"; +export * from "./listen"; // Don't export anything from ./internal.ts. diff --git a/server/src/listen.ts b/server/src/listen.ts new file mode 100644 index 0000000..ea837be --- /dev/null +++ b/server/src/listen.ts @@ -0,0 +1,102 @@ +/** + * @file This file contains function that can be used to expose uniform way to listen to TyRAS servers. + */ + +import type * as server from "./server"; +import * as serverGeneric from "@ty-ras/server"; +import * as serverNode from "./server-node"; +import * as net from "node:net"; + +/** + * The helper function to listen to given {@link server.HttpServer} asynchronously. + * @param server The {@link server.HttpServer} to listen to. + * @param host The hostname as string. + * @param port The port as number. + * @param backlog The backlog parameter, if any. + * @returns Asynchronously nothing. + */ +export function listenAsync( + server: server.HttpServer, + host: string, + port: number, + backlog?: number, +): Promise; + +/** + *The helper function to listen to given {@link server.HttpServer} asynchronously. + * @param server The {@link server.HttpServer} to listen to. + * @param options The {@link ListenOptions1}. Notice that Express 4.x does not support HTTP2. + * @returns Asynchronously nothing. + */ +export function listenAsync( + server: server.HttpServer, + options: ListenOptions1, +): Promise; + +/** + * The helper function to listen to given {@link server.HttpServer} asynchronously. + * @param server The {@link server.HttpServer} to listen to. + * @param hostOrOptions The {@link ListenOptions1}. Notice that Express 4.x does not support HTTP2. + * @param port The port to listen to. + * @param backlog The backlog parameter, if any. + * @returns Asynchronously nothing. + */ +export function listenAsync( + server: server.HttpServer, + hostOrOptions: string | ListenOptions1, + port?: number, + backlog?: number, +) { + const opts: ListenOptions1 = + typeof hostOrOptions === "string" + ? { + options: {}, + listen: { + host: hostOrOptions, + port, + backlog, + }, + } + : hostOrOptions; + + return serverGeneric.listenAsyncGeneric( + serverNode.createNodeServerGeneric(opts, server), + typeof hostOrOptions === "string" ? hostOrOptions : hostOrOptions.listen, + port, + backlog, + ); +} + +/** + * This interface contains options for both HTTP 1 and 2 servers when listening to them via {@link listenAsync}. + */ +export interface ListenOptionsBase { + /** + * Options related to listening for connections. + */ + listen: net.ListenOptions; +} + +/** + * This interface contains options for HTTP 1 servers when listening to them via {@link listenAsync}. + */ +export interface ListenOptions1 + extends serverNode.ServerOptions1, + ListenOptionsBase { + /** + * Use this property if needed. + */ + httpVersion?: 1; +} + +// /** +// * This interface contains options for HTTP 2 servers when listening to them via {@link listenAsync}. +// */ +// export interface ListenOptions2 +// extends serverNode.ServerOptions2, +// ListenOptionsBase { +// /** +// * Set this property to `2` in order to use HTTP2 server when listening. +// */ +// httpVersion: 2; +// } diff --git a/server/src/server-node.ts b/server/src/server-node.ts new file mode 100644 index 0000000..63d4635 --- /dev/null +++ b/server/src/server-node.ts @@ -0,0 +1,263 @@ +/** + * @file This file contains function that can be used to expose uniform way to create Node HTTP servers. + */ + +import * as http from "node:http"; +import * as https from "node:https"; +import * as http2 from "node:http2"; +import type * as tls from "node:tls"; + +/** + * Creates new non-secure HTTP1 {@link http.Server} using given callback with optional additional configuration via {@link ServerOptions1}. + * @param handler The {@link HTTP1Handler} callback. + * @param opts The {@link ServerCreationOptions} to use when creating server. + * @returns A new non-secure HTTP1 {@link http.Server}. + */ +export function createNodeServer( + handler: HTTP1Handler, + opts?: ServerOptions1, +): http.Server; + +/** + * Creates new secure HTTP1 {@link https.Server} using given callback with additional configuration via {@link ServerOptions1}. + * @param opts The {@link ServerCreationOptions} to use when creating server. + * @param handler The {@link HTTP1Handler} callback. + * @returns A new secure HTTP1 {@link https.Server}. + */ +export function createNodeServer( + opts: ServerOptions1, + handler: HTTP1Handler, +): https.Server; + +/** + * Creates new non-secure HTTP2 {@link http2.Http2Server} using given callback with additional configuration via {@link ServerOptions2}. + * Please set `httpVersion` value of `opts` to `2` to use HTTP2 protocol. + * @param opts The {@link ServerCreationOptions} to use when creating server. + * @param handler The {@link HTTP2Handler} callback. + * @returns A new non-secure HTTP2 {@link http2.Http2Server}. + */ +export function createNodeServer( + opts: ServerOptions2, + handler: HTTP2Handler, +): http2.Http2Server; + +/** + * Creates new secure HTTP2 {@link http2.Http2SecureServer} using given callback with additional configuration via {@link ServerOptions2}. + * Please set `httpVersion` value of `opts` to `2` to use HTTP2 protocol. + * @param opts The {@link ServerCreationOptions} to use when creating server. + * @param handler The {@link HTTP2Handler} callback. + * @returns A new secure HTTP2 {@link http2.Http2SecureServer}. + */ +export function createNodeServer( + opts: ServerOptions2, + handler: HTTP2Handler, +): http2.Http2SecureServer; + +/** + * Creates new secure or non-secure HTTP1 or HTTP2 Node server using given callback with additional configuration via {@link ServerOptions1} or {@link ServerOptions2}. + * Please set `httpVersion` value of `opts` to `2` to enable HTTP2 protocol, otherwise HTTP1 server will be returned. + * @param handler The {@link HTTP1Handler} or {@link ServerOptions1} or {@link ServerOptions2}. + * @param options The {@link ServerOptions1} or {@link HTTP1Handler} or {@link HTTP2Handler}. + * @returns Secure or non-secure HTTP1 or HTTP2 Node server + * @see createNodeServerGeneric + */ +export function createNodeServer( + handler: HTTP1Handler | ServerOptions1 | ServerOptions2, + options?: ServerOptions1 | HTTP1Handler | HTTP2Handler, +): http.Server | https.Server | http2.Http2Server | http2.Http2SecureServer { + return createNodeServerGeneric( + typeof handler === "function" + ? ensureObject, HTTP1Handler | HTTP2Handler>( + options ?? { options: {} }, + ) + : handler ?? + doThrow( + "The HTTP server options are mandatory when creating anything other than unsecured HTTP1 server.", + ), + typeof handler === "function" + ? handler + : typeof options === "function" + ? options + : doThrow("The HTTP server callback must be specified."), + ); +} + +/** + * Creates new secure or non-secure HTTP1 or HTTP2 Node server with given callback. + * Please set `httpVersion` value of `opts` to `2` to enable HTTP2 protocol, otherwise HTTP1 server will be returned. + * @param opts The {@link ServerOptions1} or {@link ServerOptions2} options. + * @param handler The {@link HTTP1Handler} or {@link HTTP2Handler} callback. + * @returns Secure or non-secure HTTP1 or HTTP2 Node server + */ +export function createNodeServerGeneric( + opts: ServerOptions1 | ServerOptions2, + handler: HTTP1Handler | HTTP2Handler, +): http.Server | https.Server | http2.Http2Server | http2.Http2SecureServer { + let retVal; + if ("httpVersion" in opts && opts.httpVersion === 2) { + const { options, secure } = opts; + const httpHandler = asyncToVoid(handler); + if (isSecure(secure, options, 2)) { + retVal = http2.createSecureServer(options ?? {}, httpHandler); + } else { + retVal = http2.createServer(options ?? {}, httpHandler); + } + } else { + const { options, secure } = opts; + const httpHandler = asyncToVoid(handler); + if (isSecure(secure, options, 1)) { + retVal = https.createServer(options ?? {}, httpHandler); + } else { + retVal = http.createServer(options ?? {}, httpHandler); + } + } + return retVal; +} + +/** + * This interface contains options common for both HTTP 1 and 2 servers when creating them via {@link createNodeServer}. + */ +export interface ServerOptionsBase { + /** + * The further options for the HTTP server. + */ + options: TOptions; + + /** + * Set this to `true` explicitly if automatic detection of server being secure by {@link createNodeServer} fails. + */ + secure?: TSecure; +} + +/** + * This interface contains options for HTTP 1 servers when creating them via {@link createNodeServer}. + */ +export interface ServerOptions1 + extends ServerOptionsBase< + boolean extends TSecure + ? http.ServerOptions | https.ServerOptions + : true extends TSecure + ? https.ServerOptions + : http.ServerOptions, + TSecure + > { + /** + * Use this property if needed. + */ + httpVersion?: 1; +} + +/** + * This interface contains options for HTTP 2 servers when creating them via {@link createNodeServer}. + */ +export interface ServerOptions2 + extends ServerOptionsBase< + boolean extends TSecure + ? http2.ServerOptions | http2.SecureServerOptions + : true extends TSecure + ? http2.SecureServerOptions + : http2.ServerOptions, + TSecure + > { + /** + * Set this property to `2` in order to use HTTP2 server when listening. + */ + httpVersion: 2; +} + +const isSecure = ( + secure: boolean | undefined, + options: object | undefined, + version: 1 | 2, +) => + secure || + (options && + (version === 1 ? secureHttp1OptionKeys : secureHttp2OptionKeys).some( + (propKey) => propKey in options, + )); + +const secureHttp1OptionKeys: ReadonlyArray = [ + "key", + "cert", + "pfx", + "passphrase", + "rejectUnauthorized", + "ciphers", + "ca", + "requestCert", + "secureContext", + "secureOptions", + "secureProtocol", + "sigalgs", + "ticketKeys", + "crl", + "clientCertEngine", + "dhparam", + "ecdhCurve", + "allowHalfOpen", + "handshakeTimeout", + "honorCipherOrder", + "keepAlive", + "keepAliveInitialDelay", + "maxVersion", + "minVersion", + "noDelay", + "pauseOnConnect", + "privateKeyEngine", + "privateKeyIdentifier", + "pskCallback", + "pskIdentityHint", + "sessionIdContext", + "sessionTimeout", + "ALPNProtocols", + "SNICallback", +]; + +const secureHttp2OptionKeys: ReadonlyArray< + "allowHTTP1" | "origins" | keyof tls.TlsOptions +> = ["allowHTTP1", "origins", ...secureHttp1OptionKeys]; + +const asyncToVoid = + ( + asyncCallback: HTTP1Handler | HTTP2Handler, + ): ((...args: Parameters) => void) => + (...args) => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any + void asyncCallback(...(args as [any, any])); + }; + +/** + * Generic callback interface used by {@link HTTP1Handler} and {@link HTTP2Handler}. + */ +export type HTTP1Or2Handler = ( + req: TRequest, + res: TResponse, +) => Promise; + +/** + * The callback type for HTTP1 servers. + */ +export type HTTP1Handler = HTTP1Or2Handler< + http.IncomingMessage, + http.ServerResponse +>; + +/** + * The callback type for HTTP2 servers. + */ +export type HTTP2Handler = HTTP1Or2Handler< + http2.Http2ServerRequest, + http2.Http2ServerResponse +>; + +const doThrow = (msg: string) => { + throw new Error(msg); +}; + +const ensureObject = < + TObject extends object, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TFunction extends (...args: Array) => any, +>( + obj: TObject | TFunction, +): TObject => (typeof obj === "function" ? doThrow("Please pass object") : obj); diff --git a/server/src/server.ts b/server/src/server.ts index 446a354..5e61179 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -8,137 +8,29 @@ import * as express from "express"; import type * as ctx from "./context.types"; import * as middleware from "./middleware"; -import * as http from "node:http"; -import * as https from "node:https"; -import * as http2 from "node:http2"; -import type * as tls from "node:tls"; - -/** - * Creates new non-secure HTTP1 {@link http.Server} serving given TyRAS {@link ep.AppEndpoint}s with additional configuration via {@link ServerCreationOptions}. - * @param opts The {@link ServerCreationOptions} to use when creating server. - * @returns A new non-secure HTTP1 {@link http.Server}. - */ -export function createServer( - opts: ServerCreationOptions & - HTTP1ServerOptions, -): http.Server; - -/** - * Creates new secure HTTP1 {@link https.Server} serving given TyRAS {@link ep.AppEndpoint}s with additional configuration via {@link ServerCreationOptions}. - * @param opts The {@link ServerCreationOptions} to use when creating server. - * @returns A new secure HTTP1 {@link https.Server}. - */ -export function createServer( - opts: ServerCreationOptions & - HTTP1ServerOptions, -): https.Server; - -/** - * Creates new non-secure HTTP2 {@link http2.Http2Server} serving given TyRAS {@link ep.AppEndpoint}s with additional configuration via {@link ServerCreationOptions}. - * Please set `httpVersion` value of `opts` to `2` to use HTTP2 protocol. - * @param opts The {@link ServerCreationOptions} to use when creating server. - * @returns A new non-secure HTTP2 {@link http2.Http2Server}. - */ -export function createServer( - opts: ServerCreationOptions & - HTTP2ServerOptions, -): http2.Http2Server; - -/** - * Creates new secure HTTP2 {@link http2.Http2SecureServer} serving given TyRAS {@link ep.AppEndpoint}s with additional configuration via {@link ServerCreationOptions}. - * Please set `httpVersion` value of `opts` to `2` to use HTTP2 protocol. - * @param opts The {@link ServerCreationOptions} to use when creating server. - * @returns A new secure HTTP2 {@link http2.Http2SecureServer}. - */ -export function createServer( - opts: ServerCreationOptions< - TStateInfo, - TState, - http2.SecureServerOptions, - true - > & - HTTP2ServerOptions, -): http2.Http2SecureServer; - /** - * Creates new secure or non-secure HTTP1 or HTTP2 Node server serving given TyRAS {@link ep.AppEndpoint}s with additional configuration via {@link ServerCreationOptions}. + * Creates new {@link express.Express} server serving given TyRAS {@link ep.AppEndpoint}s with additional configuration via {@link ServerCreationOptions}. * Please set `httpVersion` value of `opts` to `2` to enable HTTP2 protocol, otherwise HTTP1 server will be returned. * @param opts The {@link ServerCreationOptions} to use when creating server. - * @returns Secure or non-secure HTTP1 or HTTP2 Node server + * @param opts.endpoints Privately deconstructed variable. + * @param opts.createState Privately deconstructed variable. + * @param opts.events Privately deconstructed variable. + * @returns The {@link express.Express} server. */ -export function createServer( - opts: - | (ServerCreationOptions & - HTTP1ServerOptions) - | (ServerCreationOptions & - HTTP1ServerOptions) - | (ServerCreationOptions & - HTTP2ServerOptions) - | (ServerCreationOptions< - TStateInfo, - TState, - http2.SecureServerOptions, - true - > & - HTTP2ServerOptions), -) { - let retVal; - if ("httpVersion" in opts && opts.httpVersion === 2) { - const { options, secure, ...handlerOptions } = opts; - // eslint-disable-next-line sonarjs/no-use-of-empty-return-value - const httpHandler = createHandleHttpRequest2( - handlerOptions, - ); - if (isSecure(secure, options, 2)) { - retVal = http2.createSecureServer(options ?? {}, httpHandler); - } else { - retVal = http2.createServer(options ?? {}, httpHandler); - } - } else { - const { options, secure, ...handlerOptions } = opts; - const httpHandler = createHandleHttpRequest1( - handlerOptions, - ); - if (isSecure(secure, options, 1)) { - retVal = https.createServer(options ?? {}, httpHandler); - } else { - retVal = http.createServer(options ?? {}, httpHandler); - } - } - return retVal; +export function createServer({ + endpoints, + createState, + events, +}: ServerCreationOptions): HttpServer { + return express + .default() + .disable("x-powered-by") + .use(middleware.createMiddleware(endpoints, createState, events)); } - -/** - * This type is used to make it possible to explicitly specify using HTTP protocol version 1 for server if given to {@link createServer}. - */ -export type HTTP1ServerOptions = { - /** - * Optional property which should be set to `1` if needed to explicitly use HTTP protocol version 1 for server. - * The default protocol version is 1, so this is optional. - */ - httpVersion?: 1; -}; - -/** - * This type is used to make it possible to specify {@link createServer} to use HTTP protocol version 2, as opposed to default 1. - */ -export type HTTP2ServerOptions = { - /** - * Property which should be set to `2` if needed to use HTTP protocol version 2 for server. - * The default protocol version is 1, so to override that, this property must be specified. - */ - httpVersion: 2; -}; - /** * This interface contains options common for both HTTP 1 and 2 servers when creating them via {@link createServer}. */ -export interface ServerCreationOptions< - TStateInfo, - TState, - TOPtions, - TSecure extends boolean, -> { +export interface ServerCreationOptions { /** * The TyRAS {@link ep.AppEndpoint}s to server via returned HTTP server. */ @@ -155,114 +47,9 @@ export interface ServerCreationOptions< events?: | server.ServerEventHandler, TState> | undefined; - - /** - * The further options for the HTTP server. - */ - options?: TOPtions | undefined; - - /** - * Set this to `true` explicitly if automatic detection of server being secure by {@link createServer} fails. - */ - secure?: TSecure | undefined; } -const secureHttp1OptionKeys: ReadonlyArray = [ - "key", - "cert", - "pfx", - "passphrase", - "rejectUnauthorized", - "ciphers", - "ca", - "requestCert", - "secureContext", - "secureOptions", - "secureProtocol", - "sigalgs", - "ticketKeys", - "crl", - "clientCertEngine", - "dhparam", - "ecdhCurve", - "allowHalfOpen", - "handshakeTimeout", - "honorCipherOrder", - "keepAlive", - "keepAliveInitialDelay", - "maxVersion", - "minVersion", - "noDelay", - "pauseOnConnect", - "privateKeyEngine", - "privateKeyIdentifier", - "pskCallback", - "pskIdentityHint", - "sessionIdContext", - "sessionTimeout", - "ALPNProtocols", - "SNICallback", -]; - -const secureHttp2OptionKeys: ReadonlyArray< - "allowHTTP1" | "origins" | keyof tls.TlsOptions -> = ["allowHTTP1", "origins", ...secureHttp1OptionKeys]; - -const createHandleHttpRequest1 = ({ - endpoints, - createState, - events, -}: Pick< - ServerCreationOptions, - "endpoints" | "createState" | "events" ->): HTTP1Or2Handler => { - return express - .default() - .disable("x-powered-by") - .use(middleware.createMiddleware(endpoints, createState, events)); -}; - -// It looks like http2-express-bridge is not compatible with newer express versions. -// Furthermore, looks like http2 support is coming to express only in 5.x, which is still in beta. -// So for now,disable this. -const createHandleHttpRequest2 = ( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _: // { - // endpoints, - // createState, - // events, - // }: - Pick< - ServerCreationOptions, - "endpoints" | "createState" | "events" - >, -): HTTP1Or2Handler => { - throw new Error( - "Unfortunately, express v4.x does not support HTTP protocol version 2, and couldn't find any workaround for that (http2-express-bridge didn't work).", - ); - // return http2Express(express.default) - // .disable("x-powered-by") - // .use( - // middleware.createMiddleware(endpoints, createState, events), - // // The http2-express-bridge typings are not so great, so we gotta do this explicit cast. - // ) as unknown as HTTP1Or2Handler< - // http2.Http2ServerRequest, - // http2.Http2ServerResponse - // >; -}; - -type HTTP1Or2Handler = ( - req: TRequest, - res: TResponse, -) => void; - -const isSecure = ( - secure: boolean | undefined, - options: object | undefined, - version: 1 | 2, -) => - secure || - (options && - (version === 1 ? secureHttp1OptionKeys : secureHttp2OptionKeys).some( - (propKey) => propKey in options, - )); +/** + * This type contains all the HTTP server types that can be created with TyRAS backend for Express servers. + */ +export type HttpServer = express.Express; diff --git a/server/yarn.lock b/server/yarn.lock index fb4c01a..27f659c 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -3500,6 +3500,11 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.2.tgz#7c094f753b6705ee4faee25c3c684ade52d66d99" integrity sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ== +ts-expect@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-expect/-/ts-expect-1.3.0.tgz#3f8d3966e0e22b5e2bb88337eb99db6816a4c1cf" + integrity sha512-e4g0EJtAjk64xgnFPD6kTBUtpnMVzDrMb12N1YZV0VvSlhnVT3SGxiYTLdGy8Q5cYHOIC/FAHmZ10eGrAguicQ== + ts-graphviz@^1.5.0: version "1.8.1" resolved "https://registry.yarnpkg.com/ts-graphviz/-/ts-graphviz-1.8.1.tgz#5d95e58120be8b571847331516327d4840cc44f7" From 8c6025259aba4147c4ce3697e9a9548072a174e8 Mon Sep 17 00:00:00 2001 From: Stanislav Muhametsin <346799+stazz@users.noreply.github.com> Date: Fri, 25 Aug 2023 23:40:39 +0300 Subject: [PATCH 3/3] =?UTF-8?q?#14=20Taking=20newer=20version=20of=20gener?= =?UTF-8?q?ic=20server=20packag=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …e into use. --- server/package.json | 3 +- server/src/__test__/listen.spec.ts | 12 +- server/src/__test__/server-node.spec.ts | 111 ---------- server/src/__test__/server.spec.ts | 4 +- server/src/index.ts | 1 - server/src/listen.ts | 6 +- server/src/middleware.ts | 4 +- server/src/server-node.ts | 263 ------------------------ server/yarn.lock | 13 +- 9 files changed, 19 insertions(+), 398 deletions(-) delete mode 100644 server/src/__test__/server-node.spec.ts delete mode 100644 server/src/server-node.ts diff --git a/server/package.json b/server/package.json index 2b5eaba..afc1190 100644 --- a/server/package.json +++ b/server/package.json @@ -31,7 +31,7 @@ } }, "dependencies": { - "@ty-ras/server": "^2.1.1" + "@ty-ras/server": "^2.2.0" }, "peerDependencies": { "express": "^4.18.2" @@ -59,7 +59,6 @@ "madge": "6.1.0", "node-forge": "1.3.1", "prettier": "3.0.1", - "ts-expect": "1.3.0", "ts-node": "10.9.1", "typescript": "5.1.6" }, diff --git a/server/src/__test__/listen.spec.ts b/server/src/__test__/listen.spec.ts index bd9511d..e64fa4c 100644 --- a/server/src/__test__/listen.spec.ts +++ b/server/src/__test__/listen.spec.ts @@ -4,14 +4,18 @@ import test from "ava"; import * as spec from "../listen"; -import * as express from "express"; +import * as server from "../server"; import getPort from "@ava/get-port"; -test("Verify that listen overload for host and port works", async (c) => { +test("Verify that listen overload for host and port as in starter template, works", async (c) => { c.plan(1); await c.notThrowsAsync( async () => - await spec.listenAsync(express.default(), "localhost", await getPort()), + await spec.listenAsync( + server.createServer({ endpoints: [] }), + "localhost", + await getPort(), + ), ); }); @@ -19,7 +23,7 @@ test("Verify that listen overload for listen options works", async (c) => { c.plan(1); await c.notThrowsAsync( async () => - await spec.listenAsync(express.default(), { + await spec.listenAsync(server.createServer({ endpoints: [] }), { options: {}, listen: { host: "localhost", port: await getPort() }, }), diff --git a/server/src/__test__/server-node.spec.ts b/server/src/__test__/server-node.spec.ts deleted file mode 100644 index 600b312..0000000 --- a/server/src/__test__/server-node.spec.ts +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @file This file contains unit tests for functionality in file `../server-node.ts`. - */ - -import test from "ava"; -import * as spec from "../server-node"; -import * as expect from "ts-expect"; - -import type * as http from "node:http"; -import type * as https from "node:https"; -import type * as http2 from "node:http2"; - -// When these errors fail, it will happen already on compile-time. -// But still need to have this code to actually call the functions. - -test("Validate that non-secure HTTP1 overload of createNodeServer works", (c) => { - expect.expectType(spec.createNodeServer(handler1)); - expect.expectType( - spec.createNodeServer(handler1, { - options: {}, - }), - ); - expect.expectType( - spec.createNodeServer(handler1, { - options: {}, - httpVersion: 1, - secure: false, - }), - ); - c.pass(); -}); - -test("Validate that secure HTTP1 overload of createNodeServer works", (c) => { - expect.expectType( - spec.createNodeServer({ options: { cert: "" } }, handler1), - ); - expect.expectType( - spec.createNodeServer({ options: {} }, handler1), - ); - expect.expectType( - spec.createNodeServer( - { options: {}, httpVersion: 1, secure: true }, - handler1, - ), - ); - c.pass(); -}); - -test("Validate that non-secure HTTP2 overload of createNodeServer works", (c) => { - expect.expectType( - spec.createNodeServer({ httpVersion: 2, options: {} }, handler2), - ); - expect.expectType( - spec.createNodeServer( - { - options: {}, - httpVersion: 2, - secure: false, - }, - handler2, - ), - ); - c.pass(); -}); - -test("Validate that secure HTTP2 overload of createNodeServer works", (c) => { - expect.expectType( - spec.createNodeServer({ httpVersion: 2, options: { cert: "" } }, handler2), - ); - // Notice that simply passing 'options: {}' will not work for secure http2 server overload! - expect.expectType( - spec.createNodeServer( - { options: {}, httpVersion: 2, secure: true }, - handler2, - ), - ); - c.pass(); -}); - -test("Validate that passing invalid parameters is caught", (c) => { - c.plan(2); - c.throws( - () => spec.createNodeServer(undefined as unknown as spec.HTTP1Handler), - { - instanceOf: Error, - message: - "The HTTP server options are mandatory when creating anything other than unsecured HTTP1 server.", - }, - ); - c.throws( - () => - spec.createNodeServer( - { options: {} }, - undefined as unknown as spec.HTTP1Handler, - ), - { - instanceOf: Error, - message: "The HTTP server callback must be specified.", - }, - ); -}); - -/* eslint-disable @typescript-eslint/no-unused-vars */ - -const handler1 = (_req: http.IncomingMessage, _res: http.ServerResponse) => - Promise.resolve(); - -const handler2 = ( - _req: http2.Http2ServerRequest, - _res: http2.Http2ServerResponse, -) => Promise.resolve(); diff --git a/server/src/__test__/server.spec.ts b/server/src/__test__/server.spec.ts index b6265f5..7ffe8a9 100644 --- a/server/src/__test__/server.spec.ts +++ b/server/src/__test__/server.spec.ts @@ -6,7 +6,7 @@ import test from "ava"; import * as spec from "../server"; import * as secure from "./secure"; -import * as serverNode from "../server-node"; +import * as serverGeneric from "@ty-ras/server"; import * as testSupport from "@ty-ras/server-test-support"; const createServer: testSupport.CreateServer = ( @@ -20,7 +20,7 @@ const createServer: testSupport.CreateServer = ( ...getCreateState(info), }); return { - server: serverNode.createNodeServerGeneric( + server: serverGeneric.createNodeServerGeneric( httpVersion === 2 ? { httpVersion: 2, diff --git a/server/src/index.ts b/server/src/index.ts index 5a52b6c..786dace 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -6,7 +6,6 @@ export type * from "./context.types"; export * from "./middleware"; export * from "./cors"; export * from "./server"; -export * from "./server-node"; export * from "./listen"; // Don't export anything from ./internal.ts. diff --git a/server/src/listen.ts b/server/src/listen.ts index ea837be..632224c 100644 --- a/server/src/listen.ts +++ b/server/src/listen.ts @@ -4,7 +4,6 @@ import type * as server from "./server"; import * as serverGeneric from "@ty-ras/server"; -import * as serverNode from "./server-node"; import * as net from "node:net"; /** @@ -50,7 +49,6 @@ export function listenAsync( const opts: ListenOptions1 = typeof hostOrOptions === "string" ? { - options: {}, listen: { host: hostOrOptions, port, @@ -60,7 +58,7 @@ export function listenAsync( : hostOrOptions; return serverGeneric.listenAsyncGeneric( - serverNode.createNodeServerGeneric(opts, server), + serverGeneric.createNodeServerGeneric(opts, server), typeof hostOrOptions === "string" ? hostOrOptions : hostOrOptions.listen, port, backlog, @@ -81,7 +79,7 @@ export interface ListenOptionsBase { * This interface contains options for HTTP 1 servers when listening to them via {@link listenAsync}. */ export interface ListenOptions1 - extends serverNode.ServerOptions1, + extends serverGeneric.NodeServerOptions1, ListenOptionsBase { /** * Use this property if needed. diff --git a/server/src/middleware.ts b/server/src/middleware.ts index 74cbbee..617354c 100644 --- a/server/src/middleware.ts +++ b/server/src/middleware.ts @@ -15,12 +15,12 @@ import * as internal from "./internal"; * @param events The optional {@link server.ServerEventHandler} callback to observe server events. * @returns The Koa middleware which will serve the given endpoints. */ -export const createMiddleware = ( +export const createMiddleware = ( endpoints: ReadonlyArray>, createState?: context.CreateState, events?: server.ServerEventHandler< server.GetContext, - TStateInfo + TState >, ): express.RequestHandler => { const flow = server.createTypicalServerFlow( diff --git a/server/src/server-node.ts b/server/src/server-node.ts deleted file mode 100644 index 63d4635..0000000 --- a/server/src/server-node.ts +++ /dev/null @@ -1,263 +0,0 @@ -/** - * @file This file contains function that can be used to expose uniform way to create Node HTTP servers. - */ - -import * as http from "node:http"; -import * as https from "node:https"; -import * as http2 from "node:http2"; -import type * as tls from "node:tls"; - -/** - * Creates new non-secure HTTP1 {@link http.Server} using given callback with optional additional configuration via {@link ServerOptions1}. - * @param handler The {@link HTTP1Handler} callback. - * @param opts The {@link ServerCreationOptions} to use when creating server. - * @returns A new non-secure HTTP1 {@link http.Server}. - */ -export function createNodeServer( - handler: HTTP1Handler, - opts?: ServerOptions1, -): http.Server; - -/** - * Creates new secure HTTP1 {@link https.Server} using given callback with additional configuration via {@link ServerOptions1}. - * @param opts The {@link ServerCreationOptions} to use when creating server. - * @param handler The {@link HTTP1Handler} callback. - * @returns A new secure HTTP1 {@link https.Server}. - */ -export function createNodeServer( - opts: ServerOptions1, - handler: HTTP1Handler, -): https.Server; - -/** - * Creates new non-secure HTTP2 {@link http2.Http2Server} using given callback with additional configuration via {@link ServerOptions2}. - * Please set `httpVersion` value of `opts` to `2` to use HTTP2 protocol. - * @param opts The {@link ServerCreationOptions} to use when creating server. - * @param handler The {@link HTTP2Handler} callback. - * @returns A new non-secure HTTP2 {@link http2.Http2Server}. - */ -export function createNodeServer( - opts: ServerOptions2, - handler: HTTP2Handler, -): http2.Http2Server; - -/** - * Creates new secure HTTP2 {@link http2.Http2SecureServer} using given callback with additional configuration via {@link ServerOptions2}. - * Please set `httpVersion` value of `opts` to `2` to use HTTP2 protocol. - * @param opts The {@link ServerCreationOptions} to use when creating server. - * @param handler The {@link HTTP2Handler} callback. - * @returns A new secure HTTP2 {@link http2.Http2SecureServer}. - */ -export function createNodeServer( - opts: ServerOptions2, - handler: HTTP2Handler, -): http2.Http2SecureServer; - -/** - * Creates new secure or non-secure HTTP1 or HTTP2 Node server using given callback with additional configuration via {@link ServerOptions1} or {@link ServerOptions2}. - * Please set `httpVersion` value of `opts` to `2` to enable HTTP2 protocol, otherwise HTTP1 server will be returned. - * @param handler The {@link HTTP1Handler} or {@link ServerOptions1} or {@link ServerOptions2}. - * @param options The {@link ServerOptions1} or {@link HTTP1Handler} or {@link HTTP2Handler}. - * @returns Secure or non-secure HTTP1 or HTTP2 Node server - * @see createNodeServerGeneric - */ -export function createNodeServer( - handler: HTTP1Handler | ServerOptions1 | ServerOptions2, - options?: ServerOptions1 | HTTP1Handler | HTTP2Handler, -): http.Server | https.Server | http2.Http2Server | http2.Http2SecureServer { - return createNodeServerGeneric( - typeof handler === "function" - ? ensureObject, HTTP1Handler | HTTP2Handler>( - options ?? { options: {} }, - ) - : handler ?? - doThrow( - "The HTTP server options are mandatory when creating anything other than unsecured HTTP1 server.", - ), - typeof handler === "function" - ? handler - : typeof options === "function" - ? options - : doThrow("The HTTP server callback must be specified."), - ); -} - -/** - * Creates new secure or non-secure HTTP1 or HTTP2 Node server with given callback. - * Please set `httpVersion` value of `opts` to `2` to enable HTTP2 protocol, otherwise HTTP1 server will be returned. - * @param opts The {@link ServerOptions1} or {@link ServerOptions2} options. - * @param handler The {@link HTTP1Handler} or {@link HTTP2Handler} callback. - * @returns Secure or non-secure HTTP1 or HTTP2 Node server - */ -export function createNodeServerGeneric( - opts: ServerOptions1 | ServerOptions2, - handler: HTTP1Handler | HTTP2Handler, -): http.Server | https.Server | http2.Http2Server | http2.Http2SecureServer { - let retVal; - if ("httpVersion" in opts && opts.httpVersion === 2) { - const { options, secure } = opts; - const httpHandler = asyncToVoid(handler); - if (isSecure(secure, options, 2)) { - retVal = http2.createSecureServer(options ?? {}, httpHandler); - } else { - retVal = http2.createServer(options ?? {}, httpHandler); - } - } else { - const { options, secure } = opts; - const httpHandler = asyncToVoid(handler); - if (isSecure(secure, options, 1)) { - retVal = https.createServer(options ?? {}, httpHandler); - } else { - retVal = http.createServer(options ?? {}, httpHandler); - } - } - return retVal; -} - -/** - * This interface contains options common for both HTTP 1 and 2 servers when creating them via {@link createNodeServer}. - */ -export interface ServerOptionsBase { - /** - * The further options for the HTTP server. - */ - options: TOptions; - - /** - * Set this to `true` explicitly if automatic detection of server being secure by {@link createNodeServer} fails. - */ - secure?: TSecure; -} - -/** - * This interface contains options for HTTP 1 servers when creating them via {@link createNodeServer}. - */ -export interface ServerOptions1 - extends ServerOptionsBase< - boolean extends TSecure - ? http.ServerOptions | https.ServerOptions - : true extends TSecure - ? https.ServerOptions - : http.ServerOptions, - TSecure - > { - /** - * Use this property if needed. - */ - httpVersion?: 1; -} - -/** - * This interface contains options for HTTP 2 servers when creating them via {@link createNodeServer}. - */ -export interface ServerOptions2 - extends ServerOptionsBase< - boolean extends TSecure - ? http2.ServerOptions | http2.SecureServerOptions - : true extends TSecure - ? http2.SecureServerOptions - : http2.ServerOptions, - TSecure - > { - /** - * Set this property to `2` in order to use HTTP2 server when listening. - */ - httpVersion: 2; -} - -const isSecure = ( - secure: boolean | undefined, - options: object | undefined, - version: 1 | 2, -) => - secure || - (options && - (version === 1 ? secureHttp1OptionKeys : secureHttp2OptionKeys).some( - (propKey) => propKey in options, - )); - -const secureHttp1OptionKeys: ReadonlyArray = [ - "key", - "cert", - "pfx", - "passphrase", - "rejectUnauthorized", - "ciphers", - "ca", - "requestCert", - "secureContext", - "secureOptions", - "secureProtocol", - "sigalgs", - "ticketKeys", - "crl", - "clientCertEngine", - "dhparam", - "ecdhCurve", - "allowHalfOpen", - "handshakeTimeout", - "honorCipherOrder", - "keepAlive", - "keepAliveInitialDelay", - "maxVersion", - "minVersion", - "noDelay", - "pauseOnConnect", - "privateKeyEngine", - "privateKeyIdentifier", - "pskCallback", - "pskIdentityHint", - "sessionIdContext", - "sessionTimeout", - "ALPNProtocols", - "SNICallback", -]; - -const secureHttp2OptionKeys: ReadonlyArray< - "allowHTTP1" | "origins" | keyof tls.TlsOptions -> = ["allowHTTP1", "origins", ...secureHttp1OptionKeys]; - -const asyncToVoid = - ( - asyncCallback: HTTP1Handler | HTTP2Handler, - ): ((...args: Parameters) => void) => - (...args) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any - void asyncCallback(...(args as [any, any])); - }; - -/** - * Generic callback interface used by {@link HTTP1Handler} and {@link HTTP2Handler}. - */ -export type HTTP1Or2Handler = ( - req: TRequest, - res: TResponse, -) => Promise; - -/** - * The callback type for HTTP1 servers. - */ -export type HTTP1Handler = HTTP1Or2Handler< - http.IncomingMessage, - http.ServerResponse ->; - -/** - * The callback type for HTTP2 servers. - */ -export type HTTP2Handler = HTTP1Or2Handler< - http2.Http2ServerRequest, - http2.Http2ServerResponse ->; - -const doThrow = (msg: string) => { - throw new Error(msg); -}; - -const ensureObject = < - TObject extends object, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TFunction extends (...args: Array) => any, ->( - obj: TObject | TFunction, -): TObject => (typeof obj === "function" ? doThrow("Please pass object") : obj); diff --git a/server/yarn.lock b/server/yarn.lock index 27f659c..1c11c09 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -445,10 +445,10 @@ dependencies: "@ty-ras/endpoint" "^2.0.0" -"@ty-ras/server@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@ty-ras/server/-/server-2.1.1.tgz#ea13ddbe58f3603d6eab396277c1cf97c2171fe7" - integrity sha512-KAiuSEYwXKQIfMSIDCaGjuX/hy42oes/JnyG0blumMNwR0kSA6PYonDfg1ROtBPO9dGQZ/mWiWS3JKbZfMFKoQ== +"@ty-ras/server@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ty-ras/server/-/server-2.2.0.tgz#6a1dc54767241355be5202006127afea3a2ff602" + integrity sha512-rJwZj20uiO2tcS9Ln+5TfapdILDPcWxYbeyIDUjmbOmkv+FvMma+pVgKhozNP3iQj1mnKN2CmqgIhaxKw+bRBg== dependencies: "@ty-ras/endpoint" "^2.0.0" @@ -3500,11 +3500,6 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.2.tgz#7c094f753b6705ee4faee25c3c684ade52d66d99" integrity sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ== -ts-expect@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ts-expect/-/ts-expect-1.3.0.tgz#3f8d3966e0e22b5e2bb88337eb99db6816a4c1cf" - integrity sha512-e4g0EJtAjk64xgnFPD6kTBUtpnMVzDrMb12N1YZV0VvSlhnVT3SGxiYTLdGy8Q5cYHOIC/FAHmZ10eGrAguicQ== - ts-graphviz@^1.5.0: version "1.8.1" resolved "https://registry.yarnpkg.com/ts-graphviz/-/ts-graphviz-1.8.1.tgz#5d95e58120be8b571847331516327d4840cc44f7"