equipped 5.2.4 → 5.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/cjs/server/impls/base.cjs +11 -9
- package/dist/cjs/server/impls/base.cjs.map +1 -1
- package/dist/cjs/server/impls/base.min.cjs +1 -1
- package/dist/cjs/server/impls/base.min.cjs.map +1 -1
- package/dist/cjs/server/impls/express.cjs +3 -5
- package/dist/cjs/server/impls/express.cjs.map +1 -1
- package/dist/cjs/server/impls/express.min.cjs +1 -1
- package/dist/cjs/server/impls/express.min.cjs.map +1 -1
- package/dist/cjs/server/routes.cjs +1 -0
- package/dist/cjs/server/routes.cjs.map +1 -1
- package/dist/cjs/server/routes.min.cjs +1 -1
- package/dist/cjs/server/routes.min.cjs.map +1 -1
- package/dist/cjs/server/types.cjs +3 -1
- package/dist/cjs/server/types.cjs.map +1 -1
- package/dist/cjs/server/types.min.cjs +1 -1
- package/dist/cjs/server/types.min.cjs.map +1 -1
- package/dist/esm/server/impls/base.min.mjs +1 -1
- package/dist/esm/server/impls/base.min.mjs.map +1 -1
- package/dist/esm/server/impls/base.mjs +7 -5
- package/dist/esm/server/impls/base.mjs.map +1 -1
- package/dist/esm/server/impls/express.min.mjs +1 -1
- package/dist/esm/server/impls/express.min.mjs.map +1 -1
- package/dist/esm/server/impls/express.mjs +3 -5
- package/dist/esm/server/impls/express.mjs.map +1 -1
- package/dist/esm/server/routes.min.mjs +1 -1
- package/dist/esm/server/routes.min.mjs.map +1 -1
- package/dist/esm/server/routes.mjs +1 -0
- package/dist/esm/server/routes.mjs.map +1 -1
- package/dist/esm/server/types.min.mjs +1 -1
- package/dist/esm/server/types.min.mjs.map +1 -1
- package/dist/esm/server/types.mjs +3 -1
- package/dist/esm/server/types.mjs.map +1 -1
- package/dist/types/audit/index.d.ts +3 -4
- package/dist/types/{core-BWUHISEy.d.ts → core-BrkNSwvc.d.ts} +1 -1
- package/dist/types/{db-DEiImw1Z.d.ts → db-C8YY1yTO.d.ts} +1 -1
- package/dist/types/{db-vKGTnGlO.d.ts → db-Dj1SGto0.d.ts} +2 -2
- package/dist/types/dbs/index.d.ts +5 -6
- package/dist/types/errors/index.d.ts +3 -4
- package/dist/types/events/index.d.ts +2 -3
- package/dist/types/fastify-DLPUK3vD.d.ts +224 -0
- package/dist/types/index.d.ts +6 -7
- package/dist/types/instance/index.d.ts +6 -7
- package/dist/types/{kafka-DCpqW_YM.d.ts → kafka-Cf-TUJgv.d.ts} +12 -2
- package/dist/types/{requestError-MGJ-ojtC.d.ts → requestError-C2PNWUrt.d.ts} +12 -149
- package/dist/types/server/impls/base.js +7 -5
- package/dist/types/server/impls/express.js +3 -5
- package/dist/types/server/index.d.ts +9 -9
- package/dist/types/server/routes.js +1 -0
- package/dist/types/server/types.js +3 -1
- package/dist/types/{validationError-BbiTIoAh.d.ts → validationError-Bw8OYv5s.d.ts} +1 -1
- package/dist/types/validations/index.d.ts +2 -3
- package/package.json +1 -1
- package/dist/types/base-CfeyC14V.d.ts +0 -14
- package/dist/types/fastify-BizyaCY_.d.ts +0 -80
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/server/types.ts"],"names":["Methods","StatusCodes","makeMiddlewareHandler","cb","onSetup","makeMiddleware","args","makeErrorMiddleware"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/server/types.ts"],"names":["Methods","StatusCodes","makeMiddlewareHandler","cb","onSetup","makeMiddleware","args","makeResponseMiddleware","makeErrorMiddleware"],"mappings":"AAMO,+EAAMA,CAAAA,CAAU,CACtB,IAAA,CAAM,MAAA,CACN,GAAA,CAAK,KAAA,CACL,IAAA,CAAM,MAAA,CACN,GAAA,CAAK,KAAA,CACL,KAAA,CAAO,OAAA,CACP,MAAA,CAAQ,QAAA,CACR,OAAA,CAAS,SACV,CAAA,CAEaC,CAAAA,uBAAc,CAC1B,EAAA,CAAI,GAAA,CACJ,KAAA,CAAO,GAAA,CACP,UAAA,CAAY,GAAA,CACZ,gBAAA,CAAkB,GAAA,CAClB,aAAA,CAAe,GAAA,CACf,QAAA,CAAU,GAAA,CACV,eAAA,CAAiB,GAAA,CACjB,eAAA,CAAiB,GAAA,CACjB,YAAA,CAAc,GACf,CAAA,CAiHA,SAASC,CAAAA,CAA+DC,CAAAA,CAAQC,CAAAA,CAA2B,CAC1G,MAAO,CAAE,EAAA,CAAAD,CAAAA,CAAI,OAAA,CAAAC,CAAQ,CACtB,CAEO,MAAMC,CAAAA,CAAiB,CAAA,GAA0BC,CAAAA,CAAAA,EACvDJ,CAAAA,CAAsB,GAAGI,CAAI,CAAA,CACjBC,CAAAA,kCAAyB,CAAA,GAClCD,CAAAA,CAAAA,EACCJ,CAAAA,CAAsB,GAAGI,CAAI,CAAA,CACrBE,CAAAA,+BAAsB,CAAA,GAA0BF,CAAAA,CAAAA,EAC5DJ,CAAAA,CAAsB,GAAGI,CAAI,CAAA,CAAA,8IAAA","file":"/home/runner/work/equipped/equipped/dist/cjs/server/types.min.cjs","sourcesContent":["import type { IsInTypeList, Pipe, PipeInput, PipeOutput, Prettify } from 'valleyed'\n\nimport type { RequestError } from '../errors'\nimport type { Enum } from '../types'\nimport type { Request, Response } from './requests'\n\nexport const Methods = {\n\thead: 'head',\n\tget: 'get',\n\tpost: 'post',\n\tput: 'put',\n\tpatch: 'patch',\n\tdelete: 'delete',\n\toptions: 'options',\n} as const\n\nexport const StatusCodes = {\n\tOk: 200,\n\tFound: 302,\n\tBadRequest: 400,\n\tNotAuthenticated: 401,\n\tNotAuthorized: 403,\n\tNotFound: 404,\n\tValidationError: 422,\n\tTooManyRequests: 429,\n\tTokenExpired: 461,\n} as const\n\nexport type MethodsEnum = Enum<typeof Methods>\nexport type StatusCodesEnum = Enum<typeof StatusCodes>\n\nexport type DefaultHeaders = Record<string, ArrayOrValue<string>>\nexport type DefaultCookies = Record<string, string | undefined>\n\ntype ArrayOrValue<T> = T | T[] | undefined\n\nexport type IncomingFile = {\n\tname: string\n\ttype: string\n\tsize: number\n\tisTruncated: boolean\n\tdata: Buffer\n\tduration: number\n}\n\nexport type RouteDef = {\n\tparams?: Pipe<Record<string, ArrayOrValue<string>>, Record<string, ArrayOrValue<string>>>\n\tquery?: Pipe<Record<string, ArrayOrValue<unknown>>, Record<string, ArrayOrValue<unknown>>>\n\theaders?: Pipe<DefaultHeaders, DefaultHeaders>\n\tcookies?: Pipe<DefaultCookies, DefaultCookies>\n\tbody?: Pipe<Record<string, unknown>, Record<string, unknown>>\n\tresponse?: Pipe<unknown, unknown>\n\tresponseHeaders?: Pipe<DefaultHeaders, DefaultHeaders>\n\tresponseCookies?: Pipe<DefaultCookies, DefaultCookies>\n\tdefaultStatusCode?: StatusCodesEnum\n\tdefaultContentType?: string\n}\n\ntype RouteGroup = { name: string; description?: string }\ntype HandlerSetup<T extends RouteDef> = (route: Route<T>) => void\n\nexport type RouteConfig<T extends RouteDef> = {\n\tmiddlewares?: ReturnType<typeof makeMiddleware<RouteDef>>[]\n\tresponseMiddlewares?: ReturnType<typeof makeResponseMiddleware<RouteDef>>[]\n\tonError?: ReturnType<typeof makeErrorMiddleware<RouteDef>>\n\tgroups?: (RouteGroup | RouteGroup['name'])[]\n\ttitle?: string\n\tdescriptions?: string[]\n\tsecurity?: Record<string, string[]>[]\n\tschema?: T\n\thide?: boolean\n}\n\nexport type RouterConfig<T extends RouteDef> = RouteConfig<T> & { path: string }\nexport type Route<T extends RouteDef> = RouteConfig<T> & {\n\tpath: string\n\tmethod: MethodsEnum\n\thandler: RouteDefHandler<T>\n}\n\ntype GetApiPart<T extends RouteDef, K extends keyof RouteDef> = NonNullable<IsInTypeList<T[K], [unknown]> extends true ? RouteDef[K] : T[K]>\n\ntype ArePipes<A, B> = A extends Pipe<any, any> ? (B extends Pipe<any, any> ? true : false) : false\ntype Compare<K extends keyof RouteDef, A, B> =\n\tIsInTypeList<B, [unknown]> extends true\n\t\t? A\n\t\t: IsInTypeList<A, [unknown]> extends true\n\t\t\t? B\n\t\t\t: K extends `default${string}` | 'context'\n\t\t\t\t? B\n\t\t\t\t: ArePipes<A, B> extends true\n\t\t\t\t\t? Pipe<PipeInput<A> & PipeInput<B>, PipeOutput<A> & PipeOutput<B>>\n\t\t\t\t\t: B\n\nexport type MergeRouteDefs<A extends RouteDef, B extends RouteDef> = {\n\t[K in keyof RouteDef]: Compare<K, A[K], B[K]>\n}\n\nexport type RouteDefToReqRes<T extends RouteDef> = Prettify<{\n\tbody: PipeOutput<GetApiPart<T, 'body'>>\n\tparams: PipeOutput<GetApiPart<T, 'params'>>\n\trequestHeaders: PipeOutput<GetApiPart<T, 'headers'>>\n\trequestCookies: PipeOutput<GetApiPart<T, 'cookies'>>\n\tquery: PipeOutput<GetApiPart<T, 'query'>>\n\tresponse: PipeOutput<GetApiPart<T, 'response'>>\n\tresponseHeaders: PipeOutput<GetApiPart<T, 'responseHeaders'>>\n\tresponseCookies: PipeOutput<GetApiPart<T, 'responseCookies'>>\n\tstatusCode: GetApiPart<T, 'defaultStatusCode'>\n\tcontentType: GetApiPart<T, 'defaultContentType'>\n}>\n\ntype Awaitable<T> = Promise<T> | T\ntype Res<T extends RouteDefToReqRes<any>> = Awaitable<\n\tIsInTypeList<T['statusCode'], [StatusCodesEnum, 200]> extends true\n\t\t? IsInTypeList<T['responseHeaders'], [DefaultHeaders]> extends true\n\t\t\t? IsInTypeList<T['responseCookies'], [DefaultCookies]> extends true\n\t\t\t\t? Response<T> | T['response']\n\t\t\t\t: Response<T>\n\t\t\t: Response<T>\n\t\t: Response<T>\n>\nexport type RouteDefHandler<Def extends RouteDef> = (req: Request<RouteDefToReqRes<Def>>) => Res<RouteDefToReqRes<Def>>\ntype RouteMiddlewareHandler<_Def extends RouteDef> = (req: Request<RouteDefToReqRes<RouteDef>>) => Awaitable<void>\ntype RouteResponseMiddlewareHandler<_Def extends RouteDef> = (\n\treq: Request<RouteDefToReqRes<RouteDef>>,\n\tres: Response<RouteDefToReqRes<RouteDef>>,\n) => Awaitable<void>\ntype ErrorHandler<Def extends RouteDef> = (\n\treq: Request<RouteDefToReqRes<Def>>,\n\terr: Error,\n) => Res<\n\tOmit<RouteDefToReqRes<Def>, 'response' | 'statusCode' | 'responseHeaders' | 'responseCookies'> & {\n\t\tresponse: RequestError['serializedErrors']\n\t\tstatusCode: RequestError['statusCode']\n\t\tresponseHeaders: DefaultHeaders\n\t\tresponseCookies: DefaultCookies\n\t}\n>\n\nfunction makeMiddlewareHandler<Cb extends Function, T extends RouteDef>(cb: Cb, onSetup?: HandlerSetup<T>) {\n\treturn { cb, onSetup }\n}\n\nexport const makeMiddleware = <Def extends RouteDef>(...args: Parameters<typeof makeMiddlewareHandler<RouteMiddlewareHandler<Def>, Def>>) =>\n\tmakeMiddlewareHandler(...args)\nexport const makeResponseMiddleware = <Def extends RouteDef>(\n\t...args: Parameters<typeof makeMiddlewareHandler<RouteResponseMiddlewareHandler<Def>, Def>>\n) => makeMiddlewareHandler(...args)\nexport const makeErrorMiddleware = <Def extends RouteDef>(...args: Parameters<typeof makeMiddlewareHandler<ErrorHandler<Def>, Def>>) =>\n\tmakeMiddlewareHandler(...args)\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import"@fastify/cors";import"cors";import{Server as O}from"socket.io";import j from"supertest";import{PipeError as $,v as a}from"valleyed";import{EquippedError as
|
|
1
|
+
import"@fastify/cors";import"cors";import{Server as O}from"socket.io";import j from"supertest";import{PipeError as $,v as a}from"valleyed";import{EquippedError as q,NotFoundError as D,RequestError as T}from "../../errors/index.min.mjs";import{Instance as b}from "../../instance/index.min.mjs";import{pipeErrorToValidationError as P}from "../../validations/index.min.mjs";import{requestLocalStorage as H,responseLocalStorage as M}from "../../validations/valleyed.min.mjs";import{OpenApi as A}from "../openapi.min.mjs";import{Response as h}from "../requests.min.mjs";import"../routes";import{SocketEmitter as V}from "../sockets.min.mjs";import{Methods as f,StatusCodes as R}from "../types.min.mjs";const x=Object.entries(R).filter(([,k])=>k>399).map(([k,r])=>({status:r,contentType:"application/json",pipe:a.meta(a.array(a.object({message:a.string(),field:a.optional(a.string())})),{$refId:`Errors.${k}Response`,description:`${k} Response`})}));class Z{constructor(r,t,p){this.config=t;this.implementations=p;this.server=r,this.#e=new A(t);const c=new O(r,{cors:this.cors});this.socket=new V(c,t),this.addRouter(this.#e.router())}#t=[];#s=new Map;#e;socket;server;get cors(){return{origin:this.config.cors?.origin?(r,t)=>t(null,!0):this.config.cors?.origin,methods:(this.config.cors?.methods??Object.values(f)).filter(r=>r!==f.options).map(r=>r.toUpperCase()),credentials:this.config.cors?.credentials}}addRouter(...r){r.map(t=>t.routes).forEach(t=>this.addRoute(...t))}addRoute(...r){r.forEach(t=>{this.#t.push(async()=>{const{method:p,path:c,schema:o={},onError:d,middlewares:u=[],responseMiddlewares:m=[]}=t,y=`(${p.toUpperCase()}) ${this.#e.cleanPath(c)}`;if(this.#s.get(y))throw new q(`Route key ${y} already registered. All route keys must be unique`,{route:t,key:y});u.forEach(l=>l.onSetup?.(t)),d?.onSetup?.(t),m.forEach(l=>l.onSetup?.(t));const{validateRequest:E,validateResponse:v,jsonSchema:g}=this.#o(p,o);this.#s.set(y,!0),await this.#e.register(t,g),this.implementations.registerRoute(p,this.#e.cleanPath(c),async(l,w)=>{const e=await E(await this.implementations.parseRequest(l));try{for(const n of u)await n.cb(e);const s=await t.handler(e),i=s instanceof h?s:new h({body:s,status:R.Ok,headers:{},piped:!1});for(const n of m)await n.cb(e,i);return await this.implementations.handleResponse(w,await v(i))}catch(s){if(d?.cb){const i=await d.cb(e,s),n=i instanceof h?i:new h({body:i,status:R.BadRequest,headers:{}});return await this.implementations.handleResponse(w,await v(n))}throw s}})})})}#o(r,t){const p=t?.defaultStatusCode??R.Ok,c=t?.defaultContentType??"application/json";let o=p,d=c;const u={response:{},request:{}},m={},y={};[{key:"params",type:"request"},{key:"headers",type:"request"},{key:"cookies",type:"request"},{key:"query",type:"request"},{key:"body",type:"request",skip:![f.post,f.put,f.patch].includes(r)},{key:"response",type:"response"},{key:"responseHeaders",type:"response"},{key:"responseCookies",type:"response"}].forEach(e=>{const s=t[e.key]??a.any();if(!e.skip&&(e.type==="request"&&(m[e.key]=s,u.request[e.key]=a.schema(s)),e.type==="response")){const i=x.concat({status:p,contentType:d,pipe:s});y[e.key]=a.any().pipe(n=>{const S=i.find(C=>C.status===o)?.pipe;if(!S)throw $.root(`schema not defined for status code: ${o}`,n);return a.assert(S,n)}),u.response[e.key]=i.map(n=>({status:n.status,contentType:n.contentType,schema:a.schema(n.pipe)}))}});const v=a.object(m);a.compile(v,{allErrors:!0});const g=a.object(y);return a.compile(g,{allErrors:!0}),{jsonSchema:u,validateRequest:async e=>{if(!Object.keys(m))return e;const s=H.run(e,()=>a.validate(v,{params:e.params,headers:e.headers,query:e.query,body:e.body,cookies:e.cookies}));if(!s.valid)throw P(s.error);return e.params=s.value.params,e.headers=s.value.headers,e.query=s.value.query,e.body=s.value.body,e.cookies=s.value.cookies,e},validateResponse:async e=>{if(!Object.keys(y))return e;o=e.status,d=e.contentType;const s=M.run(e,()=>a.validate(g,{responseHeaders:e.headers,responseCookies:Object.fromEntries(Object.entries(e.cookies).map(([i,n])=>[i,n.value])),response:e.body}));if(!s.valid)throw P(s.error);return e.body=s.value.response,e.headers=s.value.responseHeaders,e.cookieValues=s.value.responseCookies,e}}}test(){return j(this.server)}async start(){const r=this.config.port,t=b.get(),{app:p}=t.settings;this.config.healthPath&&this.addRoute({method:f.get,path:this.config.healthPath,handler:async o=>o.res({body:`${t.id}(${p.name}) service running`,contentType:"text/plain"})}),await Promise.all(this.#t.map(o=>o())),this.implementations.registerNotFoundHandler(async o=>{const d=await this.implementations.parseRequest(o);throw new D(`Route ${d.path} not found`)}),this.implementations.registerErrorHandler(async(o,d,u)=>{o instanceof q||b.get().log.error({error:o},"Uncaught error in route handler");const m=o instanceof T?new h({body:o.serializedErrors,status:o.statusCode}):o instanceof q?new h({body:[{message:o.message}],status:R.BadRequest}):new h({body:[{message:"Something went wrong",data:o.message}],status:R.BadRequest});return await this.implementations.handleResponse(u,m)});const c=await this.implementations.start(r);return c&&b.get().log.info(`${t.id}(${p.name}) service listening on port ${r}`),c}}export{Z as Server};
|
|
2
2
|
//# sourceMappingURL=base.min.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/server/impls/base.ts"],"sourcesContent":["import type http from 'node:http'\n\nimport { type FastifyCorsOptions } from '@fastify/cors'\nimport { type CorsOptions } from 'cors'\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { type Pipe, PipeError, v } from 'valleyed'\n\nimport { EquippedError, NotFoundError, RequestError } from '../../errors'\nimport { Instance } from '../../instance'\nimport { pipeErrorToValidationError } from '../../validations'\nimport { requestLocalStorage, responseLocalStorage } from '../../validations/valleyed'\nimport { OpenApi, type OpenApiSchemaDef } from '../openapi'\nimport type { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, type MethodsEnum, type Route, type RouteDef, StatusCodes } from '../types'\n\ntype RequestValidator = (req: Request<any>) => Promise<Request<any>>\ntype ResponseValidator = (res: Response<any>) => Promise<Response<any>>\n\nconst errorsSchemas = Object.entries(StatusCodes)\n\t.filter(([, value]) => value > 399)\n\t.map(([key, value]) => ({\n\t\tstatus: value,\n\t\tcontentType: 'application/json',\n\t\tpipe: v.meta(v.array(v.object({ message: v.string(), field: v.optional(v.string()) })), {\n\t\t\t$refId: `Errors.${key}Response`,\n\t\t\tdescription: `${key} Response`,\n\t\t}) as Pipe<any, any>,\n\t}))\n\nexport abstract class Server<Req = any, Res = any> {\n\t#queue: (() => void | Promise<void>)[] = []\n\t#routesByKey = new Map<string, boolean>()\n\t#openapi: OpenApi\n\tsocket: SocketEmitter\n\tprotected server: http.Server\n\tprotected get cors(): CorsOptions & FastifyCorsOptions {\n\t\treturn {\n\t\t\torigin: this.config.cors?.origin ? (_, cb) => cb(null, true) : this.config.cors?.origin,\n\t\t\tmethods: (this.config.cors?.methods ?? Object.values(Methods)).filter((m) => m !== Methods.options).map((m) => m.toUpperCase()),\n\t\t\tcredentials: this.config.cors?.credentials,\n\t\t}\n\t}\n\n\tconstructor(\n\t\tserver: http.Server,\n\t\tprivate config: ServerConfig,\n\t\tprivate implementations: {\n\t\t\tparseRequest: (req: Req) => Promise<Request<any>>\n\t\t\thandleResponse: (res: Res, response: Response<any>) => Promise<void>\n\t\t\tregisterRoute: (method: MethodsEnum, path: string, cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterErrorHandler: (cb: (error: Error, req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterNotFoundHandler: (cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tstart: (port: number) => Promise<boolean>\n\t\t},\n\t) {\n\t\tthis.server = server\n\t\tthis.#openapi = new OpenApi(config)\n\t\tconst socketInstance = new SocketServer(server, { cors: this.cors })\n\t\tthis.socket = new SocketEmitter(socketInstance, config)\n\t\tthis.addRouter(this.#openapi.router())\n\t}\n\n\taddRouter(...routers: Router<any>[]) {\n\t\trouters.map((router) => router.routes).forEach((routes) => this.addRoute(...routes))\n\t}\n\n\taddRoute<T extends RouteDef>(...routes: Route<T>[]) {\n\t\troutes.forEach((route) => {\n\t\t\tthis.#queue.push(async () => {\n\t\t\t\tconst { method, path, schema = {}, onError, middlewares = [] } = route\n\n\t\t\t\tconst key = `(${method.toUpperCase()}) ${this.#openapi.cleanPath(path)}`\n\t\t\t\tif (this.#routesByKey.get(key))\n\t\t\t\t\tthrow new EquippedError(`Route key ${key} already registered. All route keys must be unique`, { route, key })\n\n\t\t\t\tmiddlewares.forEach((m) => m.onSetup?.(route as any))\n\t\t\t\tonError?.onSetup?.(route as any)\n\n\t\t\t\tconst { validateRequest, validateResponse, jsonSchema } = this.#resolveSchema(method, schema)\n\n\t\t\t\tthis.#routesByKey.set(key, true)\n\t\t\t\tawait this.#openapi.register(route, jsonSchema)\n\t\t\t\tthis.implementations.registerRoute(method, this.#openapi.cleanPath(path), async (req: Req, res: Res) => {\n\t\t\t\t\tconst request = await validateRequest(await this.implementations.parseRequest(req))\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor (const middleware of middlewares) await middleware.cb(request, this.config)\n\t\t\t\t\t\tconst rawRes = await route.handler(request, this.config)\n\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\trawRes instanceof Response\n\t\t\t\t\t\t\t\t? rawRes\n\t\t\t\t\t\t\t\t: new Response({ body: rawRes, status: StatusCodes.Ok, headers: {}, piped: false })\n\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tif (onError?.cb) {\n\t\t\t\t\t\t\tconst rawResponse = await onError.cb(request, this.config, error as Error)\n\t\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\t\trawResponse instanceof Response\n\t\t\t\t\t\t\t\t\t? rawResponse\n\t\t\t\t\t\t\t\t\t: new Response({ body: rawResponse, status: StatusCodes.BadRequest, headers: {} })\n\t\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t}\n\n\t#resolveSchema(method: MethodsEnum, schema: RouteDef) {\n\t\tconst defaultStatusCode = schema?.defaultStatusCode ?? StatusCodes.Ok\n\t\tconst defaultContentType = schema?.defaultContentType ?? 'application/json'\n\t\tlet status = defaultStatusCode\n\t\tlet contentType = defaultContentType\n\t\tconst jsonSchema: OpenApiSchemaDef = { response: {}, request: {} }\n\t\tconst requestPipeDefs: Pick<RouteDef, 'body' | 'headers' | 'query' | 'params' | 'cookies'> = {}\n\t\tconst responsePipeDefs: Pick<RouteDef, 'response' | 'responseHeaders' | 'responseCookies'> = {}\n\n\t\tconst defs: {\n\t\t\tkey: Exclude<keyof RouteDef, `default${string}` | 'context'>\n\t\t\ttype: keyof OpenApiSchemaDef\n\t\t\tskip?: boolean\n\t\t}[] = [\n\t\t\t{ key: 'params', type: 'request' },\n\t\t\t{ key: 'headers', type: 'request' },\n\t\t\t{ key: 'cookies', type: 'request' },\n\t\t\t{ key: 'query', type: 'request' },\n\t\t\t{ key: 'body', type: 'request', skip: !(<MethodsEnum[]>[Methods.post, Methods.put, Methods.patch]).includes(method) },\n\t\t\t{ key: 'response', type: 'response' },\n\t\t\t{ key: 'responseHeaders', type: 'response' },\n\t\t\t{ key: 'responseCookies', type: 'response' },\n\t\t]\n\t\tdefs.forEach((def) => {\n\t\t\tconst pipe = schema[def.key] ?? v.any()\n\t\t\tif (def.skip) return\n\n\t\t\tif (def.type === 'request') {\n\t\t\t\trequestPipeDefs[def.key] = pipe\n\t\t\t\tjsonSchema.request[def.key as keyof typeof jsonSchema.request] = v.schema(pipe)\n\t\t\t}\n\t\t\tif (def.type === 'response') {\n\t\t\t\tconst pipeRecords = errorsSchemas.concat({ status: defaultStatusCode, contentType, pipe })\n\t\t\t\tresponsePipeDefs[def.key] = v.any().pipe((input) => {\n\t\t\t\t\tconst p = pipeRecords.find((r) => r.status === status)?.pipe\n\t\t\t\t\tif (!p) throw PipeError.root(`schema not defined for status code: ${status}`, input)\n\t\t\t\t\treturn v.assert(p, input)\n\t\t\t\t})\n\t\t\t\tjsonSchema.response[def.key as keyof typeof jsonSchema.response] = pipeRecords.map((record) => ({\n\t\t\t\t\tstatus: record.status,\n\t\t\t\t\tcontentType: record.contentType,\n\t\t\t\t\tschema: v.schema(record.pipe),\n\t\t\t\t}))\n\t\t\t}\n\t\t})\n\t\tconst requestPipe = v.object(requestPipeDefs)\n\t\tv.compile(requestPipe, { allErrors: true })\n\t\tconst responsePipe = v.object(responsePipeDefs)\n\t\tv.compile(responsePipe, { allErrors: true })\n\t\tconst validateRequest: RequestValidator = async (request) => {\n\t\t\tif (!Object.keys(requestPipeDefs)) return request\n\t\t\tconst validity = requestLocalStorage.run(request, () =>\n\t\t\t\tv.validate(requestPipe, {\n\t\t\t\t\tparams: request.params,\n\t\t\t\t\theaders: request.headers,\n\t\t\t\t\tquery: request.query,\n\t\t\t\t\tbody: request.body,\n\t\t\t\t\tcookies: request.cookies,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\trequest.params = validity.value.params!\n\t\t\trequest.headers = validity.value.headers!\n\t\t\trequest.query = validity.value.query!\n\t\t\trequest.body = validity.value.body!\n\t\t\trequest.cookies = validity.value.cookies!\n\t\t\treturn request\n\t\t}\n\t\tconst validateResponse: ResponseValidator = async (response) => {\n\t\t\tif (!Object.keys(responsePipeDefs)) return response\n\t\t\tstatus = response.status\n\t\t\tcontentType = response.contentType\n\n\t\t\tconst validity = responseLocalStorage.run(response, () =>\n\t\t\t\tv.validate(responsePipe, {\n\t\t\t\t\tresponseHeaders: response.headers,\n\t\t\t\t\tresponseCookies: Object.fromEntries(Object.entries(response.cookies).map(([key, val]) => [key, val.value] as const)),\n\t\t\t\t\tresponse: response.body,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\tresponse.body = validity.value.response!\n\t\t\tresponse.headers = validity.value.responseHeaders!\n\t\t\tresponse.cookieValues = validity.value.responseCookies!\n\t\t\treturn response\n\t\t}\n\t\treturn {\n\t\t\tjsonSchema,\n\t\t\tvalidateRequest,\n\t\t\tvalidateResponse,\n\t\t}\n\t}\n\n\ttest() {\n\t\treturn supertest(this.server)\n\t}\n\n\tasync start() {\n\t\tconst port = this.config.port\n\t\tconst instance = Instance.get()\n\t\tconst { app } = instance.settings\n\t\tif (this.config.healthPath)\n\t\t\tthis.addRoute({\n\t\t\t\tmethod: Methods.get,\n\t\t\t\tpath: this.config.healthPath,\n\t\t\t\thandler: async (req) =>\n\t\t\t\t\treq.res({\n\t\t\t\t\t\tbody: `${instance.id}(${app.name}) service running`,\n\t\t\t\t\t\tcontentType: 'text/plain',\n\t\t\t\t\t}),\n\t\t\t})\n\n\t\tthis.implementations.registerNotFoundHandler(async (req) => {\n\t\t\tconst request = await this.implementations.parseRequest(req)\n\t\t\tthrow new NotFoundError(`Route ${request.path} not found`)\n\t\t})\n\t\tthis.implementations.registerErrorHandler(async (error, _, res) => {\n\t\t\tif (!(error instanceof EquippedError)) Instance.get().log.error({ error }, 'Uncaught error in route handler')\n\t\t\tconst response =\n\t\t\t\terror instanceof RequestError\n\t\t\t\t\t? new Response({\n\t\t\t\t\t\t\tbody: error.serializedErrors,\n\t\t\t\t\t\t\tstatus: error.statusCode,\n\t\t\t\t\t\t})\n\t\t\t\t\t: error instanceof EquippedError\n\t\t\t\t\t\t? new Response({\n\t\t\t\t\t\t\t\tbody: [{ message: error.message }],\n\t\t\t\t\t\t\t\tstatus: StatusCodes.BadRequest,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: new Response({\n\t\t\t\t\t\t\t\tbody: [{ message: 'Something went wrong', data: error.message }],\n\t\t\t\t\t\t\t\tstatus: StatusCodes.BadRequest,\n\t\t\t\t\t\t\t})\n\t\t\treturn await this.implementations.handleResponse(res, response)\n\t\t})\n\n\t\tawait Promise.all(this.#queue.map((cb) => cb()))\n\t\tconst started = await this.implementations.start(port)\n\t\tif (started) Instance.get().log.info(`${instance.id}(${app.name}) service listening on port ${port}`)\n\t\treturn started\n\t}\n}\n"],"mappings":"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","names":["SocketServer","supertest","PipeError","v","EquippedError","NotFoundError","RequestError","Instance","pipeErrorToValidationError","requestLocalStorage","responseLocalStorage","OpenApi","Response","SocketEmitter","Methods","StatusCodes","errorsSchemas","value","key","Server","server","config","implementations","#openapi","socketInstance","#queue","#routesByKey","_","cb","m","routers","router","routes","route","method","path","schema","onError","middlewares","validateRequest","validateResponse","jsonSchema","#resolveSchema","req","res","request","middleware","rawRes","response","error","rawResponse","defaultStatusCode","defaultContentType","status","contentType","requestPipeDefs","responsePipeDefs","def","pipe","pipeRecords","input","p","r","record","requestPipe","responsePipe","validity","val","port","instance","app","started"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/server/impls/base.ts"],"sourcesContent":["import type http from 'node:http'\n\nimport { type FastifyCorsOptions } from '@fastify/cors'\nimport { type CorsOptions } from 'cors'\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { type Pipe, PipeError, v } from 'valleyed'\n\nimport { EquippedError, NotFoundError, RequestError } from '../../errors'\nimport { Instance } from '../../instance'\nimport { pipeErrorToValidationError } from '../../validations'\nimport { requestLocalStorage, responseLocalStorage } from '../../validations/valleyed'\nimport { OpenApi, type OpenApiSchemaDef } from '../openapi'\nimport type { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, type MethodsEnum, type Route, type RouteDef, StatusCodes } from '../types'\n\ntype RequestValidator = (req: Request<any>) => Promise<Request<any>>\ntype ResponseValidator = (res: Response<any>) => Promise<Response<any>>\n\nconst errorsSchemas = Object.entries(StatusCodes)\n\t.filter(([, value]) => value > 399)\n\t.map(([key, value]) => ({\n\t\tstatus: value,\n\t\tcontentType: 'application/json',\n\t\tpipe: v.meta(v.array(v.object({ message: v.string(), field: v.optional(v.string()) })), {\n\t\t\t$refId: `Errors.${key}Response`,\n\t\t\tdescription: `${key} Response`,\n\t\t}) as Pipe<any, any>,\n\t}))\n\nexport abstract class Server<Req = any, Res = any> {\n\t#queue: (() => void | Promise<void>)[] = []\n\t#routesByKey = new Map<string, boolean>()\n\t#openapi: OpenApi\n\tsocket: SocketEmitter\n\tprotected server: http.Server\n\tprotected get cors(): CorsOptions & FastifyCorsOptions {\n\t\treturn {\n\t\t\torigin: this.config.cors?.origin ? (_, cb) => cb(null, true) : this.config.cors?.origin,\n\t\t\tmethods: (this.config.cors?.methods ?? Object.values(Methods)).filter((m) => m !== Methods.options).map((m) => m.toUpperCase()),\n\t\t\tcredentials: this.config.cors?.credentials,\n\t\t}\n\t}\n\n\tconstructor(\n\t\tserver: http.Server,\n\t\tprivate config: ServerConfig,\n\t\tprivate implementations: {\n\t\t\tparseRequest: (req: Req) => Promise<Request<any>>\n\t\t\thandleResponse: (res: Res, response: Response<any>) => Promise<void>\n\t\t\tregisterRoute: (method: MethodsEnum, path: string, cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterErrorHandler: (cb: (error: Error, req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterNotFoundHandler: (cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tstart: (port: number) => Promise<boolean>\n\t\t},\n\t) {\n\t\tthis.server = server\n\t\tthis.#openapi = new OpenApi(config)\n\t\tconst socketInstance = new SocketServer(server, { cors: this.cors })\n\t\tthis.socket = new SocketEmitter(socketInstance, config)\n\t\tthis.addRouter(this.#openapi.router())\n\t}\n\n\taddRouter(...routers: Router<any>[]) {\n\t\trouters.map((router) => router.routes).forEach((routes) => this.addRoute(...routes))\n\t}\n\n\taddRoute<T extends RouteDef>(...routes: Route<T>[]) {\n\t\troutes.forEach((route) => {\n\t\t\tthis.#queue.push(async () => {\n\t\t\t\tconst { method, path, schema = {}, onError, middlewares = [], responseMiddlewares = [] } = route\n\n\t\t\t\tconst key = `(${method.toUpperCase()}) ${this.#openapi.cleanPath(path)}`\n\t\t\t\tif (this.#routesByKey.get(key))\n\t\t\t\t\tthrow new EquippedError(`Route key ${key} already registered. All route keys must be unique`, { route, key })\n\n\t\t\t\tmiddlewares.forEach((m) => m.onSetup?.(route as any))\n\t\t\t\tonError?.onSetup?.(route as any)\n\t\t\t\tresponseMiddlewares.forEach((m) => m.onSetup?.(route as any))\n\n\t\t\t\tconst { validateRequest, validateResponse, jsonSchema } = this.#resolveSchema(method, schema)\n\n\t\t\t\tthis.#routesByKey.set(key, true)\n\t\t\t\tawait this.#openapi.register(route, jsonSchema)\n\t\t\t\tthis.implementations.registerRoute(method, this.#openapi.cleanPath(path), async (req: Req, res: Res) => {\n\t\t\t\t\tconst request = await validateRequest(await this.implementations.parseRequest(req))\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor (const middleware of middlewares) await middleware.cb(request)\n\t\t\t\t\t\tconst rawRes = await route.handler(request)\n\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\trawRes instanceof Response\n\t\t\t\t\t\t\t\t? rawRes\n\t\t\t\t\t\t\t\t: new Response({ body: rawRes, status: StatusCodes.Ok, headers: {}, piped: false })\n\t\t\t\t\t\tfor (const middleware of responseMiddlewares) await middleware.cb(request, response)\n\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tif (onError?.cb) {\n\t\t\t\t\t\t\tconst rawResponse = await onError.cb(request, error as Error)\n\t\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\t\trawResponse instanceof Response\n\t\t\t\t\t\t\t\t\t? rawResponse\n\t\t\t\t\t\t\t\t\t: new Response({ body: rawResponse, status: StatusCodes.BadRequest, headers: {} })\n\t\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t}\n\n\t#resolveSchema(method: MethodsEnum, schema: RouteDef) {\n\t\tconst defaultStatusCode = schema?.defaultStatusCode ?? StatusCodes.Ok\n\t\tconst defaultContentType = schema?.defaultContentType ?? 'application/json'\n\t\tlet status = defaultStatusCode\n\t\tlet contentType = defaultContentType\n\t\tconst jsonSchema: OpenApiSchemaDef = { response: {}, request: {} }\n\t\tconst requestPipeDefs: Pick<RouteDef, 'body' | 'headers' | 'query' | 'params' | 'cookies'> = {}\n\t\tconst responsePipeDefs: Pick<RouteDef, 'response' | 'responseHeaders' | 'responseCookies'> = {}\n\n\t\tconst defs: {\n\t\t\tkey: Exclude<keyof RouteDef, `default${string}` | 'context'>\n\t\t\ttype: keyof OpenApiSchemaDef\n\t\t\tskip?: boolean\n\t\t}[] = [\n\t\t\t{ key: 'params', type: 'request' },\n\t\t\t{ key: 'headers', type: 'request' },\n\t\t\t{ key: 'cookies', type: 'request' },\n\t\t\t{ key: 'query', type: 'request' },\n\t\t\t{ key: 'body', type: 'request', skip: !(<MethodsEnum[]>[Methods.post, Methods.put, Methods.patch]).includes(method) },\n\t\t\t{ key: 'response', type: 'response' },\n\t\t\t{ key: 'responseHeaders', type: 'response' },\n\t\t\t{ key: 'responseCookies', type: 'response' },\n\t\t]\n\t\tdefs.forEach((def) => {\n\t\t\tconst pipe = schema[def.key] ?? v.any()\n\t\t\tif (def.skip) return\n\n\t\t\tif (def.type === 'request') {\n\t\t\t\trequestPipeDefs[def.key] = pipe\n\t\t\t\tjsonSchema.request[def.key as keyof typeof jsonSchema.request] = v.schema(pipe)\n\t\t\t}\n\t\t\tif (def.type === 'response') {\n\t\t\t\tconst pipeRecords = errorsSchemas.concat({ status: defaultStatusCode, contentType, pipe })\n\t\t\t\tresponsePipeDefs[def.key] = v.any().pipe((input) => {\n\t\t\t\t\tconst p = pipeRecords.find((r) => r.status === status)?.pipe\n\t\t\t\t\tif (!p) throw PipeError.root(`schema not defined for status code: ${status}`, input)\n\t\t\t\t\treturn v.assert(p, input)\n\t\t\t\t})\n\t\t\t\tjsonSchema.response[def.key as keyof typeof jsonSchema.response] = pipeRecords.map((record) => ({\n\t\t\t\t\tstatus: record.status,\n\t\t\t\t\tcontentType: record.contentType,\n\t\t\t\t\tschema: v.schema(record.pipe),\n\t\t\t\t}))\n\t\t\t}\n\t\t})\n\t\tconst requestPipe = v.object(requestPipeDefs)\n\t\tv.compile(requestPipe, { allErrors: true })\n\t\tconst responsePipe = v.object(responsePipeDefs)\n\t\tv.compile(responsePipe, { allErrors: true })\n\t\tconst validateRequest: RequestValidator = async (request) => {\n\t\t\tif (!Object.keys(requestPipeDefs)) return request\n\t\t\tconst validity = requestLocalStorage.run(request, () =>\n\t\t\t\tv.validate(requestPipe, {\n\t\t\t\t\tparams: request.params,\n\t\t\t\t\theaders: request.headers,\n\t\t\t\t\tquery: request.query,\n\t\t\t\t\tbody: request.body,\n\t\t\t\t\tcookies: request.cookies,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\trequest.params = validity.value.params!\n\t\t\trequest.headers = validity.value.headers!\n\t\t\trequest.query = validity.value.query!\n\t\t\trequest.body = validity.value.body!\n\t\t\trequest.cookies = validity.value.cookies!\n\t\t\treturn request\n\t\t}\n\t\tconst validateResponse: ResponseValidator = async (response) => {\n\t\t\tif (!Object.keys(responsePipeDefs)) return response\n\t\t\tstatus = response.status\n\t\t\tcontentType = response.contentType\n\n\t\t\tconst validity = responseLocalStorage.run(response, () =>\n\t\t\t\tv.validate(responsePipe, {\n\t\t\t\t\tresponseHeaders: response.headers,\n\t\t\t\t\tresponseCookies: Object.fromEntries(Object.entries(response.cookies).map(([key, val]) => [key, val.value] as const)),\n\t\t\t\t\tresponse: response.body,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\tresponse.body = validity.value.response!\n\t\t\tresponse.headers = validity.value.responseHeaders!\n\t\t\tresponse.cookieValues = validity.value.responseCookies!\n\t\t\treturn response\n\t\t}\n\t\treturn {\n\t\t\tjsonSchema,\n\t\t\tvalidateRequest,\n\t\t\tvalidateResponse,\n\t\t}\n\t}\n\n\ttest() {\n\t\treturn supertest(this.server)\n\t}\n\n\tasync start() {\n\t\tconst port = this.config.port\n\t\tconst instance = Instance.get()\n\t\tconst { app } = instance.settings\n\t\tif (this.config.healthPath)\n\t\t\tthis.addRoute({\n\t\t\t\tmethod: Methods.get,\n\t\t\t\tpath: this.config.healthPath,\n\t\t\t\thandler: async (req) =>\n\t\t\t\t\treq.res({\n\t\t\t\t\t\tbody: `${instance.id}(${app.name}) service running`,\n\t\t\t\t\t\tcontentType: 'text/plain',\n\t\t\t\t\t}),\n\t\t\t})\n\n\t\tawait Promise.all(this.#queue.map((cb) => cb()))\n\n\t\tthis.implementations.registerNotFoundHandler(async (req) => {\n\t\t\tconst request = await this.implementations.parseRequest(req)\n\t\t\tthrow new NotFoundError(`Route ${request.path} not found`)\n\t\t})\n\t\tthis.implementations.registerErrorHandler(async (error, _, res) => {\n\t\t\tif (!(error instanceof EquippedError)) Instance.get().log.error({ error }, 'Uncaught error in route handler')\n\t\t\tconst response =\n\t\t\t\terror instanceof RequestError\n\t\t\t\t\t? new Response({\n\t\t\t\t\t\t\tbody: error.serializedErrors,\n\t\t\t\t\t\t\tstatus: error.statusCode,\n\t\t\t\t\t\t})\n\t\t\t\t\t: error instanceof EquippedError\n\t\t\t\t\t\t? new Response({\n\t\t\t\t\t\t\t\tbody: [{ message: error.message }],\n\t\t\t\t\t\t\t\tstatus: StatusCodes.BadRequest,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: new Response({\n\t\t\t\t\t\t\t\tbody: [{ message: 'Something went wrong', data: error.message }],\n\t\t\t\t\t\t\t\tstatus: StatusCodes.BadRequest,\n\t\t\t\t\t\t\t})\n\t\t\treturn await this.implementations.handleResponse(res, response)\n\t\t})\n\n\t\tconst started = await this.implementations.start(port)\n\t\tif (started) Instance.get().log.info(`${instance.id}(${app.name}) service listening on port ${port}`)\n\t\treturn started\n\t}\n}\n"],"mappings":"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","names":["SocketServer","supertest","PipeError","v","EquippedError","NotFoundError","RequestError","Instance","pipeErrorToValidationError","requestLocalStorage","responseLocalStorage","OpenApi","Response","SocketEmitter","Methods","StatusCodes","errorsSchemas","value","key","Server","server","config","implementations","#openapi","socketInstance","#queue","#routesByKey","_","cb","m","routers","router","routes","route","method","path","schema","onError","middlewares","responseMiddlewares","validateRequest","validateResponse","jsonSchema","#resolveSchema","req","res","request","middleware","rawRes","response","error","rawResponse","defaultStatusCode","defaultContentType","status","contentType","requestPipeDefs","responsePipeDefs","def","pipe","pipeRecords","input","p","r","record","requestPipe","responsePipe","validity","val","port","instance","app","started"]}
|
|
@@ -48,25 +48,27 @@ class Server {
|
|
|
48
48
|
addRoute(...routes) {
|
|
49
49
|
routes.forEach((route) => {
|
|
50
50
|
this.#queue.push(async () => {
|
|
51
|
-
const { method, path, schema = {}, onError, middlewares = [] } = route;
|
|
51
|
+
const { method, path, schema = {}, onError, middlewares = [], responseMiddlewares = [] } = route;
|
|
52
52
|
const key = `(${method.toUpperCase()}) ${this.#openapi.cleanPath(path)}`;
|
|
53
53
|
if (this.#routesByKey.get(key))
|
|
54
54
|
throw new EquippedError(`Route key ${key} already registered. All route keys must be unique`, { route, key });
|
|
55
55
|
middlewares.forEach((m) => m.onSetup?.(route));
|
|
56
56
|
onError?.onSetup?.(route);
|
|
57
|
+
responseMiddlewares.forEach((m) => m.onSetup?.(route));
|
|
57
58
|
const { validateRequest, validateResponse, jsonSchema } = this.#resolveSchema(method, schema);
|
|
58
59
|
this.#routesByKey.set(key, true);
|
|
59
60
|
await this.#openapi.register(route, jsonSchema);
|
|
60
61
|
this.implementations.registerRoute(method, this.#openapi.cleanPath(path), async (req, res) => {
|
|
61
62
|
const request = await validateRequest(await this.implementations.parseRequest(req));
|
|
62
63
|
try {
|
|
63
|
-
for (const middleware of middlewares) await middleware.cb(request
|
|
64
|
-
const rawRes = await route.handler(request
|
|
64
|
+
for (const middleware of middlewares) await middleware.cb(request);
|
|
65
|
+
const rawRes = await route.handler(request);
|
|
65
66
|
const response = rawRes instanceof Response ? rawRes : new Response({ body: rawRes, status: StatusCodes.Ok, headers: {}, piped: false });
|
|
67
|
+
for (const middleware of responseMiddlewares) await middleware.cb(request, response);
|
|
66
68
|
return await this.implementations.handleResponse(res, await validateResponse(response));
|
|
67
69
|
} catch (error) {
|
|
68
70
|
if (onError?.cb) {
|
|
69
|
-
const rawResponse = await onError.cb(request,
|
|
71
|
+
const rawResponse = await onError.cb(request, error);
|
|
70
72
|
const response = rawResponse instanceof Response ? rawResponse : new Response({ body: rawResponse, status: StatusCodes.BadRequest, headers: {} });
|
|
71
73
|
return await this.implementations.handleResponse(res, await validateResponse(response));
|
|
72
74
|
}
|
|
@@ -179,6 +181,7 @@ class Server {
|
|
|
179
181
|
contentType: "text/plain"
|
|
180
182
|
})
|
|
181
183
|
});
|
|
184
|
+
await Promise.all(this.#queue.map((cb) => cb()));
|
|
182
185
|
this.implementations.registerNotFoundHandler(async (req) => {
|
|
183
186
|
const request = await this.implementations.parseRequest(req);
|
|
184
187
|
throw new NotFoundError(`Route ${request.path} not found`);
|
|
@@ -197,7 +200,6 @@ class Server {
|
|
|
197
200
|
});
|
|
198
201
|
return await this.implementations.handleResponse(res, response);
|
|
199
202
|
});
|
|
200
|
-
await Promise.all(this.#queue.map((cb) => cb()));
|
|
201
203
|
const started = await this.implementations.start(port);
|
|
202
204
|
if (started) Instance.get().log.info(`${instance.id}(${app.name}) service listening on port ${port}`);
|
|
203
205
|
return started;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/server/impls/base.ts"],"sourcesContent":["import type http from 'node:http'\n\nimport { type FastifyCorsOptions } from '@fastify/cors'\nimport { type CorsOptions } from 'cors'\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { type Pipe, PipeError, v } from 'valleyed'\n\nimport { EquippedError, NotFoundError, RequestError } from '../../errors'\nimport { Instance } from '../../instance'\nimport { pipeErrorToValidationError } from '../../validations'\nimport { requestLocalStorage, responseLocalStorage } from '../../validations/valleyed'\nimport { OpenApi, type OpenApiSchemaDef } from '../openapi'\nimport type { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, type MethodsEnum, type Route, type RouteDef, StatusCodes } from '../types'\n\ntype RequestValidator = (req: Request<any>) => Promise<Request<any>>\ntype ResponseValidator = (res: Response<any>) => Promise<Response<any>>\n\nconst errorsSchemas = Object.entries(StatusCodes)\n\t.filter(([, value]) => value > 399)\n\t.map(([key, value]) => ({\n\t\tstatus: value,\n\t\tcontentType: 'application/json',\n\t\tpipe: v.meta(v.array(v.object({ message: v.string(), field: v.optional(v.string()) })), {\n\t\t\t$refId: `Errors.${key}Response`,\n\t\t\tdescription: `${key} Response`,\n\t\t}) as Pipe<any, any>,\n\t}))\n\nexport abstract class Server<Req = any, Res = any> {\n\t#queue: (() => void | Promise<void>)[] = []\n\t#routesByKey = new Map<string, boolean>()\n\t#openapi: OpenApi\n\tsocket: SocketEmitter\n\tprotected server: http.Server\n\tprotected get cors(): CorsOptions & FastifyCorsOptions {\n\t\treturn {\n\t\t\torigin: this.config.cors?.origin ? (_, cb) => cb(null, true) : this.config.cors?.origin,\n\t\t\tmethods: (this.config.cors?.methods ?? Object.values(Methods)).filter((m) => m !== Methods.options).map((m) => m.toUpperCase()),\n\t\t\tcredentials: this.config.cors?.credentials,\n\t\t}\n\t}\n\n\tconstructor(\n\t\tserver: http.Server,\n\t\tprivate config: ServerConfig,\n\t\tprivate implementations: {\n\t\t\tparseRequest: (req: Req) => Promise<Request<any>>\n\t\t\thandleResponse: (res: Res, response: Response<any>) => Promise<void>\n\t\t\tregisterRoute: (method: MethodsEnum, path: string, cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterErrorHandler: (cb: (error: Error, req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterNotFoundHandler: (cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tstart: (port: number) => Promise<boolean>\n\t\t},\n\t) {\n\t\tthis.server = server\n\t\tthis.#openapi = new OpenApi(config)\n\t\tconst socketInstance = new SocketServer(server, { cors: this.cors })\n\t\tthis.socket = new SocketEmitter(socketInstance, config)\n\t\tthis.addRouter(this.#openapi.router())\n\t}\n\n\taddRouter(...routers: Router<any>[]) {\n\t\trouters.map((router) => router.routes).forEach((routes) => this.addRoute(...routes))\n\t}\n\n\taddRoute<T extends RouteDef>(...routes: Route<T>[]) {\n\t\troutes.forEach((route) => {\n\t\t\tthis.#queue.push(async () => {\n\t\t\t\tconst { method, path, schema = {}, onError, middlewares = [] } = route\n\n\t\t\t\tconst key = `(${method.toUpperCase()}) ${this.#openapi.cleanPath(path)}`\n\t\t\t\tif (this.#routesByKey.get(key))\n\t\t\t\t\tthrow new EquippedError(`Route key ${key} already registered. All route keys must be unique`, { route, key })\n\n\t\t\t\tmiddlewares.forEach((m) => m.onSetup?.(route as any))\n\t\t\t\tonError?.onSetup?.(route as any)\n\n\t\t\t\tconst { validateRequest, validateResponse, jsonSchema } = this.#resolveSchema(method, schema)\n\n\t\t\t\tthis.#routesByKey.set(key, true)\n\t\t\t\tawait this.#openapi.register(route, jsonSchema)\n\t\t\t\tthis.implementations.registerRoute(method, this.#openapi.cleanPath(path), async (req: Req, res: Res) => {\n\t\t\t\t\tconst request = await validateRequest(await this.implementations.parseRequest(req))\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor (const middleware of middlewares) await middleware.cb(request, this.config)\n\t\t\t\t\t\tconst rawRes = await route.handler(request, this.config)\n\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\trawRes instanceof Response\n\t\t\t\t\t\t\t\t? rawRes\n\t\t\t\t\t\t\t\t: new Response({ body: rawRes, status: StatusCodes.Ok, headers: {}, piped: false })\n\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tif (onError?.cb) {\n\t\t\t\t\t\t\tconst rawResponse = await onError.cb(request, this.config, error as Error)\n\t\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\t\trawResponse instanceof Response\n\t\t\t\t\t\t\t\t\t? rawResponse\n\t\t\t\t\t\t\t\t\t: new Response({ body: rawResponse, status: StatusCodes.BadRequest, headers: {} })\n\t\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t}\n\n\t#resolveSchema(method: MethodsEnum, schema: RouteDef) {\n\t\tconst defaultStatusCode = schema?.defaultStatusCode ?? StatusCodes.Ok\n\t\tconst defaultContentType = schema?.defaultContentType ?? 'application/json'\n\t\tlet status = defaultStatusCode\n\t\tlet contentType = defaultContentType\n\t\tconst jsonSchema: OpenApiSchemaDef = { response: {}, request: {} }\n\t\tconst requestPipeDefs: Pick<RouteDef, 'body' | 'headers' | 'query' | 'params' | 'cookies'> = {}\n\t\tconst responsePipeDefs: Pick<RouteDef, 'response' | 'responseHeaders' | 'responseCookies'> = {}\n\n\t\tconst defs: {\n\t\t\tkey: Exclude<keyof RouteDef, `default${string}` | 'context'>\n\t\t\ttype: keyof OpenApiSchemaDef\n\t\t\tskip?: boolean\n\t\t}[] = [\n\t\t\t{ key: 'params', type: 'request' },\n\t\t\t{ key: 'headers', type: 'request' },\n\t\t\t{ key: 'cookies', type: 'request' },\n\t\t\t{ key: 'query', type: 'request' },\n\t\t\t{ key: 'body', type: 'request', skip: !(<MethodsEnum[]>[Methods.post, Methods.put, Methods.patch]).includes(method) },\n\t\t\t{ key: 'response', type: 'response' },\n\t\t\t{ key: 'responseHeaders', type: 'response' },\n\t\t\t{ key: 'responseCookies', type: 'response' },\n\t\t]\n\t\tdefs.forEach((def) => {\n\t\t\tconst pipe = schema[def.key] ?? v.any()\n\t\t\tif (def.skip) return\n\n\t\t\tif (def.type === 'request') {\n\t\t\t\trequestPipeDefs[def.key] = pipe\n\t\t\t\tjsonSchema.request[def.key as keyof typeof jsonSchema.request] = v.schema(pipe)\n\t\t\t}\n\t\t\tif (def.type === 'response') {\n\t\t\t\tconst pipeRecords = errorsSchemas.concat({ status: defaultStatusCode, contentType, pipe })\n\t\t\t\tresponsePipeDefs[def.key] = v.any().pipe((input) => {\n\t\t\t\t\tconst p = pipeRecords.find((r) => r.status === status)?.pipe\n\t\t\t\t\tif (!p) throw PipeError.root(`schema not defined for status code: ${status}`, input)\n\t\t\t\t\treturn v.assert(p, input)\n\t\t\t\t})\n\t\t\t\tjsonSchema.response[def.key as keyof typeof jsonSchema.response] = pipeRecords.map((record) => ({\n\t\t\t\t\tstatus: record.status,\n\t\t\t\t\tcontentType: record.contentType,\n\t\t\t\t\tschema: v.schema(record.pipe),\n\t\t\t\t}))\n\t\t\t}\n\t\t})\n\t\tconst requestPipe = v.object(requestPipeDefs)\n\t\tv.compile(requestPipe, { allErrors: true })\n\t\tconst responsePipe = v.object(responsePipeDefs)\n\t\tv.compile(responsePipe, { allErrors: true })\n\t\tconst validateRequest: RequestValidator = async (request) => {\n\t\t\tif (!Object.keys(requestPipeDefs)) return request\n\t\t\tconst validity = requestLocalStorage.run(request, () =>\n\t\t\t\tv.validate(requestPipe, {\n\t\t\t\t\tparams: request.params,\n\t\t\t\t\theaders: request.headers,\n\t\t\t\t\tquery: request.query,\n\t\t\t\t\tbody: request.body,\n\t\t\t\t\tcookies: request.cookies,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\trequest.params = validity.value.params!\n\t\t\trequest.headers = validity.value.headers!\n\t\t\trequest.query = validity.value.query!\n\t\t\trequest.body = validity.value.body!\n\t\t\trequest.cookies = validity.value.cookies!\n\t\t\treturn request\n\t\t}\n\t\tconst validateResponse: ResponseValidator = async (response) => {\n\t\t\tif (!Object.keys(responsePipeDefs)) return response\n\t\t\tstatus = response.status\n\t\t\tcontentType = response.contentType\n\n\t\t\tconst validity = responseLocalStorage.run(response, () =>\n\t\t\t\tv.validate(responsePipe, {\n\t\t\t\t\tresponseHeaders: response.headers,\n\t\t\t\t\tresponseCookies: Object.fromEntries(Object.entries(response.cookies).map(([key, val]) => [key, val.value] as const)),\n\t\t\t\t\tresponse: response.body,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\tresponse.body = validity.value.response!\n\t\t\tresponse.headers = validity.value.responseHeaders!\n\t\t\tresponse.cookieValues = validity.value.responseCookies!\n\t\t\treturn response\n\t\t}\n\t\treturn {\n\t\t\tjsonSchema,\n\t\t\tvalidateRequest,\n\t\t\tvalidateResponse,\n\t\t}\n\t}\n\n\ttest() {\n\t\treturn supertest(this.server)\n\t}\n\n\tasync start() {\n\t\tconst port = this.config.port\n\t\tconst instance = Instance.get()\n\t\tconst { app } = instance.settings\n\t\tif (this.config.healthPath)\n\t\t\tthis.addRoute({\n\t\t\t\tmethod: Methods.get,\n\t\t\t\tpath: this.config.healthPath,\n\t\t\t\thandler: async (req) =>\n\t\t\t\t\treq.res({\n\t\t\t\t\t\tbody: `${instance.id}(${app.name}) service running`,\n\t\t\t\t\t\tcontentType: 'text/plain',\n\t\t\t\t\t}),\n\t\t\t})\n\n\t\tthis.implementations.registerNotFoundHandler(async (req) => {\n\t\t\tconst request = await this.implementations.parseRequest(req)\n\t\t\tthrow new NotFoundError(`Route ${request.path} not found`)\n\t\t})\n\t\tthis.implementations.registerErrorHandler(async (error, _, res) => {\n\t\t\tif (!(error instanceof EquippedError)) Instance.get().log.error({ error }, 'Uncaught error in route handler')\n\t\t\tconst response =\n\t\t\t\terror instanceof RequestError\n\t\t\t\t\t? new Response({\n\t\t\t\t\t\t\tbody: error.serializedErrors,\n\t\t\t\t\t\t\tstatus: error.statusCode,\n\t\t\t\t\t\t})\n\t\t\t\t\t: error instanceof EquippedError\n\t\t\t\t\t\t? new Response({\n\t\t\t\t\t\t\t\tbody: [{ message: error.message }],\n\t\t\t\t\t\t\t\tstatus: StatusCodes.BadRequest,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: new Response({\n\t\t\t\t\t\t\t\tbody: [{ message: 'Something went wrong', data: error.message }],\n\t\t\t\t\t\t\t\tstatus: StatusCodes.BadRequest,\n\t\t\t\t\t\t\t})\n\t\t\treturn await this.implementations.handleResponse(res, response)\n\t\t})\n\n\t\tawait Promise.all(this.#queue.map((cb) => cb()))\n\t\tconst started = await this.implementations.start(port)\n\t\tif (started) Instance.get().log.info(`${instance.id}(${app.name}) service listening on port ${port}`)\n\t\treturn started\n\t}\n}\n"],"mappings":"AAEA,eAAwC;AACxC,eAAiC;AACjC,SAAS,UAAU,oBAAoB;AACvC,OAAO,eAAe;AACtB,SAAoB,WAAW,SAAS;AAExC,SAAS,eAAe,eAAe,oBAAoB;AAC3D,SAAS,gBAAgB;AACzB,SAAS,kCAAkC;AAC3C,SAAS,qBAAqB,4BAA4B;AAC1D,SAAS,eAAsC;AAE/C,SAAuB,gBAAgB;AACvC,SAAS,cAAc;AACvB,SAAS,qBAAqB;AAC9B,SAAS,SAAsD,mBAAmB;AAKlF,MAAM,gBAAgB,OAAO,QAAQ,WAAW,EAC9C,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,QAAQ,GAAG,EACjC,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO;AAAA,EACvB,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG;AAAA,IACvF,QAAQ,UAAU,GAAG;AAAA,IACrB,aAAa,GAAG,GAAG;AAAA,EACpB,CAAC;AACF,EAAE;AAEI,MAAe,OAA6B;AAAA,EAclD,YACC,QACQ,QACA,iBAQP;AATO;AACA;AASR,SAAK,SAAS;AACd,SAAK,WAAW,IAAI,QAAQ,MAAM;AAClC,UAAM,iBAAiB,IAAI,aAAa,QAAQ,EAAE,MAAM,KAAK,KAAK,CAAC;AACnE,SAAK,SAAS,IAAI,cAAc,gBAAgB,MAAM;AACtD,SAAK,UAAU,KAAK,SAAS,OAAO,CAAC;AAAA,EACtC;AAAA,EA9BA,SAAyC,CAAC;AAAA,EAC1C,eAAe,oBAAI,IAAqB;AAAA,EACxC;AAAA,EACA;AAAA,EACU;AAAA,EACV,IAAc,OAAyC;AACtD,WAAO;AAAA,MACN,QAAQ,KAAK,OAAO,MAAM,SAAS,CAAC,GAAG,OAAO,GAAG,MAAM,IAAI,IAAI,KAAK,OAAO,MAAM;AAAA,MACjF,UAAU,KAAK,OAAO,MAAM,WAAW,OAAO,OAAO,OAAO,GAAG,OAAO,CAAC,MAAM,MAAM,QAAQ,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;AAAA,MAC9H,aAAa,KAAK,OAAO,MAAM;AAAA,IAChC;AAAA,EACD;AAAA,EAqBA,aAAa,SAAwB;AACpC,YAAQ,IAAI,CAAC,WAAW,OAAO,MAAM,EAAE,QAAQ,CAAC,WAAW,KAAK,SAAS,GAAG,MAAM,CAAC;AAAA,EACpF;AAAA,EAEA,YAAgC,QAAoB;AACnD,WAAO,QAAQ,CAAC,UAAU;AACzB,WAAK,OAAO,KAAK,YAAY;AAC5B,cAAM,EAAE,QAAQ,MAAM,SAAS,CAAC,GAAG,SAAS,cAAc,CAAC,EAAE,IAAI;AAEjE,cAAM,MAAM,IAAI,OAAO,YAAY,CAAC,KAAK,KAAK,SAAS,UAAU,IAAI,CAAC;AACtE,YAAI,KAAK,aAAa,IAAI,GAAG;AAC5B,gBAAM,IAAI,cAAc,aAAa,GAAG,sDAAsD,EAAE,OAAO,IAAI,CAAC;AAE7G,oBAAY,QAAQ,CAAC,MAAM,EAAE,UAAU,KAAY,CAAC;AACpD,iBAAS,UAAU,KAAY;AAE/B,cAAM,EAAE,iBAAiB,kBAAkB,WAAW,IAAI,KAAK,eAAe,QAAQ,MAAM;AAE5F,aAAK,aAAa,IAAI,KAAK,IAAI;AAC/B,cAAM,KAAK,SAAS,SAAS,OAAO,UAAU;AAC9C,aAAK,gBAAgB,cAAc,QAAQ,KAAK,SAAS,UAAU,IAAI,GAAG,OAAO,KAAU,QAAa;AACvG,gBAAM,UAAU,MAAM,gBAAgB,MAAM,KAAK,gBAAgB,aAAa,GAAG,CAAC;AAClF,cAAI;AACH,uBAAW,cAAc,YAAa,OAAM,WAAW,GAAG,SAAS,KAAK,MAAM;AAC9E,kBAAM,SAAS,MAAM,MAAM,QAAQ,SAAS,KAAK,MAAM;AACvD,kBAAM,WACL,kBAAkB,WACf,SACA,IAAI,SAAS,EAAE,MAAM,QAAQ,QAAQ,YAAY,IAAI,SAAS,CAAC,GAAG,OAAO,MAAM,CAAC;AACpF,mBAAO,MAAM,KAAK,gBAAgB,eAAe,KAAK,MAAM,iBAAiB,QAAQ,CAAC;AAAA,UACvF,SAAS,OAAO;AACf,gBAAI,SAAS,IAAI;AAChB,oBAAM,cAAc,MAAM,QAAQ,GAAG,SAAS,KAAK,QAAQ,KAAc;AACzE,oBAAM,WACL,uBAAuB,WACpB,cACA,IAAI,SAAS,EAAE,MAAM,aAAa,QAAQ,YAAY,YAAY,SAAS,CAAC,EAAE,CAAC;AACnF,qBAAO,MAAM,KAAK,gBAAgB,eAAe,KAAK,MAAM,iBAAiB,QAAQ,CAAC;AAAA,YACvF;AACA,kBAAM;AAAA,UACP;AAAA,QACD,CAAC;AAAA,MACF,CAAC;AAAA,IACF,CAAC;AAAA,EACF;AAAA,EAEA,eAAe,QAAqB,QAAkB;AACrD,UAAM,oBAAoB,QAAQ,qBAAqB,YAAY;AACnE,UAAM,qBAAqB,QAAQ,sBAAsB;AACzD,QAAI,SAAS;AACb,QAAI,cAAc;AAClB,UAAM,aAA+B,EAAE,UAAU,CAAC,GAAG,SAAS,CAAC,EAAE;AACjE,UAAM,kBAAuF,CAAC;AAC9F,UAAM,mBAAuF,CAAC;AAE9F,UAAM,OAIA;AAAA,MACL,EAAE,KAAK,UAAU,MAAM,UAAU;AAAA,MACjC,EAAE,KAAK,WAAW,MAAM,UAAU;AAAA,MAClC,EAAE,KAAK,WAAW,MAAM,UAAU;AAAA,MAClC,EAAE,KAAK,SAAS,MAAM,UAAU;AAAA,MAChC,EAAE,KAAK,QAAQ,MAAM,WAAW,MAAM,CAAiB,CAAC,QAAQ,MAAM,QAAQ,KAAK,QAAQ,KAAK,EAAG,SAAS,MAAM,EAAE;AAAA,MACpH,EAAE,KAAK,YAAY,MAAM,WAAW;AAAA,MACpC,EAAE,KAAK,mBAAmB,MAAM,WAAW;AAAA,MAC3C,EAAE,KAAK,mBAAmB,MAAM,WAAW;AAAA,IAC5C;AACA,SAAK,QAAQ,CAAC,QAAQ;AACrB,YAAM,OAAO,OAAO,IAAI,GAAG,KAAK,EAAE,IAAI;AACtC,UAAI,IAAI,KAAM;AAEd,UAAI,IAAI,SAAS,WAAW;AAC3B,wBAAgB,IAAI,GAAG,IAAI;AAC3B,mBAAW,QAAQ,IAAI,GAAsC,IAAI,EAAE,OAAO,IAAI;AAAA,MAC/E;AACA,UAAI,IAAI,SAAS,YAAY;AAC5B,cAAM,cAAc,cAAc,OAAO,EAAE,QAAQ,mBAAmB,aAAa,KAAK,CAAC;AACzF,yBAAiB,IAAI,GAAG,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,UAAU;AACnD,gBAAM,IAAI,YAAY,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM,GAAG;AACxD,cAAI,CAAC,EAAG,OAAM,UAAU,KAAK,uCAAuC,MAAM,IAAI,KAAK;AACnF,iBAAO,EAAE,OAAO,GAAG,KAAK;AAAA,QACzB,CAAC;AACD,mBAAW,SAAS,IAAI,GAAuC,IAAI,YAAY,IAAI,CAAC,YAAY;AAAA,UAC/F,QAAQ,OAAO;AAAA,UACf,aAAa,OAAO;AAAA,UACpB,QAAQ,EAAE,OAAO,OAAO,IAAI;AAAA,QAC7B,EAAE;AAAA,MACH;AAAA,IACD,CAAC;AACD,UAAM,cAAc,EAAE,OAAO,eAAe;AAC5C,MAAE,QAAQ,aAAa,EAAE,WAAW,KAAK,CAAC;AAC1C,UAAM,eAAe,EAAE,OAAO,gBAAgB;AAC9C,MAAE,QAAQ,cAAc,EAAE,WAAW,KAAK,CAAC;AAC3C,UAAM,kBAAoC,OAAO,YAAY;AAC5D,UAAI,CAAC,OAAO,KAAK,eAAe,EAAG,QAAO;AAC1C,YAAM,WAAW,oBAAoB;AAAA,QAAI;AAAA,QAAS,MACjD,EAAE,SAAS,aAAa;AAAA,UACvB,QAAQ,QAAQ;AAAA,UAChB,SAAS,QAAQ;AAAA,UACjB,OAAO,QAAQ;AAAA,UACf,MAAM,QAAQ;AAAA,UACd,SAAS,QAAQ;AAAA,QAClB,CAAC;AAAA,MACF;AAEA,UAAI,CAAC,SAAS,MAAO,OAAM,2BAA2B,SAAS,KAAK;AACpE,cAAQ,SAAS,SAAS,MAAM;AAChC,cAAQ,UAAU,SAAS,MAAM;AACjC,cAAQ,QAAQ,SAAS,MAAM;AAC/B,cAAQ,OAAO,SAAS,MAAM;AAC9B,cAAQ,UAAU,SAAS,MAAM;AACjC,aAAO;AAAA,IACR;AACA,UAAM,mBAAsC,OAAO,aAAa;AAC/D,UAAI,CAAC,OAAO,KAAK,gBAAgB,EAAG,QAAO;AAC3C,eAAS,SAAS;AAClB,oBAAc,SAAS;AAEvB,YAAM,WAAW,qBAAqB;AAAA,QAAI;AAAA,QAAU,MACnD,EAAE,SAAS,cAAc;AAAA,UACxB,iBAAiB,SAAS;AAAA,UAC1B,iBAAiB,OAAO,YAAY,OAAO,QAAQ,SAAS,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,KAAK,CAAU,CAAC;AAAA,UACnH,UAAU,SAAS;AAAA,QACpB,CAAC;AAAA,MACF;AAEA,UAAI,CAAC,SAAS,MAAO,OAAM,2BAA2B,SAAS,KAAK;AACpE,eAAS,OAAO,SAAS,MAAM;AAC/B,eAAS,UAAU,SAAS,MAAM;AAClC,eAAS,eAAe,SAAS,MAAM;AACvC,aAAO;AAAA,IACR;AACA,WAAO;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA,EAEA,OAAO;AACN,WAAO,UAAU,KAAK,MAAM;AAAA,EAC7B;AAAA,EAEA,MAAM,QAAQ;AACb,UAAM,OAAO,KAAK,OAAO;AACzB,UAAM,WAAW,SAAS,IAAI;AAC9B,UAAM,EAAE,IAAI,IAAI,SAAS;AACzB,QAAI,KAAK,OAAO;AACf,WAAK,SAAS;AAAA,QACb,QAAQ,QAAQ;AAAA,QAChB,MAAM,KAAK,OAAO;AAAA,QAClB,SAAS,OAAO,QACf,IAAI,IAAI;AAAA,UACP,MAAM,GAAG,SAAS,EAAE,IAAI,IAAI,IAAI;AAAA,UAChC,aAAa;AAAA,QACd,CAAC;AAAA,MACH,CAAC;AAEF,SAAK,gBAAgB,wBAAwB,OAAO,QAAQ;AAC3D,YAAM,UAAU,MAAM,KAAK,gBAAgB,aAAa,GAAG;AAC3D,YAAM,IAAI,cAAc,SAAS,QAAQ,IAAI,YAAY;AAAA,IAC1D,CAAC;AACD,SAAK,gBAAgB,qBAAqB,OAAO,OAAO,GAAG,QAAQ;AAClE,UAAI,EAAE,iBAAiB,eAAgB,UAAS,IAAI,EAAE,IAAI,MAAM,EAAE,MAAM,GAAG,iCAAiC;AAC5G,YAAM,WACL,iBAAiB,eACd,IAAI,SAAS;AAAA,QACb,MAAM,MAAM;AAAA,QACZ,QAAQ,MAAM;AAAA,MACf,CAAC,IACA,iBAAiB,gBAChB,IAAI,SAAS;AAAA,QACb,MAAM,CAAC,EAAE,SAAS,MAAM,QAAQ,CAAC;AAAA,QACjC,QAAQ,YAAY;AAAA,MACrB,CAAC,IACA,IAAI,SAAS;AAAA,QACb,MAAM,CAAC,EAAE,SAAS,wBAAwB,MAAM,MAAM,QAAQ,CAAC;AAAA,QAC/D,QAAQ,YAAY;AAAA,MACrB,CAAC;AACL,aAAO,MAAM,KAAK,gBAAgB,eAAe,KAAK,QAAQ;AAAA,IAC/D,CAAC;AAED,UAAM,QAAQ,IAAI,KAAK,OAAO,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;AAC/C,UAAM,UAAU,MAAM,KAAK,gBAAgB,MAAM,IAAI;AACrD,QAAI,QAAS,UAAS,IAAI,EAAE,IAAI,KAAK,GAAG,SAAS,EAAE,IAAI,IAAI,IAAI,+BAA+B,IAAI,EAAE;AACpG,WAAO;AAAA,EACR;AACD;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/server/impls/base.ts"],"sourcesContent":["import type http from 'node:http'\n\nimport { type FastifyCorsOptions } from '@fastify/cors'\nimport { type CorsOptions } from 'cors'\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { type Pipe, PipeError, v } from 'valleyed'\n\nimport { EquippedError, NotFoundError, RequestError } from '../../errors'\nimport { Instance } from '../../instance'\nimport { pipeErrorToValidationError } from '../../validations'\nimport { requestLocalStorage, responseLocalStorage } from '../../validations/valleyed'\nimport { OpenApi, type OpenApiSchemaDef } from '../openapi'\nimport type { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, type MethodsEnum, type Route, type RouteDef, StatusCodes } from '../types'\n\ntype RequestValidator = (req: Request<any>) => Promise<Request<any>>\ntype ResponseValidator = (res: Response<any>) => Promise<Response<any>>\n\nconst errorsSchemas = Object.entries(StatusCodes)\n\t.filter(([, value]) => value > 399)\n\t.map(([key, value]) => ({\n\t\tstatus: value,\n\t\tcontentType: 'application/json',\n\t\tpipe: v.meta(v.array(v.object({ message: v.string(), field: v.optional(v.string()) })), {\n\t\t\t$refId: `Errors.${key}Response`,\n\t\t\tdescription: `${key} Response`,\n\t\t}) as Pipe<any, any>,\n\t}))\n\nexport abstract class Server<Req = any, Res = any> {\n\t#queue: (() => void | Promise<void>)[] = []\n\t#routesByKey = new Map<string, boolean>()\n\t#openapi: OpenApi\n\tsocket: SocketEmitter\n\tprotected server: http.Server\n\tprotected get cors(): CorsOptions & FastifyCorsOptions {\n\t\treturn {\n\t\t\torigin: this.config.cors?.origin ? (_, cb) => cb(null, true) : this.config.cors?.origin,\n\t\t\tmethods: (this.config.cors?.methods ?? Object.values(Methods)).filter((m) => m !== Methods.options).map((m) => m.toUpperCase()),\n\t\t\tcredentials: this.config.cors?.credentials,\n\t\t}\n\t}\n\n\tconstructor(\n\t\tserver: http.Server,\n\t\tprivate config: ServerConfig,\n\t\tprivate implementations: {\n\t\t\tparseRequest: (req: Req) => Promise<Request<any>>\n\t\t\thandleResponse: (res: Res, response: Response<any>) => Promise<void>\n\t\t\tregisterRoute: (method: MethodsEnum, path: string, cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterErrorHandler: (cb: (error: Error, req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterNotFoundHandler: (cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tstart: (port: number) => Promise<boolean>\n\t\t},\n\t) {\n\t\tthis.server = server\n\t\tthis.#openapi = new OpenApi(config)\n\t\tconst socketInstance = new SocketServer(server, { cors: this.cors })\n\t\tthis.socket = new SocketEmitter(socketInstance, config)\n\t\tthis.addRouter(this.#openapi.router())\n\t}\n\n\taddRouter(...routers: Router<any>[]) {\n\t\trouters.map((router) => router.routes).forEach((routes) => this.addRoute(...routes))\n\t}\n\n\taddRoute<T extends RouteDef>(...routes: Route<T>[]) {\n\t\troutes.forEach((route) => {\n\t\t\tthis.#queue.push(async () => {\n\t\t\t\tconst { method, path, schema = {}, onError, middlewares = [], responseMiddlewares = [] } = route\n\n\t\t\t\tconst key = `(${method.toUpperCase()}) ${this.#openapi.cleanPath(path)}`\n\t\t\t\tif (this.#routesByKey.get(key))\n\t\t\t\t\tthrow new EquippedError(`Route key ${key} already registered. All route keys must be unique`, { route, key })\n\n\t\t\t\tmiddlewares.forEach((m) => m.onSetup?.(route as any))\n\t\t\t\tonError?.onSetup?.(route as any)\n\t\t\t\tresponseMiddlewares.forEach((m) => m.onSetup?.(route as any))\n\n\t\t\t\tconst { validateRequest, validateResponse, jsonSchema } = this.#resolveSchema(method, schema)\n\n\t\t\t\tthis.#routesByKey.set(key, true)\n\t\t\t\tawait this.#openapi.register(route, jsonSchema)\n\t\t\t\tthis.implementations.registerRoute(method, this.#openapi.cleanPath(path), async (req: Req, res: Res) => {\n\t\t\t\t\tconst request = await validateRequest(await this.implementations.parseRequest(req))\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor (const middleware of middlewares) await middleware.cb(request)\n\t\t\t\t\t\tconst rawRes = await route.handler(request)\n\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\trawRes instanceof Response\n\t\t\t\t\t\t\t\t? rawRes\n\t\t\t\t\t\t\t\t: new Response({ body: rawRes, status: StatusCodes.Ok, headers: {}, piped: false })\n\t\t\t\t\t\tfor (const middleware of responseMiddlewares) await middleware.cb(request, response)\n\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tif (onError?.cb) {\n\t\t\t\t\t\t\tconst rawResponse = await onError.cb(request, error as Error)\n\t\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\t\trawResponse instanceof Response\n\t\t\t\t\t\t\t\t\t? rawResponse\n\t\t\t\t\t\t\t\t\t: new Response({ body: rawResponse, status: StatusCodes.BadRequest, headers: {} })\n\t\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t}\n\n\t#resolveSchema(method: MethodsEnum, schema: RouteDef) {\n\t\tconst defaultStatusCode = schema?.defaultStatusCode ?? StatusCodes.Ok\n\t\tconst defaultContentType = schema?.defaultContentType ?? 'application/json'\n\t\tlet status = defaultStatusCode\n\t\tlet contentType = defaultContentType\n\t\tconst jsonSchema: OpenApiSchemaDef = { response: {}, request: {} }\n\t\tconst requestPipeDefs: Pick<RouteDef, 'body' | 'headers' | 'query' | 'params' | 'cookies'> = {}\n\t\tconst responsePipeDefs: Pick<RouteDef, 'response' | 'responseHeaders' | 'responseCookies'> = {}\n\n\t\tconst defs: {\n\t\t\tkey: Exclude<keyof RouteDef, `default${string}` | 'context'>\n\t\t\ttype: keyof OpenApiSchemaDef\n\t\t\tskip?: boolean\n\t\t}[] = [\n\t\t\t{ key: 'params', type: 'request' },\n\t\t\t{ key: 'headers', type: 'request' },\n\t\t\t{ key: 'cookies', type: 'request' },\n\t\t\t{ key: 'query', type: 'request' },\n\t\t\t{ key: 'body', type: 'request', skip: !(<MethodsEnum[]>[Methods.post, Methods.put, Methods.patch]).includes(method) },\n\t\t\t{ key: 'response', type: 'response' },\n\t\t\t{ key: 'responseHeaders', type: 'response' },\n\t\t\t{ key: 'responseCookies', type: 'response' },\n\t\t]\n\t\tdefs.forEach((def) => {\n\t\t\tconst pipe = schema[def.key] ?? v.any()\n\t\t\tif (def.skip) return\n\n\t\t\tif (def.type === 'request') {\n\t\t\t\trequestPipeDefs[def.key] = pipe\n\t\t\t\tjsonSchema.request[def.key as keyof typeof jsonSchema.request] = v.schema(pipe)\n\t\t\t}\n\t\t\tif (def.type === 'response') {\n\t\t\t\tconst pipeRecords = errorsSchemas.concat({ status: defaultStatusCode, contentType, pipe })\n\t\t\t\tresponsePipeDefs[def.key] = v.any().pipe((input) => {\n\t\t\t\t\tconst p = pipeRecords.find((r) => r.status === status)?.pipe\n\t\t\t\t\tif (!p) throw PipeError.root(`schema not defined for status code: ${status}`, input)\n\t\t\t\t\treturn v.assert(p, input)\n\t\t\t\t})\n\t\t\t\tjsonSchema.response[def.key as keyof typeof jsonSchema.response] = pipeRecords.map((record) => ({\n\t\t\t\t\tstatus: record.status,\n\t\t\t\t\tcontentType: record.contentType,\n\t\t\t\t\tschema: v.schema(record.pipe),\n\t\t\t\t}))\n\t\t\t}\n\t\t})\n\t\tconst requestPipe = v.object(requestPipeDefs)\n\t\tv.compile(requestPipe, { allErrors: true })\n\t\tconst responsePipe = v.object(responsePipeDefs)\n\t\tv.compile(responsePipe, { allErrors: true })\n\t\tconst validateRequest: RequestValidator = async (request) => {\n\t\t\tif (!Object.keys(requestPipeDefs)) return request\n\t\t\tconst validity = requestLocalStorage.run(request, () =>\n\t\t\t\tv.validate(requestPipe, {\n\t\t\t\t\tparams: request.params,\n\t\t\t\t\theaders: request.headers,\n\t\t\t\t\tquery: request.query,\n\t\t\t\t\tbody: request.body,\n\t\t\t\t\tcookies: request.cookies,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\trequest.params = validity.value.params!\n\t\t\trequest.headers = validity.value.headers!\n\t\t\trequest.query = validity.value.query!\n\t\t\trequest.body = validity.value.body!\n\t\t\trequest.cookies = validity.value.cookies!\n\t\t\treturn request\n\t\t}\n\t\tconst validateResponse: ResponseValidator = async (response) => {\n\t\t\tif (!Object.keys(responsePipeDefs)) return response\n\t\t\tstatus = response.status\n\t\t\tcontentType = response.contentType\n\n\t\t\tconst validity = responseLocalStorage.run(response, () =>\n\t\t\t\tv.validate(responsePipe, {\n\t\t\t\t\tresponseHeaders: response.headers,\n\t\t\t\t\tresponseCookies: Object.fromEntries(Object.entries(response.cookies).map(([key, val]) => [key, val.value] as const)),\n\t\t\t\t\tresponse: response.body,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\tresponse.body = validity.value.response!\n\t\t\tresponse.headers = validity.value.responseHeaders!\n\t\t\tresponse.cookieValues = validity.value.responseCookies!\n\t\t\treturn response\n\t\t}\n\t\treturn {\n\t\t\tjsonSchema,\n\t\t\tvalidateRequest,\n\t\t\tvalidateResponse,\n\t\t}\n\t}\n\n\ttest() {\n\t\treturn supertest(this.server)\n\t}\n\n\tasync start() {\n\t\tconst port = this.config.port\n\t\tconst instance = Instance.get()\n\t\tconst { app } = instance.settings\n\t\tif (this.config.healthPath)\n\t\t\tthis.addRoute({\n\t\t\t\tmethod: Methods.get,\n\t\t\t\tpath: this.config.healthPath,\n\t\t\t\thandler: async (req) =>\n\t\t\t\t\treq.res({\n\t\t\t\t\t\tbody: `${instance.id}(${app.name}) service running`,\n\t\t\t\t\t\tcontentType: 'text/plain',\n\t\t\t\t\t}),\n\t\t\t})\n\n\t\tawait Promise.all(this.#queue.map((cb) => cb()))\n\n\t\tthis.implementations.registerNotFoundHandler(async (req) => {\n\t\t\tconst request = await this.implementations.parseRequest(req)\n\t\t\tthrow new NotFoundError(`Route ${request.path} not found`)\n\t\t})\n\t\tthis.implementations.registerErrorHandler(async (error, _, res) => {\n\t\t\tif (!(error instanceof EquippedError)) Instance.get().log.error({ error }, 'Uncaught error in route handler')\n\t\t\tconst response =\n\t\t\t\terror instanceof RequestError\n\t\t\t\t\t? new Response({\n\t\t\t\t\t\t\tbody: error.serializedErrors,\n\t\t\t\t\t\t\tstatus: error.statusCode,\n\t\t\t\t\t\t})\n\t\t\t\t\t: error instanceof EquippedError\n\t\t\t\t\t\t? new Response({\n\t\t\t\t\t\t\t\tbody: [{ message: error.message }],\n\t\t\t\t\t\t\t\tstatus: StatusCodes.BadRequest,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: new Response({\n\t\t\t\t\t\t\t\tbody: [{ message: 'Something went wrong', data: error.message }],\n\t\t\t\t\t\t\t\tstatus: StatusCodes.BadRequest,\n\t\t\t\t\t\t\t})\n\t\t\treturn await this.implementations.handleResponse(res, response)\n\t\t})\n\n\t\tconst started = await this.implementations.start(port)\n\t\tif (started) Instance.get().log.info(`${instance.id}(${app.name}) service listening on port ${port}`)\n\t\treturn started\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import d from"http";import l from"cookie-parser";import y from"cors";import
|
|
1
|
+
import d from"http";import l from"cookie-parser";import y from"cors";import m from"express";import h from"express-fileupload";import{rateLimit as f}from"express-rate-limit";import b from"helmet";import{pinoHttp as x}from"pino-http";import{Instance as u}from "../../instance/index.min.mjs";import{getMediaDuration as g}from "../../utilities/index.min.mjs";import{Request as R}from "../requests.min.mjs";import{StatusCodes as S}from "../types.min.mjs";import{Server as v}from "./base.min.mjs";class C extends v{constructor(a){const r=m(),c=u.get();super(d.createServer(r),a,{parseRequest:async e=>{const s=Object.fromEntries(await Promise.all(Object.entries(e.files??{}).map(async([o,t])=>{const i=Array.isArray(t)?t:[t],p=await Promise.all(i.map(async n=>({name:n.name,type:n.mimetype,size:n.size,isTruncated:n.truncated,data:n.data,duration:await g(n.data)})));return[o,p]})));return new R({ip:e.ip,body:e.body??{},cookies:e.cookies??{},params:e.params??{},query:e.query??{},method:e.method,path:e.path,headers:e.headers,files:s})},handleResponse:async(e,s)=>{if(s.piped)s.body.pipe(e);else{Object.entries(s.headers).forEach(([t,i])=>e.header(t,i)),Object.entries(s.cookies).forEach(([t,{value:i,...p}])=>e.cookie(t,i,p));const o=s.body===null||s.body===void 0?"json":"send";e.status(s.status)[o](s.body).end()}},registerRoute:(e,s,o)=>{r[e]?.(s,async(t,i)=>o(t,i))},registerErrorHandler:e=>{r.use(async(s,o,t,i)=>e(s,o,t))},registerNotFoundHandler:e=>{r.use(async(s,o,t)=>e(s,o))},start:async e=>new Promise((s,o)=>{try{const t=this.server.listen({host:"0.0.0.0",port:e},async()=>s(!0));u.on("close",t.close,1)}catch(t){o(t)}})}),r.disable("x-powered-by"),a.requests.log&&r.use(x({logger:c.log})),r.use(m.json()),r.use(m.text()),r.use(l()),r.use(b({crossOriginResourcePolicy:{policy:"cross-origin"},contentSecurityPolicy:!1})),r.use(y(this.cors)),r.use(m.urlencoded({extended:!1})),a.publicPath&&r.use(m.static(a.publicPath)),r.use(h({limits:{fileSize:c.settings.utils.maxFileUploadSizeInMb*1024*1024},useTempFiles:!1})),a.requests.rateLimit.enabled&&r.use(f({windowMs:a.requests.rateLimit.periodInMs,limit:a.requests.rateLimit.limit,handler:(e,s)=>s.status(S.TooManyRequests).json([{message:"Too Many Requests"}])}))}}export{C as ExpressServer};
|
|
2
2
|
//# sourceMappingURL=express.min.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/server/impls/express.ts"],"sourcesContent":["import http from 'http'\n\nimport cookie from 'cookie-parser'\nimport cors from 'cors'\nimport express from 'express'\nimport fileUpload from 'express-fileupload'\nimport { rateLimit } from 'express-rate-limit'\n// import slowDown from 'express-slow-down'\nimport helmet from 'helmet'\nimport { pinoHttp } from 'pino-http'\n\nimport { Instance } from '../../instance'\nimport { getMediaDuration } from '../../utilities'\nimport type { ServerConfig } from '../pipes'\nimport { Request } from '../requests'\nimport { type IncomingFile, StatusCodes } from '../types'\nimport { Server } from './base'\n\nexport class ExpressServer extends Server<express.Request, express.Response> {\n\
|
|
1
|
+
{"version":3,"sources":["../../../../src/server/impls/express.ts"],"sourcesContent":["import http from 'http'\n\nimport cookie from 'cookie-parser'\nimport cors from 'cors'\nimport express from 'express'\nimport fileUpload from 'express-fileupload'\nimport { rateLimit } from 'express-rate-limit'\n// import slowDown from 'express-slow-down'\nimport helmet from 'helmet'\nimport { pinoHttp } from 'pino-http'\n\nimport { Instance } from '../../instance'\nimport { getMediaDuration } from '../../utilities'\nimport type { ServerConfig } from '../pipes'\nimport { Request } from '../requests'\nimport { type IncomingFile, StatusCodes } from '../types'\nimport { Server } from './base'\n\nexport class ExpressServer extends Server<express.Request, express.Response> {\n\tconstructor(config: ServerConfig) {\n\t\tconst app = express()\n\t\tconst instance = Instance.get()\n\t\tsuper(http.createServer(app), config, {\n\t\t\tparseRequest: async (req) => {\n\t\t\t\tconst files = Object.fromEntries(\n\t\t\t\t\tawait Promise.all(\n\t\t\t\t\t\tObject.entries(req.files ?? {}).map(async ([key, file]) => {\n\t\t\t\t\t\t\tconst uploads = Array.isArray(file) ? file : [file]\n\t\t\t\t\t\t\tconst fileArray: IncomingFile[] = await Promise.all(\n\t\t\t\t\t\t\t\tuploads.map(async (f) => ({\n\t\t\t\t\t\t\t\t\tname: f.name,\n\t\t\t\t\t\t\t\t\ttype: f.mimetype,\n\t\t\t\t\t\t\t\t\tsize: f.size,\n\t\t\t\t\t\t\t\t\tisTruncated: f.truncated,\n\t\t\t\t\t\t\t\t\tdata: f.data,\n\t\t\t\t\t\t\t\t\tduration: await getMediaDuration(f.data),\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn <const>[key, fileArray]\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\n\t\t\t\treturn new Request<any>({\n\t\t\t\t\tip: req.ip,\n\t\t\t\t\tbody: req.body ?? {},\n\t\t\t\t\tcookies: req.cookies ?? {},\n\t\t\t\t\tparams: req.params ?? {},\n\t\t\t\t\tquery: req.query ?? {},\n\t\t\t\t\tmethod: <any>req.method,\n\t\t\t\t\tpath: req.path,\n\t\t\t\t\theaders: req.headers,\n\t\t\t\t\tfiles,\n\t\t\t\t})\n\t\t\t},\n\t\t\thandleResponse: async (res, response) => {\n\t\t\t\tif (!response.piped) {\n\t\t\t\t\tObject.entries(response.headers).forEach(([key, value]) => res.header(key, value as string))\n\t\t\t\t\tObject.entries(response.cookies).forEach(([key, { value, ...opts }]) => res.cookie(key, value, opts))\n\t\t\t\t\tconst type = response.body === null || response.body === undefined ? 'json' : 'send'\n\t\t\t\t\tres.status(response.status)[type](response.body).end()\n\t\t\t\t} else {\n\t\t\t\t\tresponse.body.pipe(res)\n\t\t\t\t}\n\t\t\t},\n\t\t\tregisterRoute: (method, path, cb) => {\n\t\t\t\tapp[method]?.(path, async (req, res) => cb(req, res))\n\t\t\t},\n\t\t\tregisterErrorHandler: (cb) => {\n\t\t\t\tapp.use(async (err, req, res, _next) => cb(err, req, res))\n\t\t\t},\n\t\t\tregisterNotFoundHandler: (cb) => {\n\t\t\t\tapp.use(async (req, res, _next) => cb(req, res))\n\t\t\t},\n\t\t\tstart: async (port) =>\n\t\t\t\tnew Promise((resolve: (s: boolean) => void, reject: (e: Error) => void) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst app = this.server.listen({ host: '0.0.0.0', port }, async () => resolve(true))\n\t\t\t\t\t\tInstance.on('close', app.close, 1)\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\treject(<Error>err)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t})\n\n\t\tapp.disable('x-powered-by')\n\t\tif (config.requests.log) app.use(pinoHttp({ logger: instance.log }))\n\t\tapp.use(express.json())\n\t\tapp.use(express.text())\n\t\tapp.use(cookie())\n\t\tapp.use(\n\t\t\thelmet({\n\t\t\t\tcrossOriginResourcePolicy: { policy: 'cross-origin' },\n\t\t\t\tcontentSecurityPolicy: false,\n\t\t\t}),\n\t\t)\n\t\tapp.use(cors(this.cors))\n\t\tapp.use(express.urlencoded({ extended: false }))\n\t\tif (config.publicPath) app.use(express.static(config.publicPath))\n\t\tapp.use(\n\t\t\tfileUpload({\n\t\t\t\tlimits: { fileSize: instance.settings.utils.maxFileUploadSizeInMb * 1024 * 1024 },\n\t\t\t\tuseTempFiles: false,\n\t\t\t}),\n\t\t)\n\t\tif (config.requests.rateLimit.enabled)\n\t\t\tapp.use(\n\t\t\t\trateLimit({\n\t\t\t\t\twindowMs: config.requests.rateLimit.periodInMs,\n\t\t\t\t\tlimit: config.requests.rateLimit.limit,\n\t\t\t\t\thandler: (_: express.Request, res: express.Response) =>\n\t\t\t\t\t\tres.status(StatusCodes.TooManyRequests).json([{ message: 'Too Many Requests' }]),\n\t\t\t\t}),\n\t\t\t)\n\t\t/* if (this.settings.slowdown.enabled) app.use(slowDown({\n\t\t\twindowMs: this.settings.slowdown.periodInMs,\n\t\t\tdelayAfter: this.settings.slowdown.delayAfter,\n\t\t\tdelayMs: this.settings.slowdown.delayInMs\n\t\t})) */\n\t}\n}\n"],"mappings":"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","names":["http","cookie","cors","express","fileUpload","rateLimit","helmet","pinoHttp","Instance","getMediaDuration","Request","StatusCodes","Server","ExpressServer","config","app","instance","req","files","key","file","uploads","fileArray","f","res","response","value","opts","type","method","path","cb","err","_next","port","resolve","reject","_"]}
|
|
@@ -12,7 +12,6 @@ import { Request } from "../requests.mjs";
|
|
|
12
12
|
import { StatusCodes } from "../types.mjs";
|
|
13
13
|
import { Server } from "./base.mjs";
|
|
14
14
|
class ExpressServer extends Server {
|
|
15
|
-
#expressApp;
|
|
16
15
|
constructor(config) {
|
|
17
16
|
const app = express();
|
|
18
17
|
const instance = Instance.get();
|
|
@@ -59,13 +58,13 @@ class ExpressServer extends Server {
|
|
|
59
58
|
}
|
|
60
59
|
},
|
|
61
60
|
registerRoute: (method, path, cb) => {
|
|
62
|
-
|
|
61
|
+
app[method]?.(path, async (req, res) => cb(req, res));
|
|
63
62
|
},
|
|
64
63
|
registerErrorHandler: (cb) => {
|
|
65
|
-
|
|
64
|
+
app.use(async (err, req, res, _next) => cb(err, req, res));
|
|
66
65
|
},
|
|
67
66
|
registerNotFoundHandler: (cb) => {
|
|
68
|
-
|
|
67
|
+
app.use(async (req, res, _next) => cb(req, res));
|
|
69
68
|
},
|
|
70
69
|
start: async (port) => new Promise((resolve, reject) => {
|
|
71
70
|
try {
|
|
@@ -76,7 +75,6 @@ class ExpressServer extends Server {
|
|
|
76
75
|
}
|
|
77
76
|
})
|
|
78
77
|
});
|
|
79
|
-
this.#expressApp = app;
|
|
80
78
|
app.disable("x-powered-by");
|
|
81
79
|
if (config.requests.log) app.use(pinoHttp({ logger: instance.log }));
|
|
82
80
|
app.use(express.json());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/server/impls/express.ts"],"sourcesContent":["import http from 'http'\n\nimport cookie from 'cookie-parser'\nimport cors from 'cors'\nimport express from 'express'\nimport fileUpload from 'express-fileupload'\nimport { rateLimit } from 'express-rate-limit'\n// import slowDown from 'express-slow-down'\nimport helmet from 'helmet'\nimport { pinoHttp } from 'pino-http'\n\nimport { Instance } from '../../instance'\nimport { getMediaDuration } from '../../utilities'\nimport type { ServerConfig } from '../pipes'\nimport { Request } from '../requests'\nimport { type IncomingFile, StatusCodes } from '../types'\nimport { Server } from './base'\n\nexport class ExpressServer extends Server<express.Request, express.Response> {\n\
|
|
1
|
+
{"version":3,"sources":["../../../../src/server/impls/express.ts"],"sourcesContent":["import http from 'http'\n\nimport cookie from 'cookie-parser'\nimport cors from 'cors'\nimport express from 'express'\nimport fileUpload from 'express-fileupload'\nimport { rateLimit } from 'express-rate-limit'\n// import slowDown from 'express-slow-down'\nimport helmet from 'helmet'\nimport { pinoHttp } from 'pino-http'\n\nimport { Instance } from '../../instance'\nimport { getMediaDuration } from '../../utilities'\nimport type { ServerConfig } from '../pipes'\nimport { Request } from '../requests'\nimport { type IncomingFile, StatusCodes } from '../types'\nimport { Server } from './base'\n\nexport class ExpressServer extends Server<express.Request, express.Response> {\n\tconstructor(config: ServerConfig) {\n\t\tconst app = express()\n\t\tconst instance = Instance.get()\n\t\tsuper(http.createServer(app), config, {\n\t\t\tparseRequest: async (req) => {\n\t\t\t\tconst files = Object.fromEntries(\n\t\t\t\t\tawait Promise.all(\n\t\t\t\t\t\tObject.entries(req.files ?? {}).map(async ([key, file]) => {\n\t\t\t\t\t\t\tconst uploads = Array.isArray(file) ? file : [file]\n\t\t\t\t\t\t\tconst fileArray: IncomingFile[] = await Promise.all(\n\t\t\t\t\t\t\t\tuploads.map(async (f) => ({\n\t\t\t\t\t\t\t\t\tname: f.name,\n\t\t\t\t\t\t\t\t\ttype: f.mimetype,\n\t\t\t\t\t\t\t\t\tsize: f.size,\n\t\t\t\t\t\t\t\t\tisTruncated: f.truncated,\n\t\t\t\t\t\t\t\t\tdata: f.data,\n\t\t\t\t\t\t\t\t\tduration: await getMediaDuration(f.data),\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn <const>[key, fileArray]\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\n\t\t\t\treturn new Request<any>({\n\t\t\t\t\tip: req.ip,\n\t\t\t\t\tbody: req.body ?? {},\n\t\t\t\t\tcookies: req.cookies ?? {},\n\t\t\t\t\tparams: req.params ?? {},\n\t\t\t\t\tquery: req.query ?? {},\n\t\t\t\t\tmethod: <any>req.method,\n\t\t\t\t\tpath: req.path,\n\t\t\t\t\theaders: req.headers,\n\t\t\t\t\tfiles,\n\t\t\t\t})\n\t\t\t},\n\t\t\thandleResponse: async (res, response) => {\n\t\t\t\tif (!response.piped) {\n\t\t\t\t\tObject.entries(response.headers).forEach(([key, value]) => res.header(key, value as string))\n\t\t\t\t\tObject.entries(response.cookies).forEach(([key, { value, ...opts }]) => res.cookie(key, value, opts))\n\t\t\t\t\tconst type = response.body === null || response.body === undefined ? 'json' : 'send'\n\t\t\t\t\tres.status(response.status)[type](response.body).end()\n\t\t\t\t} else {\n\t\t\t\t\tresponse.body.pipe(res)\n\t\t\t\t}\n\t\t\t},\n\t\t\tregisterRoute: (method, path, cb) => {\n\t\t\t\tapp[method]?.(path, async (req, res) => cb(req, res))\n\t\t\t},\n\t\t\tregisterErrorHandler: (cb) => {\n\t\t\t\tapp.use(async (err, req, res, _next) => cb(err, req, res))\n\t\t\t},\n\t\t\tregisterNotFoundHandler: (cb) => {\n\t\t\t\tapp.use(async (req, res, _next) => cb(req, res))\n\t\t\t},\n\t\t\tstart: async (port) =>\n\t\t\t\tnew Promise((resolve: (s: boolean) => void, reject: (e: Error) => void) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst app = this.server.listen({ host: '0.0.0.0', port }, async () => resolve(true))\n\t\t\t\t\t\tInstance.on('close', app.close, 1)\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\treject(<Error>err)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t})\n\n\t\tapp.disable('x-powered-by')\n\t\tif (config.requests.log) app.use(pinoHttp({ logger: instance.log }))\n\t\tapp.use(express.json())\n\t\tapp.use(express.text())\n\t\tapp.use(cookie())\n\t\tapp.use(\n\t\t\thelmet({\n\t\t\t\tcrossOriginResourcePolicy: { policy: 'cross-origin' },\n\t\t\t\tcontentSecurityPolicy: false,\n\t\t\t}),\n\t\t)\n\t\tapp.use(cors(this.cors))\n\t\tapp.use(express.urlencoded({ extended: false }))\n\t\tif (config.publicPath) app.use(express.static(config.publicPath))\n\t\tapp.use(\n\t\t\tfileUpload({\n\t\t\t\tlimits: { fileSize: instance.settings.utils.maxFileUploadSizeInMb * 1024 * 1024 },\n\t\t\t\tuseTempFiles: false,\n\t\t\t}),\n\t\t)\n\t\tif (config.requests.rateLimit.enabled)\n\t\t\tapp.use(\n\t\t\t\trateLimit({\n\t\t\t\t\twindowMs: config.requests.rateLimit.periodInMs,\n\t\t\t\t\tlimit: config.requests.rateLimit.limit,\n\t\t\t\t\thandler: (_: express.Request, res: express.Response) =>\n\t\t\t\t\t\tres.status(StatusCodes.TooManyRequests).json([{ message: 'Too Many Requests' }]),\n\t\t\t\t}),\n\t\t\t)\n\t\t/* if (this.settings.slowdown.enabled) app.use(slowDown({\n\t\t\twindowMs: this.settings.slowdown.periodInMs,\n\t\t\tdelayAfter: this.settings.slowdown.delayAfter,\n\t\t\tdelayMs: this.settings.slowdown.delayInMs\n\t\t})) */\n\t}\n}\n"],"mappings":"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","names":["app"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{v as
|
|
1
|
+
import{v as a}from"valleyed";import{Methods as u}from "./types.min.mjs";function i(...o){const t={params:"",headers:"",query:"",body:"",cookies:"",response:"",responseHeaders:"",responseCookies:"",defaultStatusCode:"",defaultContentType:""};function e(s,r){return s?r?typeof s=="number"||typeof s=="string"||typeof s=="function"?r:a.merge(s,r):s:r}return Object.fromEntries(Object.keys(t).map(s=>[s,o.map(r=>r[s]).reduce(e,null)]))}const p=(o,t)=>t.map(e=>({...o,...e,path:`${o.path}/${e.path}`,groups:[...o.groups??[],...e.groups??[]],middlewares:[...o.middlewares??[],...e.middlewares??[]],responseMiddlewares:[...o.responseMiddlewares??[],...e.responseMiddlewares??[]],schema:i(o.schema??{},e.schema??{}),security:[...o.security??[],...e.security??[]]}));class d{#t={path:""};#s=[];#o=[];constructor(t={path:""}){this.#t=t}#e(t){return(e,s={})=>r=>{const n=p(this.#t,[{...s,path:e,method:t,handler:r}])[0];return this.#s.push(n),n}}head=this.#e(u.head);get=this.#e(u.get);post=this.#e(u.post);put=this.#e(u.put);patch=this.#e(u.patch);delete=this.#e(u.delete);options=this.#e(u.options);nest(...t){t.forEach(e=>this.#o.push(e))}get routes(){return[...this.#s].concat(this.#o.flatMap(t=>p(this.#t,t.routes)))}}export{d as Router};
|
|
2
2
|
//# sourceMappingURL=routes.min.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/server/routes.ts"],"sourcesContent":["import { v } from 'valleyed'\n\nimport {\n\tMethods,\n\ttype MergeRouteDefs,\n\ttype MethodsEnum,\n\ttype Route,\n\ttype RouteConfig,\n\ttype RouteDef,\n\ttype RouteDefHandler,\n\ttype RouterConfig,\n} from './types'\n\nfunction mergeSchemas(...schemas: RouteDef[]) {\n\ttype Keys = Record<keyof RouteDef, string>\n\tconst k: Keys = {\n\t\tparams: '',\n\t\theaders: '',\n\t\tquery: '',\n\t\tbody: '',\n\t\tcookies: '',\n\t\tresponse: '',\n\t\tresponseHeaders: '',\n\t\tresponseCookies: '',\n\t\tdefaultStatusCode: '',\n\t\tdefaultContentType: '',\n\t}\n\tfunction merge<T extends RouteDef[keyof Keys]>(acc: T | null, cur: T) {\n\t\tif (!acc) return cur\n\t\tif (!cur) return acc\n\t\tif (typeof acc === 'number') return cur\n\t\tif (typeof acc === 'string') return cur\n\t\tif (typeof acc === 'function') return cur\n\t\treturn v.merge(acc, cur as any)\n\t}\n\treturn Object.fromEntries(\n\t\tObject.keys(k).map((key) => [\n\t\t\tkey,\n\t\t\tschemas.map((s) => s[key] as RouteDef[keyof Keys]).reduce<RouteDef[keyof Keys] | null>(merge, null),\n\t\t]),\n\t) as RouteDef\n}\n\nconst groupRoutes = <T extends RouteDef, R extends RouteDef>(config: RouterConfig<T>, routes: Route<R>[]) =>\n\troutes.map((route) => ({\n\t\t...config,\n\t\t...route,\n\t\tpath: `${config.path}/${route.path}`,\n\t\tgroups: [...(config.groups ?? []), ...(route.groups ?? [])],\n\t\tmiddlewares: [...(config.middlewares ?? []), ...(route.middlewares ?? [])],\n\t\tschema: mergeSchemas(config.schema ?? {}, route.schema ?? {}),\n\t\tsecurity: [...(config.security ?? []), ...(route.security ?? [])],\n\t})) as Route<MergeRouteDefs<T, R>>[]\n\nexport class Router<T extends RouteDef> {\n\t#config: RouterConfig<T> = { path: '' }\n\t#routes: Route<any>[] = []\n\t#children: Router<any>[] = []\n\n\tconstructor(config: RouterConfig<T> = { path: '' }) {\n\t\tthis.#config = config\n\t}\n\n\t#wrap(method: MethodsEnum) {\n\t\treturn <R extends RouteDef>(path: string, config: RouteConfig<R> = {}) =>\n\t\t\t(handler: RouteDefHandler<MergeRouteDefs<T, R>>) => {\n\t\t\t\tconst route = groupRoutes(this.#config, [{ ...config, path, method, handler: handler as any }])[0]\n\t\t\t\tthis.#routes.push(route)\n\t\t\t\treturn route\n\t\t\t}\n\t}\n\n\thead = this.#wrap(Methods.head)\n\tget = this.#wrap(Methods.get)\n\tpost = this.#wrap(Methods.post)\n\tput = this.#wrap(Methods.put)\n\tpatch = this.#wrap(Methods.patch)\n\tdelete = this.#wrap(Methods.delete)\n\toptions = this.#wrap(Methods.options)\n\n\tnest(...routers: Router<any>[]) {\n\t\trouters.forEach((router) => this.#children.push(router))\n\t}\n\n\tget routes() {\n\t\treturn [...this.#routes].concat(this.#children.flatMap((child) => groupRoutes(this.#config, child.routes)))\n\t}\n}\n"],"mappings":"AAAA,OAAS,KAAAA,MAAS,WAElB,OACC,WAAAC,MAQM,UAEP,SAASC,KAAgBC,EAAqB,CAE7C,MAAMC,EAAU,CACf,OAAQ,GACR,QAAS,GACT,MAAO,GACP,KAAM,GACN,QAAS,GACT,SAAU,GACV,gBAAiB,GACjB,gBAAiB,GACjB,kBAAmB,GACnB,mBAAoB,EACrB,EACA,SAASC,EAAsCC,EAAeC,EAAQ,CACrE,OAAKD,EACAC,EACD,OAAOD,GAAQ,UACf,OAAOA,GAAQ,UACf,OAAOA,GAAQ,WAAmBC,EAC/BP,EAAE,MAAMM,EAAKC,CAAU,EAJbD,EADAC,CAMlB,CACA,OAAO,OAAO,YACb,OAAO,KAAKH,CAAC,EAAE,IAAKI,GAAQ,CAC3BA,EACAL,EAAQ,IAAKM,GAAMA,EAAED,CAAG,CAAyB,EAAE,OAAoCH,EAAO,IAAI,CACnG,CAAC,CACF,CACD,CAEA,MAAMK,EAAc,CAAyCC,EAAyBC,IACrFA,EAAO,IAAKC,IAAW,CACtB,GAAGF,EACH,GAAGE,EACH,KAAM,GAAGF,EAAO,IAAI,IAAIE,EAAM,IAAI,GAClC,OAAQ,CAAC,GAAIF,EAAO,QAAU,CAAC,EAAI,GAAIE,EAAM,QAAU,CAAC,CAAE,EAC1D,YAAa,CAAC,GAAIF,EAAO,aAAe,CAAC,EAAI,GAAIE,EAAM,aAAe,CAAC,CAAE,EACzE,OAAQX,EAAaS,EAAO,QAAU,CAAC,EAAGE,EAAM,QAAU,CAAC,CAAC,EAC5D,SAAU,CAAC,GAAIF,EAAO,UAAY,CAAC,EAAI,GAAIE,EAAM,UAAY,CAAC,CAAE,CACjE,EAAE,EAEI,MAAMC,CAA2B,CACvCC,GAA2B,CAAE,KAAM,EAAG,EACtCC,GAAwB,CAAC,EACzBC,GAA2B,CAAC,EAE5B,YAAYN,EAA0B,CAAE,KAAM,EAAG,EAAG,CACnD,KAAKI,GAAUJ,CAChB,CAEAO,GAAMC,EAAqB,CAC1B,MAAO,CAAqBC,EAAcT,EAAyB,CAAC,IAClEU,GAAmD,CACnD,MAAMR,EAAQH,EAAY,KAAKK,GAAS,CAAC,CAAE,GAAGJ,EAAQ,KAAAS,EAAM,OAAAD,EAAQ,QAASE,CAAe,CAAC,CAAC,EAAE,CAAC,EACjG,YAAKL,GAAQ,KAAKH,CAAK,EAChBA,CACR,CACF,CAEA,KAAO,KAAKK,GAAMjB,EAAQ,IAAI,EAC9B,IAAM,KAAKiB,GAAMjB,EAAQ,GAAG,EAC5B,KAAO,KAAKiB,GAAMjB,EAAQ,IAAI,EAC9B,IAAM,KAAKiB,GAAMjB,EAAQ,GAAG,EAC5B,MAAQ,KAAKiB,GAAMjB,EAAQ,KAAK,EAChC,OAAS,KAAKiB,GAAMjB,EAAQ,MAAM,EAClC,QAAU,KAAKiB,GAAMjB,EAAQ,OAAO,EAEpC,QAAQqB,EAAwB,CAC/BA,EAAQ,QAASC,GAAW,KAAKN,GAAU,KAAKM,CAAM,CAAC,CACxD,CAEA,IAAI,QAAS,CACZ,MAAO,CAAC,GAAG,KAAKP,EAAO,EAAE,OAAO,KAAKC,GAAU,QAASO,GAAUd,EAAY,KAAKK,GAASS,EAAM,MAAM,CAAC,CAAC,CAC3G,CACD","names":["v","Methods","mergeSchemas","schemas","k","merge","acc","cur","key","s","groupRoutes","config","routes","route","Router","#config","#routes","#children","#wrap","method","path","handler","routers","router","child"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/server/routes.ts"],"sourcesContent":["import { v } from 'valleyed'\n\nimport {\n\tMethods,\n\ttype MergeRouteDefs,\n\ttype MethodsEnum,\n\ttype Route,\n\ttype RouteConfig,\n\ttype RouteDef,\n\ttype RouteDefHandler,\n\ttype RouterConfig,\n} from './types'\n\nfunction mergeSchemas(...schemas: RouteDef[]) {\n\ttype Keys = Record<keyof RouteDef, string>\n\tconst k: Keys = {\n\t\tparams: '',\n\t\theaders: '',\n\t\tquery: '',\n\t\tbody: '',\n\t\tcookies: '',\n\t\tresponse: '',\n\t\tresponseHeaders: '',\n\t\tresponseCookies: '',\n\t\tdefaultStatusCode: '',\n\t\tdefaultContentType: '',\n\t}\n\tfunction merge<T extends RouteDef[keyof Keys]>(acc: T | null, cur: T) {\n\t\tif (!acc) return cur\n\t\tif (!cur) return acc\n\t\tif (typeof acc === 'number') return cur\n\t\tif (typeof acc === 'string') return cur\n\t\tif (typeof acc === 'function') return cur\n\t\treturn v.merge(acc, cur as any)\n\t}\n\treturn Object.fromEntries(\n\t\tObject.keys(k).map((key) => [\n\t\t\tkey,\n\t\t\tschemas.map((s) => s[key] as RouteDef[keyof Keys]).reduce<RouteDef[keyof Keys] | null>(merge, null),\n\t\t]),\n\t) as RouteDef\n}\n\nconst groupRoutes = <T extends RouteDef, R extends RouteDef>(config: RouterConfig<T>, routes: Route<R>[]) =>\n\troutes.map((route) => ({\n\t\t...config,\n\t\t...route,\n\t\tpath: `${config.path}/${route.path}`,\n\t\tgroups: [...(config.groups ?? []), ...(route.groups ?? [])],\n\t\tmiddlewares: [...(config.middlewares ?? []), ...(route.middlewares ?? [])],\n\t\tresponseMiddlewares: [...(config.responseMiddlewares ?? []), ...(route.responseMiddlewares ?? [])],\n\t\tschema: mergeSchemas(config.schema ?? {}, route.schema ?? {}),\n\t\tsecurity: [...(config.security ?? []), ...(route.security ?? [])],\n\t})) as Route<MergeRouteDefs<T, R>>[]\n\nexport class Router<T extends RouteDef> {\n\t#config: RouterConfig<T> = { path: '' }\n\t#routes: Route<any>[] = []\n\t#children: Router<any>[] = []\n\n\tconstructor(config: RouterConfig<T> = { path: '' }) {\n\t\tthis.#config = config\n\t}\n\n\t#wrap(method: MethodsEnum) {\n\t\treturn <R extends RouteDef>(path: string, config: RouteConfig<R> = {}) =>\n\t\t\t(handler: RouteDefHandler<MergeRouteDefs<T, R>>) => {\n\t\t\t\tconst route = groupRoutes(this.#config, [{ ...config, path, method, handler: handler as any }])[0]\n\t\t\t\tthis.#routes.push(route)\n\t\t\t\treturn route\n\t\t\t}\n\t}\n\n\thead = this.#wrap(Methods.head)\n\tget = this.#wrap(Methods.get)\n\tpost = this.#wrap(Methods.post)\n\tput = this.#wrap(Methods.put)\n\tpatch = this.#wrap(Methods.patch)\n\tdelete = this.#wrap(Methods.delete)\n\toptions = this.#wrap(Methods.options)\n\n\tnest(...routers: Router<any>[]) {\n\t\trouters.forEach((router) => this.#children.push(router))\n\t}\n\n\tget routes() {\n\t\treturn [...this.#routes].concat(this.#children.flatMap((child) => groupRoutes(this.#config, child.routes)))\n\t}\n}\n"],"mappings":"AAAA,OAAS,KAAAA,MAAS,WAElB,OACC,WAAAC,MAQM,UAEP,SAASC,KAAgBC,EAAqB,CAE7C,MAAMC,EAAU,CACf,OAAQ,GACR,QAAS,GACT,MAAO,GACP,KAAM,GACN,QAAS,GACT,SAAU,GACV,gBAAiB,GACjB,gBAAiB,GACjB,kBAAmB,GACnB,mBAAoB,EACrB,EACA,SAASC,EAAsCC,EAAeC,EAAQ,CACrE,OAAKD,EACAC,EACD,OAAOD,GAAQ,UACf,OAAOA,GAAQ,UACf,OAAOA,GAAQ,WAAmBC,EAC/BP,EAAE,MAAMM,EAAKC,CAAU,EAJbD,EADAC,CAMlB,CACA,OAAO,OAAO,YACb,OAAO,KAAKH,CAAC,EAAE,IAAKI,GAAQ,CAC3BA,EACAL,EAAQ,IAAKM,GAAMA,EAAED,CAAG,CAAyB,EAAE,OAAoCH,EAAO,IAAI,CACnG,CAAC,CACF,CACD,CAEA,MAAMK,EAAc,CAAyCC,EAAyBC,IACrFA,EAAO,IAAKC,IAAW,CACtB,GAAGF,EACH,GAAGE,EACH,KAAM,GAAGF,EAAO,IAAI,IAAIE,EAAM,IAAI,GAClC,OAAQ,CAAC,GAAIF,EAAO,QAAU,CAAC,EAAI,GAAIE,EAAM,QAAU,CAAC,CAAE,EAC1D,YAAa,CAAC,GAAIF,EAAO,aAAe,CAAC,EAAI,GAAIE,EAAM,aAAe,CAAC,CAAE,EACzE,oBAAqB,CAAC,GAAIF,EAAO,qBAAuB,CAAC,EAAI,GAAIE,EAAM,qBAAuB,CAAC,CAAE,EACjG,OAAQX,EAAaS,EAAO,QAAU,CAAC,EAAGE,EAAM,QAAU,CAAC,CAAC,EAC5D,SAAU,CAAC,GAAIF,EAAO,UAAY,CAAC,EAAI,GAAIE,EAAM,UAAY,CAAC,CAAE,CACjE,EAAE,EAEI,MAAMC,CAA2B,CACvCC,GAA2B,CAAE,KAAM,EAAG,EACtCC,GAAwB,CAAC,EACzBC,GAA2B,CAAC,EAE5B,YAAYN,EAA0B,CAAE,KAAM,EAAG,EAAG,CACnD,KAAKI,GAAUJ,CAChB,CAEAO,GAAMC,EAAqB,CAC1B,MAAO,CAAqBC,EAAcT,EAAyB,CAAC,IAClEU,GAAmD,CACnD,MAAMR,EAAQH,EAAY,KAAKK,GAAS,CAAC,CAAE,GAAGJ,EAAQ,KAAAS,EAAM,OAAAD,EAAQ,QAASE,CAAe,CAAC,CAAC,EAAE,CAAC,EACjG,YAAKL,GAAQ,KAAKH,CAAK,EAChBA,CACR,CACF,CAEA,KAAO,KAAKK,GAAMjB,EAAQ,IAAI,EAC9B,IAAM,KAAKiB,GAAMjB,EAAQ,GAAG,EAC5B,KAAO,KAAKiB,GAAMjB,EAAQ,IAAI,EAC9B,IAAM,KAAKiB,GAAMjB,EAAQ,GAAG,EAC5B,MAAQ,KAAKiB,GAAMjB,EAAQ,KAAK,EAChC,OAAS,KAAKiB,GAAMjB,EAAQ,MAAM,EAClC,QAAU,KAAKiB,GAAMjB,EAAQ,OAAO,EAEpC,QAAQqB,EAAwB,CAC/BA,EAAQ,QAASC,GAAW,KAAKN,GAAU,KAAKM,CAAM,CAAC,CACxD,CAEA,IAAI,QAAS,CACZ,MAAO,CAAC,GAAG,KAAKP,EAAO,EAAE,OAAO,KAAKC,GAAU,QAASO,GAAUd,EAAY,KAAKK,GAASS,EAAM,MAAM,CAAC,CAAC,CAC3G,CACD","names":["v","Methods","mergeSchemas","schemas","k","merge","acc","cur","key","s","groupRoutes","config","routes","route","Router","#config","#routes","#children","#wrap","method","path","handler","routers","router","child"]}
|
|
@@ -36,6 +36,7 @@ const groupRoutes = (config, routes) => routes.map((route) => ({
|
|
|
36
36
|
path: `${config.path}/${route.path}`,
|
|
37
37
|
groups: [...config.groups ?? [], ...route.groups ?? []],
|
|
38
38
|
middlewares: [...config.middlewares ?? [], ...route.middlewares ?? []],
|
|
39
|
+
responseMiddlewares: [...config.responseMiddlewares ?? [], ...route.responseMiddlewares ?? []],
|
|
39
40
|
schema: mergeSchemas(config.schema ?? {}, route.schema ?? {}),
|
|
40
41
|
security: [...config.security ?? [], ...route.security ?? []]
|
|
41
42
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/server/routes.ts"],"sourcesContent":["import { v } from 'valleyed'\n\nimport {\n\tMethods,\n\ttype MergeRouteDefs,\n\ttype MethodsEnum,\n\ttype Route,\n\ttype RouteConfig,\n\ttype RouteDef,\n\ttype RouteDefHandler,\n\ttype RouterConfig,\n} from './types'\n\nfunction mergeSchemas(...schemas: RouteDef[]) {\n\ttype Keys = Record<keyof RouteDef, string>\n\tconst k: Keys = {\n\t\tparams: '',\n\t\theaders: '',\n\t\tquery: '',\n\t\tbody: '',\n\t\tcookies: '',\n\t\tresponse: '',\n\t\tresponseHeaders: '',\n\t\tresponseCookies: '',\n\t\tdefaultStatusCode: '',\n\t\tdefaultContentType: '',\n\t}\n\tfunction merge<T extends RouteDef[keyof Keys]>(acc: T | null, cur: T) {\n\t\tif (!acc) return cur\n\t\tif (!cur) return acc\n\t\tif (typeof acc === 'number') return cur\n\t\tif (typeof acc === 'string') return cur\n\t\tif (typeof acc === 'function') return cur\n\t\treturn v.merge(acc, cur as any)\n\t}\n\treturn Object.fromEntries(\n\t\tObject.keys(k).map((key) => [\n\t\t\tkey,\n\t\t\tschemas.map((s) => s[key] as RouteDef[keyof Keys]).reduce<RouteDef[keyof Keys] | null>(merge, null),\n\t\t]),\n\t) as RouteDef\n}\n\nconst groupRoutes = <T extends RouteDef, R extends RouteDef>(config: RouterConfig<T>, routes: Route<R>[]) =>\n\troutes.map((route) => ({\n\t\t...config,\n\t\t...route,\n\t\tpath: `${config.path}/${route.path}`,\n\t\tgroups: [...(config.groups ?? []), ...(route.groups ?? [])],\n\t\tmiddlewares: [...(config.middlewares ?? []), ...(route.middlewares ?? [])],\n\t\tschema: mergeSchemas(config.schema ?? {}, route.schema ?? {}),\n\t\tsecurity: [...(config.security ?? []), ...(route.security ?? [])],\n\t})) as Route<MergeRouteDefs<T, R>>[]\n\nexport class Router<T extends RouteDef> {\n\t#config: RouterConfig<T> = { path: '' }\n\t#routes: Route<any>[] = []\n\t#children: Router<any>[] = []\n\n\tconstructor(config: RouterConfig<T> = { path: '' }) {\n\t\tthis.#config = config\n\t}\n\n\t#wrap(method: MethodsEnum) {\n\t\treturn <R extends RouteDef>(path: string, config: RouteConfig<R> = {}) =>\n\t\t\t(handler: RouteDefHandler<MergeRouteDefs<T, R>>) => {\n\t\t\t\tconst route = groupRoutes(this.#config, [{ ...config, path, method, handler: handler as any }])[0]\n\t\t\t\tthis.#routes.push(route)\n\t\t\t\treturn route\n\t\t\t}\n\t}\n\n\thead = this.#wrap(Methods.head)\n\tget = this.#wrap(Methods.get)\n\tpost = this.#wrap(Methods.post)\n\tput = this.#wrap(Methods.put)\n\tpatch = this.#wrap(Methods.patch)\n\tdelete = this.#wrap(Methods.delete)\n\toptions = this.#wrap(Methods.options)\n\n\tnest(...routers: Router<any>[]) {\n\t\trouters.forEach((router) => this.#children.push(router))\n\t}\n\n\tget routes() {\n\t\treturn [...this.#routes].concat(this.#children.flatMap((child) => groupRoutes(this.#config, child.routes)))\n\t}\n}\n"],"mappings":"AAAA,SAAS,SAAS;AAElB;AAAA,EACC;AAAA,OAQM;AAEP,SAAS,gBAAgB,SAAqB;AAE7C,QAAM,IAAU;AAAA,IACf,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,MAAM;AAAA,IACN,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,EACrB;AACA,WAAS,MAAsC,KAAe,KAAQ;AACrE,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,QAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,QAAI,OAAO,QAAQ,WAAY,QAAO;AACtC,WAAO,EAAE,MAAM,KAAK,GAAU;AAAA,EAC/B;AACA,SAAO,OAAO;AAAA,IACb,OAAO,KAAK,CAAC,EAAE,IAAI,CAAC,QAAQ;AAAA,MAC3B;AAAA,MACA,QAAQ,IAAI,CAAC,MAAM,EAAE,GAAG,CAAyB,EAAE,OAAoC,OAAO,IAAI;AAAA,IACnG,CAAC;AAAA,EACF;AACD;AAEA,MAAM,cAAc,CAAyC,QAAyB,WACrF,OAAO,IAAI,CAAC,WAAW;AAAA,EACtB,GAAG;AAAA,EACH,GAAG;AAAA,EACH,MAAM,GAAG,OAAO,IAAI,IAAI,MAAM,IAAI;AAAA,EAClC,QAAQ,CAAC,GAAI,OAAO,UAAU,CAAC,GAAI,GAAI,MAAM,UAAU,CAAC,CAAE;AAAA,EAC1D,aAAa,CAAC,GAAI,OAAO,eAAe,CAAC,GAAI,GAAI,MAAM,eAAe,CAAC,CAAE;AAAA,EACzE,QAAQ,aAAa,OAAO,UAAU,CAAC,GAAG,MAAM,UAAU,CAAC,CAAC;AAAA,EAC5D,UAAU,CAAC,GAAI,OAAO,YAAY,CAAC,GAAI,GAAI,MAAM,YAAY,CAAC,CAAE;AACjE,EAAE;AAEI,MAAM,OAA2B;AAAA,EACvC,UAA2B,EAAE,MAAM,GAAG;AAAA,EACtC,UAAwB,CAAC;AAAA,EACzB,YAA2B,CAAC;AAAA,EAE5B,YAAY,SAA0B,EAAE,MAAM,GAAG,GAAG;AACnD,SAAK,UAAU;AAAA,EAChB;AAAA,EAEA,MAAM,QAAqB;AAC1B,WAAO,CAAqB,MAAc,SAAyB,CAAC,MACnE,CAAC,YAAmD;AACnD,YAAM,QAAQ,YAAY,KAAK,SAAS,CAAC,EAAE,GAAG,QAAQ,MAAM,QAAQ,QAAwB,CAAC,CAAC,EAAE,CAAC;AACjG,WAAK,QAAQ,KAAK,KAAK;AACvB,aAAO;AAAA,IACR;AAAA,EACF;AAAA,EAEA,OAAO,KAAK,MAAM,QAAQ,IAAI;AAAA,EAC9B,MAAM,KAAK,MAAM,QAAQ,GAAG;AAAA,EAC5B,OAAO,KAAK,MAAM,QAAQ,IAAI;AAAA,EAC9B,MAAM,KAAK,MAAM,QAAQ,GAAG;AAAA,EAC5B,QAAQ,KAAK,MAAM,QAAQ,KAAK;AAAA,EAChC,SAAS,KAAK,MAAM,QAAQ,MAAM;AAAA,EAClC,UAAU,KAAK,MAAM,QAAQ,OAAO;AAAA,EAEpC,QAAQ,SAAwB;AAC/B,YAAQ,QAAQ,CAAC,WAAW,KAAK,UAAU,KAAK,MAAM,CAAC;AAAA,EACxD;AAAA,EAEA,IAAI,SAAS;AACZ,WAAO,CAAC,GAAG,KAAK,OAAO,EAAE,OAAO,KAAK,UAAU,QAAQ,CAAC,UAAU,YAAY,KAAK,SAAS,MAAM,MAAM,CAAC,CAAC;AAAA,EAC3G;AACD;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/server/routes.ts"],"sourcesContent":["import { v } from 'valleyed'\n\nimport {\n\tMethods,\n\ttype MergeRouteDefs,\n\ttype MethodsEnum,\n\ttype Route,\n\ttype RouteConfig,\n\ttype RouteDef,\n\ttype RouteDefHandler,\n\ttype RouterConfig,\n} from './types'\n\nfunction mergeSchemas(...schemas: RouteDef[]) {\n\ttype Keys = Record<keyof RouteDef, string>\n\tconst k: Keys = {\n\t\tparams: '',\n\t\theaders: '',\n\t\tquery: '',\n\t\tbody: '',\n\t\tcookies: '',\n\t\tresponse: '',\n\t\tresponseHeaders: '',\n\t\tresponseCookies: '',\n\t\tdefaultStatusCode: '',\n\t\tdefaultContentType: '',\n\t}\n\tfunction merge<T extends RouteDef[keyof Keys]>(acc: T | null, cur: T) {\n\t\tif (!acc) return cur\n\t\tif (!cur) return acc\n\t\tif (typeof acc === 'number') return cur\n\t\tif (typeof acc === 'string') return cur\n\t\tif (typeof acc === 'function') return cur\n\t\treturn v.merge(acc, cur as any)\n\t}\n\treturn Object.fromEntries(\n\t\tObject.keys(k).map((key) => [\n\t\t\tkey,\n\t\t\tschemas.map((s) => s[key] as RouteDef[keyof Keys]).reduce<RouteDef[keyof Keys] | null>(merge, null),\n\t\t]),\n\t) as RouteDef\n}\n\nconst groupRoutes = <T extends RouteDef, R extends RouteDef>(config: RouterConfig<T>, routes: Route<R>[]) =>\n\troutes.map((route) => ({\n\t\t...config,\n\t\t...route,\n\t\tpath: `${config.path}/${route.path}`,\n\t\tgroups: [...(config.groups ?? []), ...(route.groups ?? [])],\n\t\tmiddlewares: [...(config.middlewares ?? []), ...(route.middlewares ?? [])],\n\t\tresponseMiddlewares: [...(config.responseMiddlewares ?? []), ...(route.responseMiddlewares ?? [])],\n\t\tschema: mergeSchemas(config.schema ?? {}, route.schema ?? {}),\n\t\tsecurity: [...(config.security ?? []), ...(route.security ?? [])],\n\t})) as Route<MergeRouteDefs<T, R>>[]\n\nexport class Router<T extends RouteDef> {\n\t#config: RouterConfig<T> = { path: '' }\n\t#routes: Route<any>[] = []\n\t#children: Router<any>[] = []\n\n\tconstructor(config: RouterConfig<T> = { path: '' }) {\n\t\tthis.#config = config\n\t}\n\n\t#wrap(method: MethodsEnum) {\n\t\treturn <R extends RouteDef>(path: string, config: RouteConfig<R> = {}) =>\n\t\t\t(handler: RouteDefHandler<MergeRouteDefs<T, R>>) => {\n\t\t\t\tconst route = groupRoutes(this.#config, [{ ...config, path, method, handler: handler as any }])[0]\n\t\t\t\tthis.#routes.push(route)\n\t\t\t\treturn route\n\t\t\t}\n\t}\n\n\thead = this.#wrap(Methods.head)\n\tget = this.#wrap(Methods.get)\n\tpost = this.#wrap(Methods.post)\n\tput = this.#wrap(Methods.put)\n\tpatch = this.#wrap(Methods.patch)\n\tdelete = this.#wrap(Methods.delete)\n\toptions = this.#wrap(Methods.options)\n\n\tnest(...routers: Router<any>[]) {\n\t\trouters.forEach((router) => this.#children.push(router))\n\t}\n\n\tget routes() {\n\t\treturn [...this.#routes].concat(this.#children.flatMap((child) => groupRoutes(this.#config, child.routes)))\n\t}\n}\n"],"mappings":"AAAA,SAAS,SAAS;AAElB;AAAA,EACC;AAAA,OAQM;AAEP,SAAS,gBAAgB,SAAqB;AAE7C,QAAM,IAAU;AAAA,IACf,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,MAAM;AAAA,IACN,SAAS;AAAA,IACT,UAAU;AAAA,IACV,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,EACrB;AACA,WAAS,MAAsC,KAAe,KAAQ;AACrE,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,QAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,QAAI,OAAO,QAAQ,WAAY,QAAO;AACtC,WAAO,EAAE,MAAM,KAAK,GAAU;AAAA,EAC/B;AACA,SAAO,OAAO;AAAA,IACb,OAAO,KAAK,CAAC,EAAE,IAAI,CAAC,QAAQ;AAAA,MAC3B;AAAA,MACA,QAAQ,IAAI,CAAC,MAAM,EAAE,GAAG,CAAyB,EAAE,OAAoC,OAAO,IAAI;AAAA,IACnG,CAAC;AAAA,EACF;AACD;AAEA,MAAM,cAAc,CAAyC,QAAyB,WACrF,OAAO,IAAI,CAAC,WAAW;AAAA,EACtB,GAAG;AAAA,EACH,GAAG;AAAA,EACH,MAAM,GAAG,OAAO,IAAI,IAAI,MAAM,IAAI;AAAA,EAClC,QAAQ,CAAC,GAAI,OAAO,UAAU,CAAC,GAAI,GAAI,MAAM,UAAU,CAAC,CAAE;AAAA,EAC1D,aAAa,CAAC,GAAI,OAAO,eAAe,CAAC,GAAI,GAAI,MAAM,eAAe,CAAC,CAAE;AAAA,EACzE,qBAAqB,CAAC,GAAI,OAAO,uBAAuB,CAAC,GAAI,GAAI,MAAM,uBAAuB,CAAC,CAAE;AAAA,EACjG,QAAQ,aAAa,OAAO,UAAU,CAAC,GAAG,MAAM,UAAU,CAAC,CAAC;AAAA,EAC5D,UAAU,CAAC,GAAI,OAAO,YAAY,CAAC,GAAI,GAAI,MAAM,YAAY,CAAC,CAAE;AACjE,EAAE;AAEI,MAAM,OAA2B;AAAA,EACvC,UAA2B,EAAE,MAAM,GAAG;AAAA,EACtC,UAAwB,CAAC;AAAA,EACzB,YAA2B,CAAC;AAAA,EAE5B,YAAY,SAA0B,EAAE,MAAM,GAAG,GAAG;AACnD,SAAK,UAAU;AAAA,EAChB;AAAA,EAEA,MAAM,QAAqB;AAC1B,WAAO,CAAqB,MAAc,SAAyB,CAAC,MACnE,CAAC,YAAmD;AACnD,YAAM,QAAQ,YAAY,KAAK,SAAS,CAAC,EAAE,GAAG,QAAQ,MAAM,QAAQ,QAAwB,CAAC,CAAC,EAAE,CAAC;AACjG,WAAK,QAAQ,KAAK,KAAK;AACvB,aAAO;AAAA,IACR;AAAA,EACF;AAAA,EAEA,OAAO,KAAK,MAAM,QAAQ,IAAI;AAAA,EAC9B,MAAM,KAAK,MAAM,QAAQ,GAAG;AAAA,EAC5B,OAAO,KAAK,MAAM,QAAQ,IAAI;AAAA,EAC9B,MAAM,KAAK,MAAM,QAAQ,GAAG;AAAA,EAC5B,QAAQ,KAAK,MAAM,QAAQ,KAAK;AAAA,EAChC,SAAS,KAAK,MAAM,QAAQ,MAAM;AAAA,EAClC,UAAU,KAAK,MAAM,QAAQ,OAAO;AAAA,EAEpC,QAAQ,SAAwB;AAC/B,YAAQ,QAAQ,CAAC,WAAW,KAAK,UAAU,KAAK,MAAM,CAAC;AAAA,EACxD;AAAA,EAEA,IAAI,SAAS;AACZ,WAAO,CAAC,GAAG,KAAK,OAAO,EAAE,OAAO,KAAK,UAAU,QAAQ,CAAC,UAAU,YAAY,KAAK,SAAS,MAAM,MAAM,CAAC,CAAC;AAAA,EAC3G;AACD;","names":[]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const
|
|
1
|
+
const s={head:"head",get:"get",post:"post",put:"put",patch:"patch",delete:"delete",options:"options"},r={Ok:200,Found:302,BadRequest:400,NotAuthenticated:401,NotAuthorized:403,NotFound:404,ValidationError:422,TooManyRequests:429,TokenExpired:461};function t(e,o){return{cb:e,onSetup:o}}const n=(...e)=>t(...e),u=(...e)=>t(...e),p=(...e)=>t(...e);export{s as Methods,r as StatusCodes,p as makeErrorMiddleware,n as makeMiddleware,u as makeResponseMiddleware};
|
|
2
2
|
//# sourceMappingURL=types.min.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/server/types.ts"],"sourcesContent":["import type { IsInTypeList, Pipe, PipeInput, PipeOutput, Prettify } from 'valleyed'\n\nimport type { RequestError } from '../errors'\nimport type { Enum } from '../types'\nimport type {
|
|
1
|
+
{"version":3,"sources":["../../../src/server/types.ts"],"sourcesContent":["import type { IsInTypeList, Pipe, PipeInput, PipeOutput, Prettify } from 'valleyed'\n\nimport type { RequestError } from '../errors'\nimport type { Enum } from '../types'\nimport type { Request, Response } from './requests'\n\nexport const Methods = {\n\thead: 'head',\n\tget: 'get',\n\tpost: 'post',\n\tput: 'put',\n\tpatch: 'patch',\n\tdelete: 'delete',\n\toptions: 'options',\n} as const\n\nexport const StatusCodes = {\n\tOk: 200,\n\tFound: 302,\n\tBadRequest: 400,\n\tNotAuthenticated: 401,\n\tNotAuthorized: 403,\n\tNotFound: 404,\n\tValidationError: 422,\n\tTooManyRequests: 429,\n\tTokenExpired: 461,\n} as const\n\nexport type MethodsEnum = Enum<typeof Methods>\nexport type StatusCodesEnum = Enum<typeof StatusCodes>\n\nexport type DefaultHeaders = Record<string, ArrayOrValue<string>>\nexport type DefaultCookies = Record<string, string | undefined>\n\ntype ArrayOrValue<T> = T | T[] | undefined\n\nexport type IncomingFile = {\n\tname: string\n\ttype: string\n\tsize: number\n\tisTruncated: boolean\n\tdata: Buffer\n\tduration: number\n}\n\nexport type RouteDef = {\n\tparams?: Pipe<Record<string, ArrayOrValue<string>>, Record<string, ArrayOrValue<string>>>\n\tquery?: Pipe<Record<string, ArrayOrValue<unknown>>, Record<string, ArrayOrValue<unknown>>>\n\theaders?: Pipe<DefaultHeaders, DefaultHeaders>\n\tcookies?: Pipe<DefaultCookies, DefaultCookies>\n\tbody?: Pipe<Record<string, unknown>, Record<string, unknown>>\n\tresponse?: Pipe<unknown, unknown>\n\tresponseHeaders?: Pipe<DefaultHeaders, DefaultHeaders>\n\tresponseCookies?: Pipe<DefaultCookies, DefaultCookies>\n\tdefaultStatusCode?: StatusCodesEnum\n\tdefaultContentType?: string\n}\n\ntype RouteGroup = { name: string; description?: string }\ntype HandlerSetup<T extends RouteDef> = (route: Route<T>) => void\n\nexport type RouteConfig<T extends RouteDef> = {\n\tmiddlewares?: ReturnType<typeof makeMiddleware<RouteDef>>[]\n\tresponseMiddlewares?: ReturnType<typeof makeResponseMiddleware<RouteDef>>[]\n\tonError?: ReturnType<typeof makeErrorMiddleware<RouteDef>>\n\tgroups?: (RouteGroup | RouteGroup['name'])[]\n\ttitle?: string\n\tdescriptions?: string[]\n\tsecurity?: Record<string, string[]>[]\n\tschema?: T\n\thide?: boolean\n}\n\nexport type RouterConfig<T extends RouteDef> = RouteConfig<T> & { path: string }\nexport type Route<T extends RouteDef> = RouteConfig<T> & {\n\tpath: string\n\tmethod: MethodsEnum\n\thandler: RouteDefHandler<T>\n}\n\ntype GetApiPart<T extends RouteDef, K extends keyof RouteDef> = NonNullable<IsInTypeList<T[K], [unknown]> extends true ? RouteDef[K] : T[K]>\n\ntype ArePipes<A, B> = A extends Pipe<any, any> ? (B extends Pipe<any, any> ? true : false) : false\ntype Compare<K extends keyof RouteDef, A, B> =\n\tIsInTypeList<B, [unknown]> extends true\n\t\t? A\n\t\t: IsInTypeList<A, [unknown]> extends true\n\t\t\t? B\n\t\t\t: K extends `default${string}` | 'context'\n\t\t\t\t? B\n\t\t\t\t: ArePipes<A, B> extends true\n\t\t\t\t\t? Pipe<PipeInput<A> & PipeInput<B>, PipeOutput<A> & PipeOutput<B>>\n\t\t\t\t\t: B\n\nexport type MergeRouteDefs<A extends RouteDef, B extends RouteDef> = {\n\t[K in keyof RouteDef]: Compare<K, A[K], B[K]>\n}\n\nexport type RouteDefToReqRes<T extends RouteDef> = Prettify<{\n\tbody: PipeOutput<GetApiPart<T, 'body'>>\n\tparams: PipeOutput<GetApiPart<T, 'params'>>\n\trequestHeaders: PipeOutput<GetApiPart<T, 'headers'>>\n\trequestCookies: PipeOutput<GetApiPart<T, 'cookies'>>\n\tquery: PipeOutput<GetApiPart<T, 'query'>>\n\tresponse: PipeOutput<GetApiPart<T, 'response'>>\n\tresponseHeaders: PipeOutput<GetApiPart<T, 'responseHeaders'>>\n\tresponseCookies: PipeOutput<GetApiPart<T, 'responseCookies'>>\n\tstatusCode: GetApiPart<T, 'defaultStatusCode'>\n\tcontentType: GetApiPart<T, 'defaultContentType'>\n}>\n\ntype Awaitable<T> = Promise<T> | T\ntype Res<T extends RouteDefToReqRes<any>> = Awaitable<\n\tIsInTypeList<T['statusCode'], [StatusCodesEnum, 200]> extends true\n\t\t? IsInTypeList<T['responseHeaders'], [DefaultHeaders]> extends true\n\t\t\t? IsInTypeList<T['responseCookies'], [DefaultCookies]> extends true\n\t\t\t\t? Response<T> | T['response']\n\t\t\t\t: Response<T>\n\t\t\t: Response<T>\n\t\t: Response<T>\n>\nexport type RouteDefHandler<Def extends RouteDef> = (req: Request<RouteDefToReqRes<Def>>) => Res<RouteDefToReqRes<Def>>\ntype RouteMiddlewareHandler<_Def extends RouteDef> = (req: Request<RouteDefToReqRes<RouteDef>>) => Awaitable<void>\ntype RouteResponseMiddlewareHandler<_Def extends RouteDef> = (\n\treq: Request<RouteDefToReqRes<RouteDef>>,\n\tres: Response<RouteDefToReqRes<RouteDef>>,\n) => Awaitable<void>\ntype ErrorHandler<Def extends RouteDef> = (\n\treq: Request<RouteDefToReqRes<Def>>,\n\terr: Error,\n) => Res<\n\tOmit<RouteDefToReqRes<Def>, 'response' | 'statusCode' | 'responseHeaders' | 'responseCookies'> & {\n\t\tresponse: RequestError['serializedErrors']\n\t\tstatusCode: RequestError['statusCode']\n\t\tresponseHeaders: DefaultHeaders\n\t\tresponseCookies: DefaultCookies\n\t}\n>\n\nfunction makeMiddlewareHandler<Cb extends Function, T extends RouteDef>(cb: Cb, onSetup?: HandlerSetup<T>) {\n\treturn { cb, onSetup }\n}\n\nexport const makeMiddleware = <Def extends RouteDef>(...args: Parameters<typeof makeMiddlewareHandler<RouteMiddlewareHandler<Def>, Def>>) =>\n\tmakeMiddlewareHandler(...args)\nexport const makeResponseMiddleware = <Def extends RouteDef>(\n\t...args: Parameters<typeof makeMiddlewareHandler<RouteResponseMiddlewareHandler<Def>, Def>>\n) => makeMiddlewareHandler(...args)\nexport const makeErrorMiddleware = <Def extends RouteDef>(...args: Parameters<typeof makeMiddlewareHandler<ErrorHandler<Def>, Def>>) =>\n\tmakeMiddlewareHandler(...args)\n"],"mappings":"AAMO,MAAMA,EAAU,CACtB,KAAM,OACN,IAAK,MACL,KAAM,OACN,IAAK,MACL,MAAO,QACP,OAAQ,SACR,QAAS,SACV,EAEaC,EAAc,CAC1B,GAAI,IACJ,MAAO,IACP,WAAY,IACZ,iBAAkB,IAClB,cAAe,IACf,SAAU,IACV,gBAAiB,IACjB,gBAAiB,IACjB,aAAc,GACf,EAiHA,SAASC,EAA+DC,EAAQC,EAA2B,CAC1G,MAAO,CAAE,GAAAD,EAAI,QAAAC,CAAQ,CACtB,CAEO,MAAMC,EAAiB,IAA0BC,IACvDJ,EAAsB,GAAGI,CAAI,EACjBC,EAAyB,IAClCD,IACCJ,EAAsB,GAAGI,CAAI,EACrBE,EAAsB,IAA0BF,IAC5DJ,EAAsB,GAAGI,CAAI","names":["Methods","StatusCodes","makeMiddlewareHandler","cb","onSetup","makeMiddleware","args","makeResponseMiddleware","makeErrorMiddleware"]}
|
|
@@ -22,11 +22,13 @@ function makeMiddlewareHandler(cb, onSetup) {
|
|
|
22
22
|
return { cb, onSetup };
|
|
23
23
|
}
|
|
24
24
|
const makeMiddleware = (...args) => makeMiddlewareHandler(...args);
|
|
25
|
+
const makeResponseMiddleware = (...args) => makeMiddlewareHandler(...args);
|
|
25
26
|
const makeErrorMiddleware = (...args) => makeMiddlewareHandler(...args);
|
|
26
27
|
export {
|
|
27
28
|
Methods,
|
|
28
29
|
StatusCodes,
|
|
29
30
|
makeErrorMiddleware,
|
|
30
|
-
makeMiddleware
|
|
31
|
+
makeMiddleware,
|
|
32
|
+
makeResponseMiddleware
|
|
31
33
|
};
|
|
32
34
|
//# sourceMappingURL=types.mjs.map
|