express-zod-api 29.6.1 → 29.7.0

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 CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## Version 29
4
4
 
5
+ ### v29.7.0
6
+
7
+ - Added the `hasStatusCodeRanges` option to the Documentation generator for collapsing multiple status codes sharing
8
+ the same schema and MIME types into OpenAPI range keys (2XX, 3XX, 4XX, 5XX).
9
+
5
10
  ### v29.6.1
6
11
 
7
12
  - Performance optimization in the SSE event emission:
@@ -13,7 +13,7 @@ type Component = `${ResponseVariant}Response` | "requestParameter" | "requestBod
13
13
  /** @desc user defined function that creates a component description from its properties */
14
14
  type Descriptor = (
15
15
  props: Record<"method" | "path" | "operationId", string> & {
16
- statusCode?: number;
16
+ statusCode?: number | string;
17
17
  },
18
18
  ) => string;
19
19
  type Summarizer = (params: { summary?: string; description?: string; trim: typeof trimSummary }) => string | undefined;
@@ -49,6 +49,12 @@ interface DocumentationParams {
49
49
  hasHeadMethod?: boolean;
50
50
  /** @default inline */
51
51
  composition?: "inline" | "components";
52
+ /**
53
+ * @desc Collapses several status codes sharing the same schema (by reference) and MIME types into OpenAPI range.
54
+ * @example true — [200, 201] —> "2XX"
55
+ * @default false
56
+ * */
57
+ hasStatusCodeRanges?: boolean;
52
58
  /**
53
59
  * @desc Handling rules for your own schemas branded with `x-brand` metadata.
54
60
  * @desc Keys: brands (recommended to use unique symbols).
@@ -1 +1 @@
1
- import{H as e,J as t,Y as n,i as r,n as i,nt as a,p as o,t as s,w as c}from"./routing-walker-BmLKqjk4.js";import{a as l,c as u,d,f,i as p,l as m,m as h,n as g,o as _,r as v,s as y,t as b,u as x}from"./documentation-helpers-e3R47xpf.js";import"zod";import*as S from"ramda";import{OpenApiBuilder as C,isReferenceObject as w}from"openapi3-ts/oas32";const T=({description:e,summary:t=e,trim:n})=>n(t);var E=class extends C{#e=new Map;#t=new Map;#n=new Map;#r=new Map;#i(e,t,n){let r=this.#n.get(e);if(!r){let t=+!n;do r=`${n??`Schema`}${t?this.#n.size+t:``}`,t++;while(this.rootDoc.components?.schemas?.[r]);this.#n.set(e,r)}return this.addSchema(r,t),{$ref:`#/components/schemas/${r}`}}resolve(e){let t=e,n=new Set;for(;w(t);){if(n.has(t.$ref))return e;n.add(t.$ref);let r=S.path(t.$ref.split(`/`).slice(1),this.rootDoc);if(!r)return e;t=r}return t}#a(e,n,r){let i=r||t(n,e),a=this.#t.get(i);if(a===void 0)return this.#t.set(i,1),i;if(r)throw new c(`Duplicated operationId: "${r}"`,{method:n,isResponse:!1,path:e});return a++,this.#t.set(i,a),`${i}${a}`}#o(e){let t=JSON.stringify(e);for(let e in this.rootDoc.components?.securitySchemes||{})if(t===JSON.stringify(this.rootDoc.components?.securitySchemes?.[e]))return e;let n=(this.#e.get(e.type)||0)+1;return this.#e.set(e.type,n),`${e.type.toUpperCase()}_${n}`}#s({tags:e,server:t,info:n={title:`Generated by Express Zod API`,version:`0.0.0`}}){if(this.addInfo(n),e&&(this.rootDoc.tags=y(e)),t)for(let e of Array.isArray(t)?t:[t])this.addServer(typeof e==`string`?{url:e}:e)}#c(e,t){if(e===`head`||!t.includes(`:`))return;let r=n(t),i=this.#r.get(r);if(i!==void 0&&i!==t)throw new c(`Path has a duplicate: the normalized path "${r}" is already registered with different parameter names at "${i}"`,{method:e,path:t,isResponse:!1});i===void 0&&this.#r.set(r,t)}#l({config:t,descriptions:n,brandHandling:i,isHeader:s,isCookie:y,summarizer:C=T,composition:w=`inline`}){let E={composition:w,brandHandling:i,makeRef:this.#i.bind(this),seenIds:new Map};return(i,w,T)=>{this.#c(i,w);let D={...E,path:w,method:i,endpoint:T},{description:O,summary:k,scopes:A,inputSchema:j,security:M}=T,N=e(i,t.inputSources),{pathParams:P,getLocation:F,isBodyEnabled:I}=m({method:i,path:w,security:M,inputSources:N,isHeader:s,isCookie:y}),L=this.#a(w,i,T.getOperationId(i)),R=g({...D,schema:j}),z=this.resolve(R),B=h(z),V=v({...D,getLocation:F,flatRequest:B,description:n?.requestParameter?.({method:i,path:w,operationId:L})});if(P.size)throw new c(`The input schema is missing the path parameter "${[...P][0]}"`,{method:i,path:w,isResponse:!1});let H={};for(let e of o){let t=T.getResponses(e);for(let{mimeTypes:r,schema:a,statusCodes:o}of t)for(let s of o)H[s]=p({...D,variant:e,schema:a,mimeTypes:r,statusCode:s,hasMultipleStatusCodes:t.length>1||o.length>1,description:n?.[`${e}Response`]?.({method:i,path:w,operationId:L,statusCode:s})})}let U;if(I){let e=S.pluck(`name`,V),[t,r]=u(e.length?z:R,e);U=b({...D,bodyJsonSchema:t,hasRequiredBodyProps:r,flatRequest:B,paramNames:e,mimeType:a[T.getProbableRequestType(i)],description:n?.requestBody?.({method:i,path:w,operationId:L})})}let W=_(l(r(M),N),A,e=>{let t=this.#o(e);return this.addSecurityScheme(t,e),t}),G={operationId:L,summary:C({summary:k,description:O,trim:f}),description:O,deprecated:T.isDeprecated||void 0,tags:x(T.tags),parameters:x(V),requestBody:U,security:x(W),responses:H};this.addPath(d(w),{[i]:G})}}constructor({hasHeadMethod:e=!0,...t}){super(),this.#s(t);let n=this.#l(t),r=e?i(n):n;s({...t,onEndpoint:r})}};export{E as Documentation,c as DocumentationError};
1
+ import{H as e,J as t,Y as n,i as r,n as i,nt as a,p as o,t as s,w as c}from"./routing-walker-BmLKqjk4.js";import{a as l,c as u,d,f,i as p,l as m,m as h,n as g,o as _,r as v,s as y,t as b,u as x}from"./documentation-helpers-e3R47xpf.js";import"zod";import*as S from"ramda";import{OpenApiBuilder as C,isReferenceObject as w}from"openapi3-ts/oas32";const T=e=>`${Math.floor(e/100)}XX`,E=e=>{let t=new Map;for(let{schema:n,mimeTypes:r,statusCodes:i}of e){let e=r?[...r].sort().join(`,`):``,a=t.get(n)||new Map;t.set(n,a);let o=a.get(e),s=new Set(i);a.set(e,{schema:n,mimeTypes:r,statusCodes:o?s.union(o.statusCodes):s})}let n=[];for(let e of t.values())for(let t of e.values())n.push(t);return n},D=({schema:e,mimeTypes:t,statusCodes:n},r)=>{let i=[],a=new Map;for(let e of n){let t=T(e),n=a.get(t);a.set(t,n?new Set([e]).union(n):new Set([e]))}for(let[n,o]of a){let a=r.some(e=>T(e)===n&&!o.has(e));if(o.size>1&&!a)i.push({schema:e,mimeTypes:t,statusCodes:[n]});else for(let n of o)i.push({schema:e,mimeTypes:t,statusCodes:[n]})}return i},O=({statusCodes:e})=>typeof e[0]==`string`,k=e=>{let t=S.chain(S.prop(`statusCodes`),e),n=S.chain(e=>D(e,t),E(e));return n.some(O)?n:e},A=({description:e,summary:t=e,trim:n})=>n(t);var j=class extends C{#e=new Map;#t=new Map;#n=new Map;#r=new Map;#i(e,t,n){let r=this.#n.get(e);if(!r){let t=+!n;do r=`${n??`Schema`}${t?this.#n.size+t:``}`,t++;while(this.rootDoc.components?.schemas?.[r]);this.#n.set(e,r)}return this.addSchema(r,t),{$ref:`#/components/schemas/${r}`}}resolve(e){let t=e,n=new Set;for(;w(t);){if(n.has(t.$ref))return e;n.add(t.$ref);let r=S.path(t.$ref.split(`/`).slice(1),this.rootDoc);if(!r)return e;t=r}return t}#a(e,n,r){let i=r||t(n,e),a=this.#t.get(i);if(a===void 0)return this.#t.set(i,1),i;if(r)throw new c(`Duplicated operationId: "${r}"`,{method:n,isResponse:!1,path:e});return a++,this.#t.set(i,a),`${i}${a}`}#o(e){let t=JSON.stringify(e);for(let e in this.rootDoc.components?.securitySchemes||{})if(t===JSON.stringify(this.rootDoc.components?.securitySchemes?.[e]))return e;let n=(this.#e.get(e.type)||0)+1;return this.#e.set(e.type,n),`${e.type.toUpperCase()}_${n}`}#s({tags:e,server:t,info:n={title:`Generated by Express Zod API`,version:`0.0.0`}}){if(this.addInfo(n),e&&(this.rootDoc.tags=y(e)),t)for(let e of Array.isArray(t)?t:[t])this.addServer(typeof e==`string`?{url:e}:e)}#c(e,t){if(e===`head`||!t.includes(`:`))return;let r=n(t),i=this.#r.get(r);if(i!==void 0&&i!==t)throw new c(`Path has a duplicate: the normalized path "${r}" is already registered with different parameter names at "${i}"`,{method:e,path:t,isResponse:!1});i===void 0&&this.#r.set(r,t)}#l({config:t,descriptions:n,brandHandling:i,isHeader:s,isCookie:y,hasStatusCodeRanges:C=!1,summarizer:w=A,composition:T=`inline`}){let E={composition:T,brandHandling:i,makeRef:this.#i.bind(this),seenIds:new Map};return(i,T,D)=>{this.#c(i,T);let O={...E,path:T,method:i,endpoint:D},{description:A,summary:j,scopes:M,inputSchema:N,security:P}=D,F=e(i,t.inputSources),{pathParams:I,getLocation:L,isBodyEnabled:R}=m({method:i,path:T,security:P,inputSources:F,isHeader:s,isCookie:y}),z=this.#a(T,i,D.getOperationId(i)),B=g({...O,schema:N}),V=this.resolve(B),H=h(V),U=v({...O,getLocation:L,flatRequest:H,description:n?.requestParameter?.({method:i,path:T,operationId:z})});if(I.size)throw new c(`The input schema is missing the path parameter "${[...I][0]}"`,{method:i,path:T,isResponse:!1});let W={};for(let e of o){let t=D.getResponses(e),r=C?k(t):t;for(let{mimeTypes:t,schema:a,statusCodes:o}of r)for(let s of o)W[s]=p({...O,variant:e,schema:a,mimeTypes:t,statusCode:s,hasMultipleStatusCodes:r.length>1||o.length>1,description:n?.[`${e}Response`]?.({method:i,path:T,operationId:z,statusCode:s})})}let G;if(R){let e=S.pluck(`name`,U),[t,r]=u(e.length?V:B,e);G=b({...O,bodyJsonSchema:t,hasRequiredBodyProps:r,flatRequest:H,paramNames:e,mimeType:a[D.getProbableRequestType(i)],description:n?.requestBody?.({method:i,path:T,operationId:z})})}let K=_(l(r(P),F),M,e=>{let t=this.#o(e);return this.addSecurityScheme(t,e),t}),q={operationId:z,summary:w({summary:j,description:A,trim:f}),description:A,deprecated:D.isDeprecated||void 0,tags:x(D.tags),parameters:x(U),requestBody:G,security:x(K),responses:W};this.addPath(d(T),{[i]:q})}}constructor({hasHeadMethod:e=!0,...t}){super(),this.#s(t);let n=this.#l(t),r=e?i(n):n;s({...t,onEndpoint:r})}};export{j as Documentation,c as DocumentationError};
package/dist/index.js CHANGED
@@ -3,5 +3,5 @@ import{A as e,B as t,C as n,D as r,E as i,H as a,K as o,L as s,M as c,O as l,P a
3
3
  `+i.join(`
4
4
  `)+`
5
5
 
6
- `)},dt=e=>{e.startupLogo!==!1&&ut(process.stdout);let t=e.errorHandler||I,n=Le(e.logger)?e.logger:new J(e.logger);n.debug(`Running`,{build:`v29.6.1`,env:m.env}),m.isProduction&&n instanceof J&&n.warn(`Using the built-in logger in production may degrade performance due to synchronous printing. Consider installing a professional logging solution, such as Pino or Winston.`),ct(n);let r=at({logger:n,config:e}),i={getLogger:ot(n),errorHandler:t},a=Qe(i),o=Ze(i);return{...i,logger:n,notFoundHandler:a,catcher:o,loggingMiddleware:r}},ft=(e,t)=>{let{logger:n,getLogger:r,notFoundHandler:i,loggingMiddleware:a}=dt(e),o=e.app.use(a);return e.cors&&o.use(tt(e.cors)),Ue({app:o,routing:t,getLogger:r,config:e}),{notFoundHandler:i,logger:n}},pt=(e,t)=>{let{logger:n,getLogger:r,notFoundHandler:i,catcher:a,loggingMiddleware:o}=dt(e),s=N().disable(`x-powered-by`).set(`query parser`,e.queryParser??`simple`).use(o);if(e.beforeParsers?.({app:s,getLogger:r}),e.compression){let t=E(`compression`);s.use(t(typeof e.compression==`object`?e.compression:void 0))}return e.cookies&&s.use(et({config:e})),e.cors&&s.use(tt(e.cors)),s.use(e.jsonParser||N.json()).use(e.formParser||N.urlencoded()).use(e.rawParser||N.raw(),it),e.upload&&s.use(...rt({config:e,getLogger:r})),e.beforeRouting?.({app:s,getLogger:r}),Ue({app:s,routing:t,getLogger:r,config:e}),e.afterRouting?.({app:s,getLogger:r}),s.use(a,i),{app:s,logger:n}},mt=(e,t)=>{let{app:n,logger:r}=pt(e,t),i=[],a=(e,t)=>()=>e.listen(t,()=>r.info(`Listening`,t)),o=[];if(e.http){let t=Ce.createServer(n);i.push(t),o.push(a(t,e.http.listen))}if(e.https){let t=we.createServer(e.https.options,n);i.push(t),o.push(a(t,e.https.listen))}return i.length||r.warn(`No servers configured.`),e.gracefulShutdown&&lt({logger:r,servers:i,options:e.gracefulShutdown===!0?{}:e.gracefulShutdown}),{app:n,logger:r,servers:o.map(e=>e())}},ht=e=>Ee({...e,headers:{"content-type":x.json,...e?.headers}}),gt=e=>De(e),_t=e=>{let t={warn:[],error:[],info:[],debug:[]};return new Proxy(e||{},{get(e,n,r){return n===`_getLogs`?()=>t:K(n)?(...e)=>t[n].push(e):Reflect.get(e,n,r)},has(e,t){return K(t)||t===`_getLogs`?!0:Reflect.has(e,t)}})},vt=({requestProps:e,responseOptions:t,configProps:n,loggerProps:r})=>{let i=ht(e),a=gt({req:i,...t});a.req=t?.req||i,i.res=a;let o=_t(r);return{requestMock:i,responseMock:a,loggerMock:o,configMock:{cors:!1,logger:o,...n}}},yt=async({endpoint:e,...t})=>{let{requestMock:n,responseMock:r,loggerMock:i,configMock:a}=vt(t);return await e.execute({request:n,response:r,config:a,logger:i}),{requestMock:n,responseMock:r,loggerMock:i}},bt=async({middleware:e,ctx:n={},...r})=>{let{configMock:i,...a}=vt(r),{inputSources:o,errorHandler:s=I}=i,c=p(a.requestMock,o),l={request:a.requestMock,response:a.responseMock,logger:a.loggerMock,input:c,ctx:n};try{let t=await e.execute({...l,config:i});return{...a,output:t}}catch(e){return await s.execute({...l,error:t(e),output:null}),{...a,output:{}}}},xt=(e,t)=>O.object({data:t,event:O.literal(e),id:O.string().optional(),retry:O.int().positive().optional()}),St=(e,t,n)=>{if(!Object.prototype.hasOwnProperty.call(e,t))throw Error(`Unknown event: ${t}`);let r=e[t].parse(n);return[`event: ${t}`,`data: ${JSON.stringify(r)}`,``,``].join(`
6
+ `)},dt=e=>{e.startupLogo!==!1&&ut(process.stdout);let t=e.errorHandler||I,n=Le(e.logger)?e.logger:new J(e.logger);n.debug(`Running`,{build:`v29.7.0`,env:m.env}),m.isProduction&&n instanceof J&&n.warn(`Using the built-in logger in production may degrade performance due to synchronous printing. Consider installing a professional logging solution, such as Pino or Winston.`),ct(n);let r=at({logger:n,config:e}),i={getLogger:ot(n),errorHandler:t},a=Qe(i),o=Ze(i);return{...i,logger:n,notFoundHandler:a,catcher:o,loggingMiddleware:r}},ft=(e,t)=>{let{logger:n,getLogger:r,notFoundHandler:i,loggingMiddleware:a}=dt(e),o=e.app.use(a);return e.cors&&o.use(tt(e.cors)),Ue({app:o,routing:t,getLogger:r,config:e}),{notFoundHandler:i,logger:n}},pt=(e,t)=>{let{logger:n,getLogger:r,notFoundHandler:i,catcher:a,loggingMiddleware:o}=dt(e),s=N().disable(`x-powered-by`).set(`query parser`,e.queryParser??`simple`).use(o);if(e.beforeParsers?.({app:s,getLogger:r}),e.compression){let t=E(`compression`);s.use(t(typeof e.compression==`object`?e.compression:void 0))}return e.cookies&&s.use(et({config:e})),e.cors&&s.use(tt(e.cors)),s.use(e.jsonParser||N.json()).use(e.formParser||N.urlencoded()).use(e.rawParser||N.raw(),it),e.upload&&s.use(...rt({config:e,getLogger:r})),e.beforeRouting?.({app:s,getLogger:r}),Ue({app:s,routing:t,getLogger:r,config:e}),e.afterRouting?.({app:s,getLogger:r}),s.use(a,i),{app:s,logger:n}},mt=(e,t)=>{let{app:n,logger:r}=pt(e,t),i=[],a=(e,t)=>()=>e.listen(t,()=>r.info(`Listening`,t)),o=[];if(e.http){let t=Ce.createServer(n);i.push(t),o.push(a(t,e.http.listen))}if(e.https){let t=we.createServer(e.https.options,n);i.push(t),o.push(a(t,e.https.listen))}return i.length||r.warn(`No servers configured.`),e.gracefulShutdown&&lt({logger:r,servers:i,options:e.gracefulShutdown===!0?{}:e.gracefulShutdown}),{app:n,logger:r,servers:o.map(e=>e())}},ht=e=>Ee({...e,headers:{"content-type":x.json,...e?.headers}}),gt=e=>De(e),_t=e=>{let t={warn:[],error:[],info:[],debug:[]};return new Proxy(e||{},{get(e,n,r){return n===`_getLogs`?()=>t:K(n)?(...e)=>t[n].push(e):Reflect.get(e,n,r)},has(e,t){return K(t)||t===`_getLogs`?!0:Reflect.has(e,t)}})},vt=({requestProps:e,responseOptions:t,configProps:n,loggerProps:r})=>{let i=ht(e),a=gt({req:i,...t});a.req=t?.req||i,i.res=a;let o=_t(r);return{requestMock:i,responseMock:a,loggerMock:o,configMock:{cors:!1,logger:o,...n}}},yt=async({endpoint:e,...t})=>{let{requestMock:n,responseMock:r,loggerMock:i,configMock:a}=vt(t);return await e.execute({request:n,response:r,config:a,logger:i}),{requestMock:n,responseMock:r,loggerMock:i}},bt=async({middleware:e,ctx:n={},...r})=>{let{configMock:i,...a}=vt(r),{inputSources:o,errorHandler:s=I}=i,c=p(a.requestMock,o),l={request:a.requestMock,response:a.responseMock,logger:a.loggerMock,input:c,ctx:n};try{let t=await e.execute({...l,config:i});return{...a,output:t}}catch(e){return await s.execute({...l,error:t(e),output:null}),{...a,output:{}}}},xt=(e,t)=>O.object({data:t,event:O.literal(e),id:O.string().optional(),retry:O.int().positive().optional()}),St=(e,t,n)=>{if(!Object.prototype.hasOwnProperty.call(e,t))throw Error(`Unknown event: ${t}`);let r=e[t].parse(n);return[`event: ${t}`,`data: ${JSON.stringify(r)}`,``,``].join(`
7
7
  `)},Ct=e=>e.headersSent||e.writeHead(200,{connection:`keep-alive`,"content-type":x.sse,"cache-control":`no-cache`}),wt=e=>new v({handler:async({request:t,response:n})=>{let r=new AbortController,i=setTimeout(()=>Ct(n),1e4);return t.once(`close`,()=>{clearTimeout(i),r.abort()}),{isClosed:()=>n.writableEnded||n.closed,signal:r.signal,emit:(t,r)=>{Ct(n),n.write(St(e,String(t),r),`utf-8`),n.flush?.()}}}}),Tt=e=>new P({positive:()=>{let[t,...n]=Object.entries(e).map(([e,t])=>xt(e,t));if(!t)throw new l(Error(`At least one SSE event is required.`));return{mimeType:x.sse,schema:n.length?O.discriminatedUnion(`event`,[t,...n]):t}},negative:{mimeType:`text/plain`,schema:O.string()},handler:async({response:e,error:t,logger:n,request:r,input:i})=>{if(t){let a=S(t);y(a,n,r,i),e.headersSent||e.status(a.statusCode).type(`text/plain`).write(h(a),`utf-8`)}e.end()}});var Et=class extends U{constructor(e){super(Tt(e)),this.middlewares=[wt(e)]}};const Dt=[`total`,`limit`,`offset`],$=[`nextCursor`,`limit`];function Ot({style:e,itemSchema:t,itemsName:n=`items`,maxLimit:r=100,defaultLimit:i=20}){if(!Number.isInteger(r)||r<1)throw Error(`ez.paginated: maxLimit must be a positive integer`);if(!Number.isInteger(i)||i<1)throw Error(`ez.paginated: defaultLimit must be a positive integer`);if(i>r)throw Error(`ez.paginated: defaultLimit must not be greater than maxLimit`);if(e===`offset`&&Dt.includes(n))throw Error(`ez.paginated: itemsName must not match reserved keys for offset output (${Dt.join(`, `)})`);if(e===`cursor`&&$.includes(n))throw Error(`ez.paginated: itemsName must not match reserved keys for cursor output (${$.join(`, `)})`);let a=O.coerce.number().int().min(1).max(r).default(i).describe(`Page size (number of ${n} per page)`);if(e===`offset`){let e=O.coerce.number().int().min(0).default(0).describe(`Number of ${n} to skip`);return{input:O.object({limit:a,offset:e}),output:O.object({[n]:O.array(t).describe(`Page of ${n}`),total:O.number().int().min(0).describe(`Total number of ${n}`),limit:O.number().int().min(1).describe(`Page size used`),offset:O.number().int().min(0).describe(`Offset used`)})}}let o=O.string().optional().describe(`Cursor for the next page; omit for first page`);return{input:O.object({cursor:o,limit:a}),output:O.object({[n]:O.array(t).describe(`Page of ${n}`),nextCursor:O.string().nullable().describe(`Cursor for the next page, or null if no more pages`),limit:O.number().int().min(1).describe(`Page size used`)})}}const kt={dateIn:c,dateOut:e,form:ee,upload:n,raw:ce,buffer:u,paginated:Ot};export{J as BuiltinLogger,se as DocumentationError,U as EndpointsFactory,Et as EventStreamFactory,d as InputValidationError,v as Middleware,i as MissingPeerError,r as OutputValidationError,P as ResultHandler,re as RoutingError,te as ServeStatic,Ie as arrayEndpointsFactory,R as arrayResultHandler,ft as attachRouting,ne as createApiResponse,B as createCacheMiddleware,Oe as createConfig,V as createCookieMiddleware,H as createRateLimitMiddleware,mt as createServer,Fe as defaultEndpointsFactory,I as defaultResultHandler,S as ensureHttpError,kt as ez,f as getMessageFromError,yt as testEndpoint,bt as testMiddleware};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-zod-api",
3
- "version": "29.6.1",
3
+ "version": "29.7.0",
4
4
  "description": "A Typescript framework to help you get an API server up and running with I/O schema validation and custom middlewares in minutes.",
5
5
  "license": "MIT",
6
6
  "repository": {