Mirror of https://github.com/roostorg/coop github.com/roostorg/coop
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 557ff54b2b435e5f1e789c6a8a4e1bebf2d7deb6 110 lines 4.0 kB view raw
1import { type RequestHandler } from 'express'; 2import { type ParamsDictionary, type Query } from 'express-serve-static-core'; 3import { type JsonObject, type JsonValue, type ReadonlyDeep } from 'type-fest'; 4 5import { type Dependencies } from '../iocContainer/index.js'; 6import { type JSONSchemaV4 } from './json-schema-types.js'; 7 8export type RequestHandlerWithBodies< 9 ReqBody extends JsonObject, 10 // @ts-ignore Silence error w/ hitting TS max recursion limit before the type param is actually bound. 11 ResBody extends ReadonlyDeep<JsonValue> | undefined, // undefined is used to indicate a 204 response 12> = RequestHandler< 13 ParamsDictionary, 14 ResBody, 15 ReqBody, 16 Query, 17 Record<string, unknown> 18>; 19 20export type Route< 21 ReqBody extends JsonObject, 22 ResBody extends ReadonlyDeep<JsonValue> | undefined, 23> = { 24 path: string; 25 method: 'get' | 'post' | 'patch' | 'delete'; 26 handler: ( 27 deps: Dependencies, 28 ) => 29 | RequestHandlerWithBodies<ReqBody, ResBody> 30 | RequestHandlerWithBodies<ReqBody, ResBody>[]; 31 name?: string; 32 bodySchema?: JSONSchemaV4<ReqBody>; 33}; 34 35type RouteOpts<ReqBody extends JsonObject> = Pick< 36 Route<ReqBody, ReadonlyDeep<JsonValue> | undefined>, 37 'name' | 'bodySchema' 38>; 39 40function makeRoute< 41 ReqBody extends JsonObject, 42 ResBody extends ReadonlyDeep<JsonValue> | undefined, 43>( 44 method: Route<ReqBody, ResBody>['method'], 45 path: Route<ReqBody, ResBody>['path'], 46 ...rest: 47 | [RouteOpts<ReqBody>, Route<ReqBody, ResBody>['handler']] 48 | [Route<ReqBody, ResBody>['handler']] 49) { 50 return { 51 method, 52 path, 53 ...(typeof rest[0] === 'function' 54 ? { handler: rest[0] } 55 : { ...rest[0], handler: rest[1] }), 56 }; 57} 58 59// Some helpers function for making route objects, to bring back the ergonomics 60// of app.get('/', ...handlers) while still getting the benefits of returned 61// route objects (whereas app[method]() just triggers the side effect of 62// registering a route with the internal express router). 63// We don't use partial application here to help TS. 64type MakeRouteBoundArgs< 65 ReqBody extends JsonObject, 66 ResBody extends ReadonlyDeep<JsonValue> | undefined, 67> = 68 | [ 69 path: Route<ReqBody, ResBody>['path'], 70 opts: RouteOpts<ReqBody>, 71 handler: Route<ReqBody, ResBody>['handler'], 72 ] 73 | [ 74 path: Route<ReqBody, ResBody>['path'], 75 handler: Route<ReqBody, ResBody>['handler'], 76 ]; 77 78export const route = { 79 // @ts-ignore Silence error w/ hitting TS max recursion limit before the type param is actually bound. 80 get<ResBody extends ReadonlyDeep<JsonValue> | undefined>( 81 ...args: MakeRouteBoundArgs<never, ResBody> 82 ) { 83 // any cast is to work around https://github.com/microsoft/TypeScript/issues/42508 84 // eslint-disable-next-line @typescript-eslint/no-explicit-any 85 return (makeRoute as any)('get', ...args) as Route<never, ResBody>; 86 }, 87 post< 88 ReqBody extends JsonObject, 89 ResBody extends ReadonlyDeep<JsonValue> | undefined, 90 >(...args: MakeRouteBoundArgs<ReqBody, ResBody>) { 91 // any cast is to work around https://github.com/microsoft/TypeScript/issues/42508 92 // eslint-disable-next-line @typescript-eslint/no-explicit-any 93 return (makeRoute as any)('post', ...args) as Route<ReqBody, ResBody>; 94 }, 95 patch< 96 ReqBody extends JsonObject, 97 ResBody extends ReadonlyDeep<JsonValue> | undefined, 98 >(...args: MakeRouteBoundArgs<ReqBody, ResBody>) { 99 // any cast is to work around https://github.com/microsoft/TypeScript/issues/42508 100 // eslint-disable-next-line @typescript-eslint/no-explicit-any 101 return (makeRoute as any)('patch', ...args) as Route<ReqBody, ResBody>; 102 }, 103 del<ResBody extends ReadonlyDeep<JsonValue> | undefined>( 104 ...args: MakeRouteBoundArgs<never, ResBody> 105 ) { 106 // any cast is to work around https://github.com/microsoft/TypeScript/issues/42508 107 // eslint-disable-next-line @typescript-eslint/no-explicit-any 108 return (makeRoute as any)('delete', ...args) as Route<never, ResBody>; 109 }, 110};