Scratch space for learning atproto app development
1import { Request, Response } from 'express' 2import { createHttpTerminator } from 'http-terminator' 3import { once } from 'node:events' 4import type { 5 IncomingMessage, 6 RequestListener, 7 ServerResponse, 8} from 'node:http' 9import { createServer } from 'node:http' 10 11export type NextFunction = (err?: unknown) => void 12 13export type Middleware< 14 Req extends IncomingMessage = IncomingMessage, 15 Res extends ServerResponse = ServerResponse, 16> = (req: Req, res: Res, next: NextFunction) => void 17 18export type Handler< 19 Req extends IncomingMessage = IncomingMessage, 20 Res extends ServerResponse = ServerResponse, 21> = (req: Req, res: Res) => unknown | Promise<unknown> 22/** 23 * Wraps a request handler middleware to ensure that `next` is called if it 24 * throws or returns a promise that rejects. 25 */ 26export function handler< 27 Req extends IncomingMessage = Request, 28 Res extends ServerResponse = Response, 29>(fn: Handler<Req, Res>): Middleware<Req, Res> { 30 return async (req, res, next) => { 31 try { 32 await fn(req, res) 33 } catch (err) { 34 next(err) 35 } 36 } 37} 38 39/** 40 * Create an HTTP server with the provided request listener, ensuring that it 41 * can bind the listening port, and returns a termination function that allows 42 * graceful termination of HTTP connections. 43 */ 44export async function startServer( 45 requestListener: RequestListener, 46 { 47 port, 48 gracefulTerminationTimeout, 49 }: { port?: number; gracefulTerminationTimeout?: number } = {}, 50) { 51 const server = createServer(requestListener) 52 const { terminate } = createHttpTerminator({ 53 gracefulTerminationTimeout, 54 server, 55 }) 56 server.listen(port) 57 await once(server, 'listening') 58 return { server, terminate } 59}