express-zod-api 29.5.2 → 29.6.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,19 @@
2
2
 
3
3
  ## Version 29
4
4
 
5
+ ### v29.6.0
6
+
7
+ - Added the `isCookie` (a boolean returning function) option to the Documentation generator for your customizations:
8
+ - The default one recognizes names that are typical for sessions: `session`, `session_id`, `sessionId`.
9
+ - Fixed depiction of API request by the Documentation generator:
10
+ - When `body` is among the configured `inputSources` for a certain HTTP method (POST, PUT, PATCH, QUERY by default):
11
+ - The request body would be the default location for the inputs that are not headers or cookies;
12
+ - When `body` is not enabled for a certain HTTP method (GET and DELETE methods by default):
13
+ - `isCookie()` would be used beside the Middleware's `CookieSecurity` to recognize cookies;
14
+ - Either `query` or `cookie` would be the default param location (if the corresponding input source is enabled);
15
+ - The customization of the `inputSources` config is respected for the QUERY method (you can exclude the `body`);
16
+ - 🙏[@marco-carvalho](https://github.com/marco-carvalho), [@BetterAndBetterII](https://github.com/BetterAndBetterII).
17
+
5
18
  ### v29.5.2
6
19
 
7
20
  - Compatibility fix for the Zod 4.5 feature of [compiled](https://zod.dev/compile) schemas:
package/README.md CHANGED
@@ -90,6 +90,7 @@ Therefore, many basic tasks can be achieved faster and easier, in particular:
90
90
  These people contributed to the improvement of the framework by reporting bugs, making changes, and suggesting ideas:
91
91
 
92
92
  [<img src="https://github.com/marco-carvalho.png" alt="@marco-carvalho" width="50" />](https://github.com/marco-carvalho)
93
+ [<img src="https://github.com/BetterAndBetterII.png" alt="@BetterAndBetterII" width="50" />](https://github.com/BetterAndBetterII)
93
94
  [<img src="https://github.com/pycanis.png" alt="@pycanis" width="50" />](https://github.com/pycanis)
94
95
  [<img src="https://github.com/arlyon.png" alt="@arlyon" width="50" />](https://github.com/arlyon)
95
96
  [<img src="https://github.com/Upsilon-Iridani.png" alt="@Upsilon-Iridani" width="50" />](https://github.com/Upsilon-Iridani)
@@ -0,0 +1 @@
1
+ import{$ as e,F as t,G as n,I as r,J as i,K as a,N as o,Q as s,R as c,S as l,W as u,X as d,b as f,j as p,nt as m,q as h,r as g,w as _}from"./routing-walker-BmLKqjk4.js";import{z as v}from"zod";import*as y from"ramda";import{isReferenceObject as b,isSchemaObject as x}from"openapi3-ts/oas32";const ee=e=>e.type===`object`,te=y.mergeDeepWith((e,t)=>{if(Array.isArray(e)&&Array.isArray(t))return y.concat(e,t);if(e===t)return t;throw Error(`Can not flatten properties`,{cause:{a:e,b:t}})}),S=new Set([`type`,`properties`,`required`,`examples`,`description`,`additionalProperties`]),C=e=>{for(let t of Object.keys(e))if(!S.has(t))return!1;return!0},w=y.pair(!0),ne=(e,t,n)=>!(`allOf`in e)||!e.allOf?[]:e.allOf.map(e=>{if(t===`throw`&&!(e.type===`object`&&C(e)))throw Error(`Can not merge`);return y.pair(n,e)}),re=e=>{let t=[];return e.anyOf&&t.push(...y.map(w,e.anyOf)),e.oneOf&&t.push(...y.map(w,e.oneOf)),t},ie=(e,t,n,r)=>{if(!a(e.propertyNames))return;let i=[];typeof e.propertyNames.const==`string`&&i.push(e.propertyNames.const),e.propertyNames.enum&&i.push(...e.propertyNames.enum.filter(e=>typeof e==`string`));let o={...Object(e.additionalProperties)};for(let e of i)t.properties[e]??=o;r||n.push(...i)},ae=(e,t,n)=>{t.examples?.length&&(e.examples=n?y.concat(e.examples||[],t.examples):c(e.examples?.filter(a)||[],t.examples.filter(a),([e,t])=>y.mergeDeepRight(e,t)))},T=(e,t=`coerce`)=>{let n=[y.pair(!1,e)],r={type:`object`,properties:{}},i=[];for(let[e,a]of n)a.description&&(r.description??=a.description),n.push(...ne(a,t,e)),n.push(...re(a)),ae(r,a,e),ee(a)&&(n.push([e,{examples:E(a)}]),a.properties&&(r.properties=(t===`throw`?te:y.mergeDeepRight)(r.properties,a.properties),!e&&a.required&&i.push(...a.required)),ie(a,r,i,e));return i.length&&(r.required=[...new Set(i)]),r},E=e=>Object.entries(e.properties||{}).reduce((e,[t,n])=>{let{examples:r=[]}=a(n)?n:{};return c(e,r.map(y.objOf(t)),([e,t])=>({...e,...t}))},[]),D=`x-coerce`,O=new Set([`array`,`object`]),k=(e,t)=>{let n=[e.items,e.prefixItems,e.additionalItems,Object.values(e.properties??{}),e.additionalProperties,e.propertyNames];for(let e of n){if(!a(e))continue;let n=Array.isArray(e)?e:[e];for(let e of n)if(a(e)&&!A(e,t))return!1}return!0},A=(e,t)=>e[`x-coerce`]===!0?!0:e.anyOf?e.anyOf.some(e=>A(e,t)):e.oneOf?e.oneOf.some(e=>A(e,t)):e.allOf?e.allOf.every(e=>A(e,t)):e.type===void 0||e.type===`string`?!0:Array.isArray(e.type)?A({anyOf:e.type.map(t=>({...e,type:t}))},t):t!==`path`&&O.has(e.type)&&k(e,t);let j;const M=()=>j??=new Set([`session`,`session_id`,`sessionId`]);let N;const P=()=>N??=new Set(`a-im.accept.accept-additions.accept-charset.accept-datetime.accept-encoding.accept-features.accept-language.accept-signature.access-control.access-control-request-headers.access-control-request-method.alpn.alt-used.amp-cache-transform.apply-to-redirect-ref.authorization.available-dictionary.c-ext.c-man.c-opt.c-pep.c-pep-info.cache-control.cal-managed-id.caldav-timezones.capsule-protocol.cdn-loop.cert-not-after.cert-not-before.client-cert.client-cert-chain.close.cmcd-object.cmcd-request.cmcd-session.cmcd-status.cmsd-dynamic.cmsd-static.concealed-auth-export.configuration-context.connection.content-digest.content-disposition.content-encoding.content-id.content-language.content-length.content-location.content-md5.content-range.content-script-type.content-type.cookie.cookie2.cta-common-access-token.dasl.date.dav.default-style.delta-base.deprecation.depth.derived-from.destination.detached-jws.dictionary-id.differential-id.digest.dpop.early-data.ediint-features.expect.expect-ct.ext.forwarded.from.getprofile.hobareg.host.http2-settings.if.if-match.if-modified-since.if-none-match.if-range.if-schedule-tag-match.if-unmodified-since.im.include-referred-token-binding-id.incremental.isolation.keep-alive.label.last-event-id.link.link-template.lock-token.man.max-forwards.memento-datetime.meter.method-check.method-check-expires.mime-version.negotiate.odata-entityid.odata-isolation.odata-maxversion.odata-version.opt.ordering-type.origin.origin-agent-cluster.oscore.oslc-core-version.overwrite.pep.pep-info.permissions-policy.pics-label.ping-from.ping-to.position.pragma.prefer.preference-applied.priority.profileobject.protocol.protocol-info.protocol-query.protocol-request.proxy-authorization.proxy-features.proxy-instruction.range.redirect-ref.referer.referer-root.referrer-policy.repeatability-client-id.repeatability-first-sent.repeatability-request-id.repeatability-result.replay-nonce.reporting-endpoints.repr-digest.safe.schedule-reply.schedule-tag.sec-fetch-storage-access.sec-gpc.sec-purpose.sec-token-binding.sec-websocket-extensions.sec-websocket-key.sec-websocket-protocol.sec-websocket-version.security-scheme.signature.signature-input.slug.soapaction.status-uri.sunset.surrogate-capability.tcn.te.timeout.topic.traceparent.tracestate.trailer.transfer-encoding.ttl.upgrade.urgency.uri.user-agent.variant-vary.via.want-content-digest.want-digest.want-repr-digest.want-unencoded-digest.warning.x-content-type-options.x-frame-options`.split(`.`)),F={integer:0,number:0,string:``,boolean:!1,object:{},null:null,array:[]},I=e=>e.replace(d,e=>`{${e.slice(1)}}`),L=({},e)=>{if(e.isResponse)throw new _(`Please use ez.upload() only for input.`,e);return{type:`string`,format:`binary`}},R=({jsonSchema:e})=>({...e,externalDocs:{description:`raw binary data`,url:`https://swagger.io/specification/#working-with-binary-data`}}),z=({zodSchema:e,jsonSchema:t})=>{if(!h(e,`union`)||!(`discriminator`in e._zod.def))return t;let n=e._zod.def.discriminator;return{...t,discriminator:t.discriminator??{propertyName:n}}},B=y.tryCatch(({jsonSchema:e})=>{if(!e.allOf)throw`no allOf`;return T(e,`throw`)},(e,{jsonSchema:t})=>t),V=({jsonSchema:e})=>{if(!e.anyOf||!e.anyOf.length)return e;let t=e.anyOf[0];return Object.assign(t,{type:J(t.type)})},H=e=>e,U=({jsonSchema:e},t)=>{if(t.isResponse)throw new _(`Please use ez.dateOut() for output.`,t);return e},W=({jsonSchema:e},t)=>{if(!t.isResponse)throw new _(`Please use ez.dateIn() for input.`,t);return e},G=()=>({type:`string`,format:`bigint`,pattern:`^-?\\d+$`}),K=({zodSchema:e,jsonSchema:t})=>e._zod.def.rest===null?{...t,items:{not:{}}}:t,q=e=>{let t=Array.isArray(e.type)?e.type[0]:e.type;return F?.[t]},J=e=>e===`null`?e:typeof e==`string`?[e,`null`]:e&&[...new Set(e).add(`null`)],oe=new Set([`number`,`string`,`boolean`]),se=({zodSchema:e,jsonSchema:t},r)=>{let i=e._zod.def[r.isResponse?`out`:`in`],a=e._zod.def[r.isResponse?`in`:`out`];if(!h(i,`transform`))return t;let o=H(Z(a,{ctx:r}));if(x(o)){if(r.isResponse){let e=n(i,q(o));if(e&&oe.has(e))return{...t,type:e}}else{let{type:e,...t}=o;return{...t,format:`${t.format||e} (preprocessed)`}}}return t},ce=({jsonSchema:e})=>{if(e.type!==`object`)return e;let t=e;return!t.properties||!(`raw`in t.properties)||!a(t.properties.raw)?e:t.properties.raw},Y=e=>e.length?y.fromPairs(y.zip(y.times(e=>`example${e+1}`,e.length),y.map(y.objOf(`dataValue`),e))):void 0,le=(e,t)=>t?.has(e)||e.startsWith(`x-`)||P().has(e),ue=(e,t)=>t?.has(e)||M().has(e),de=({method:e,path:t,security:n,inputSources:r,isHeader:i,isCookie:a})=>{let o=new Set(u(t)),s=r.includes(`query`),c=r.includes(`body`),l=r.includes(`params`),d=r.includes(`headers`),f=r.includes(`cookies`)||r.includes(`signedCookies`),p;d&&n&&(p=g(n,`header`));let m;f&&n&&(m=g(n,`cookie`));let h=n=>a?.(n,e,t)??ue(n,m);return{pathParams:o,getLocation:n=>{if(l&&o.has(n)&&o.delete(n))return`path`;if(f&&h(n))return`cookie`;if(d&&(i?.(n,e,t)??le(n,p)))return`header`;if(!c){if(s)return`query`;if(f)return`cookie`}},isQueryEnabled:s,isBodyEnabled:c}},fe=({path:e,method:t,flatRequest:n,makeRef:r,composition:o,getLocation:s,description:c=`${t.toUpperCase()} ${e} Parameter`})=>{let l=[];for(let[e,t]of Object.entries(n.properties)){if(!a(t))continue;let u=s(e);if(!u)continue;let d=H(t),f=o===`components`?r(t.id||JSON.stringify(t),d,t.id||i(c,e)):d;l.push({name:e,in:u,deprecated:t.deprecated,required:n.required?.includes(e)||u===`path`,description:d.description||c,schema:f,examples:Y(x(d)&&d.examples?.length?d.examples:y.pluck(e,n.examples?.filter(y.both(a,y.has(e)))||[]))})}return l},X={nullable:V,union:z,bigint:G,intersection:B,tuple:K,pipe:se,[o]:U,[p]:W,[l]:L,[f]:ce,[t]:R},pe=(e,t,n)=>{let r=[e,t],i=e=>/schema\d+$/.test(e)?void 0:e;for(let e=0;e<r.length;e++){let a=r[e];if(y.is(Object,a)){if(b(a)&&!a.$ref.startsWith(`#/components`)){let e=a.$ref.split(`/`).pop(),r=t[e];if(r){let t=r.id||i(e);a.$ref=n.makeRef(t||r,H(r),t).$ref}continue}r.push(...y.values(a))}y.is(Array,a)&&r.push(...y.values(a))}return e},Z=(e,{ctx:t,rules:n=X})=>{let{$defs:i={},properties:o={}}=v.toJSONSchema(v.object({subject:e}),{unrepresentable:`any`,io:t.isResponse?`output`:`input`,override:e=>{let i=v.globalRegistry.get(e.zodSchema)?.id;if(i){let n=t.seenIds.get(i);if(n&&n!==e.zodSchema)throw new _(`The meta id "${i}" is used by two different schemas. Please make the ids unique or reuse the same schema instance.`,t);t.seenIds.set(i,e.zodSchema)}let a=r(e.zodSchema),o=n[a&&a in n?a:e.zodSchema._zod.def.type];if(o){let n={...o(e,t)};for(let t in e.jsonSchema)delete e.jsonSchema[t];Object.assign(e.jsonSchema,n)}}});return pe(a(o.subject)?o.subject:{},i,t)},Q=(e,t)=>{if(b(e))return[e,!1];let n=!1,r=y.map(e=>{let[r,i]=Q(e,t);return n||=i,r}),i=y.omit(t),a={properties:i,examples:y.map(i),required:y.without(t),allOf:r,oneOf:r,anyOf:r},o=y.evolve(a,e);return[o,n||!!o.required?.length]},me=({method:t,path:n,schema:r,mimeTypes:a,variant:o,makeRef:c,composition:l,hasMultipleStatusCodes:u,statusCode:d,brandHandling:f,seenIds:p,description:h=`${t.toUpperCase()} ${n} ${e(o)} response ${u?d:``}`.trim()})=>{if(!s(t,a))return{description:h};let g=H(Z(r,{rules:{...f,...X},ctx:{isResponse:!0,makeRef:c,path:n,method:t,seenIds:p}})),_=[];x(g)&&g.examples&&(_.push(...g.examples),delete g.examples);let v=l===`components`?c(r,g,i(h)):g;return{description:h,content:y.fromPairs(a.map(e=>[e,{[e===m.sse?`itemSchema`:`schema`]:v,examples:Y(_)}]))}},he=({format:e})=>{let t={type:`http`,scheme:`bearer`};return e&&(t.bearerFormat=e),t},ge=({name:e},t)=>{let n={type:`apiKey`,in:`query`,name:e};return t?.includes(`body`)&&(t?.includes(`query`)?(n[`x-in-alternative`]=`body`,n.description=`${e} CAN also be supplied within the request body`):(n[`x-in-actual`]=`body`,n.description=`${e} MUST be supplied within the request body instead of query`)),n},_e=({name:e})=>({type:`apiKey`,in:`header`,name:e}),ve=({name:e})=>({type:`apiKey`,in:`cookie`,name:e}),ye=({url:e})=>({type:`openIdConnect`,openIdConnectUrl:e}),be=({flows:e={},oauth2MetadataUrl:t})=>({type:`oauth2`,flows:y.map(e=>({...e,scopes:e.scopes||{}}),y.reject(y.isNil,e)),oauth2MetadataUrl:t}),$=(e,t=[])=>{let n=e=>e.type===`basic`?{type:`http`,scheme:`basic`}:e.type===`bearer`?he(e):e.type===`input`?ge(e,t):e.type===`header`?_e(e):e.type===`cookie`?ve(e):e.type===`openid`?ye(e):be(e);return e.map(e=>e.map(({deprecated:e,...t})=>({...n(t),deprecated:e})))},xe=Set.prototype.has.bind(new Set([`oauth2`,`openIdConnect`])),Se=(e,t,n)=>{let r=Array.from(t);return e.map(e=>{let t={};for(let i of e){let e=n(i);t[e]=xe(i.type)?r:[]}return t})},Ce=({schema:e,brandHandling:t,makeRef:n,path:r,method:i,seenIds:a})=>Z(e,{rules:{...t,...X},ctx:{isResponse:!1,makeRef:n,path:r,method:i,seenIds:a}}),we=({method:e,path:t,bodyJsonSchema:n,hasRequiredBodyProps:r,flatRequest:o,mimeType:s,makeRef:c,composition:l,paramNames:u,description:d=`${e.toUpperCase()} ${t} Request body`})=>{let f=H(n),p=[];x(f)&&f.examples&&(p.push(...f.examples),delete f.examples);let h={schema:l===`components`?c(JSON.stringify(f),f,i(d)):f,examples:Y(p.length?p:o.examples?.filter(e=>a(e)&&!Array.isArray(e)).map(y.omit(u))||[])},g={description:d,content:{[s]:h}};return(r||s===m.raw)&&(g.required=!0),g},Te=e=>Object.entries(e).reduce((e,[t,n])=>{if(!n)return e;if(typeof n==`string`)return e.concat({name:t,description:n});let{url:r,...i}=n,a={...i,name:t};return r&&(a.externalDocs={...a.externalDocs,url:r}),e.concat(a)},[]),Ee=(e,t=50)=>!e||e.length<=t?e:e.slice(0,Math.max(1,t||0)-1)+`…`,De=e=>{let t=Array.from(e);return t.length?t:void 0};export{$ as a,Q as c,I as d,Ee as f,A as h,me as i,de as l,T as m,Ce as n,Se as o,D as p,fe as r,Te as s,we as t,De as u};
@@ -1,12 +1,12 @@
1
1
  import { M as ResponseVariant, g as CommonConfig, t as Routing } from "./routing-oAHiW3zy.js";
2
2
  import {
3
- c as IsHeader,
3
+ c as ParamRecognizer,
4
4
  l as depictTags,
5
5
  o as BrandHandling,
6
6
  s as Depicter,
7
7
  t as DocumentationError,
8
8
  u as trimSummary,
9
- } from "./errors-BeNQFko9.js";
9
+ } from "./errors-Dbnie2Mk.js";
10
10
  import { z } from "zod";
11
11
  import { InfoObject, OpenApiBuilder, SchemaObjectValue, ServerObject } from "openapi3-ts/oas32";
12
12
  type Component = `${ResponseVariant}Response` | "requestParameter" | "requestBody";
@@ -63,7 +63,13 @@ interface DocumentationParams {
63
63
  * @see defaultIsHeader
64
64
  * @link https://www.iana.org/assignments/http-fields/http-fields.xhtml
65
65
  * */
66
- isHeader?: IsHeader;
66
+ isHeader?: ParamRecognizer;
67
+ /**
68
+ * @desc Ability to configure recognition of cookies among other input data
69
+ * @desc Only applicable when "cookies" or "signedCookies" is present within inputSources config option
70
+ * @see defaultIsCookie
71
+ * */
72
+ isCookie?: ParamRecognizer;
67
73
  /**
68
74
  * @desc Extended description of tags used in endpoints. For enforcing constraints:
69
75
  * @see TagOverrides
@@ -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-DWdITRNC.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,summarizer:y=T,composition:C=`inline`}){let w={composition:C,brandHandling:i,makeRef:this.#i.bind(this),seenIds:new Map};return(i,C,T)=>{this.#c(i,C);let E={...w,path:C,method:i,endpoint:T},{description:D,summary:O,scopes:k,inputSchema:A,security:j}=T,M=e(i,t.inputSources),{pathParams:N,getLocation:P}=m({method:i,path:C,security:j,inputSources:M,isHeader:s}),F=this.#a(C,i,T.getOperationId(i)),I=g({...E,schema:A}),L=this.resolve(I),R=h(L),z=v({...E,getLocation:P,flatRequest:R,description:n?.requestParameter?.({method:i,path:C,operationId:F})});if(N.size)throw new c(`The input schema is missing the path parameter "${[...N][0]}"`,{method:i,path:C,isResponse:!1});let B={};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)B[s]=p({...E,variant:e,schema:a,mimeTypes:r,statusCode:s,hasMultipleStatusCodes:t.length>1||o.length>1,description:n?.[`${e}Response`]?.({method:i,path:C,operationId:F,statusCode:s})})}let V;if(M.includes(`body`)){let e=S.pluck(`name`,z),[t,r]=u(e.length?L:I,e);V=b({...E,bodyJsonSchema:t,hasRequiredBodyProps:r,flatRequest:R,paramNames:e,mimeType:a[T.getProbableRequestType(i)],description:n?.requestBody?.({method:i,path:C,operationId:F})})}let H=_(l(r(j),M),k,e=>{let t=this.#o(e);return this.addSecurityScheme(t,e),t}),U={operationId:F,summary:y({summary:O,description:D,trim:f}),description:D,deprecated:T.isDeprecated||void 0,tags:x(T.tags),parameters:x(z),requestBody:V,security:x(H),responses:B};this.addPath(d(C),{[i]:U})}}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=({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};
@@ -17,8 +17,8 @@ type Depicter = (
17
17
  },
18
18
  oasCtx: OpenAPIContext,
19
19
  ) => z.core.JSONSchema.BaseSchema | SchemaObjectValue;
20
- /** @desc Using defaultIsHeader when returns null or undefined */
21
- type IsHeader = (name: string, method: ClientMethod, path: string) => boolean | null | undefined;
20
+ /** @desc Using defaultIsHeader or defaultIsCookie when returns null or undefined */
21
+ type ParamRecognizer = (name: string, method: ClientMethod, path: string) => boolean | null | undefined;
22
22
  type BrandHandling = Record<string | symbol, Depicter>;
23
23
  interface TagDetails extends Pick<TagObject, "summary" | "description" | "externalDocs" | "kind"> {
24
24
  /** @desc shorthand for externalDocs.url */
@@ -67,7 +67,7 @@ declare class MissingPeerError extends Error {
67
67
  }
68
68
  export {
69
69
  RoutingError as a,
70
- IsHeader as c,
70
+ ParamRecognizer as c,
71
71
  OutputValidationError as i,
72
72
  depictTags as l,
73
73
  InputValidationError as n,
package/dist/index.d.ts CHANGED
@@ -38,7 +38,7 @@ import {
38
38
  n as InputValidationError,
39
39
  r as MissingPeerError,
40
40
  t as DocumentationError,
41
- } from "./errors-BeNQFko9.js";
41
+ } from "./errors-Dbnie2Mk.js";
42
42
  import { z } from "zod";
43
43
  import express, { CookieOptions, Request, Response } from "express";
44
44
  import http from "node:http";
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- 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 as u,T as d,U as f,V as p,Z as m,_ as ee,a as te,c as h,d as ne,f as g,g as _,h as v,k as re,l as y,m as b,nt as x,o as ie,p as ae,s as S,t as oe,tt as C,u as w,v as T,w as se,x as ce,z as le}from"./routing-walker-BmLKqjk4.js";import{t as E}from"./peer-helpers-C4GvKwdJ.js";import{h as ue,l as de,m as fe,p as pe}from"./documentation-helpers-DWdITRNC.js";import{globalRegistry as D,z as O}from"zod";import*as me from"ramda";import k,{isHttpError as he}from"http-errors";import ge,{blue as _e,cyanBright as ve,green as ye,hex as A,italic as be,red as xe,whiteBright as j}from"ansis";import{inspect as Se}from"node:util";import{performance as M}from"node:perf_hooks";import N from"express";import Ce from"node:http";import we from"node:https";import{setInterval as Te}from"node:timers/promises";import{createRequest as Ee,createResponse as De}from"node-mocks-http";function Oe(e){return e}const ke=(e,t)=>e&&t?e.and(t):e||t,Ae=(e,t)=>e?e.and(t):t;var je=class e{#e;constructor(e){this.#e=e}async execute(...n){try{return await this.#e(...n)}catch(r){let{response:i,logger:a,error:o}=n[0],s=new l(t(r),o||void 0);e.lastResort({response:i,logger:a,error:s})}}static lastResort({error:e,logger:t,response:n}){t.error(`Result handler failure`,e);let r=h(k(500,`An error occurred while serving the result: ${e.message}.`+(e.handled?`\nOriginal error: ${e.handled.message}.`:``),{expose:he(e.cause)?e.cause.expose:!1}));n.status(500).type(`text/plain`).end(r)}},P=class extends je{#e;#t;constructor(e){super(e.handler),this.#e=e.positive,this.#t=e.negative}getPositiveResponse(e){return w(this.#e,{variant:`positive`,args:[e]})}getNegativeResponse(){return w(this.#t,{variant:`negative`,args:[]})}};const F=O.object({status:O.literal(`error`),error:O.object({message:O.string()})});D.add(F,{examples:[{status:`error`,error:{message:`Sample error message`}}]});const I=new P({positive:e=>{let t=O.object({status:O.literal(`success`),data:e}),n=s(e);return n.length&&D.add(t,{examples:n.map(e=>({status:`success`,data:e}))}),t},negative:F,handler:({error:e,input:t,output:n,request:r,response:i,logger:a})=>{if(e){let n=S(e);y(n,a,r,t),i.status(n.statusCode).set(n.headers).json({status:`error`,error:{message:h(n)}});return}i.status(g.positive).json({status:`success`,data:n})}}),L=O.string();D.add(L,{examples:[`Sample error message`]});const R=new P({positive:e=>{let t=e instanceof O.ZodObject&&`items`in e.shape&&e.shape.items instanceof O.ZodArray?e.shape.items:O.array(O.any());if(s(t).length)return t;let n=s(e).filter(e=>o(e)&&`items`in e&&Array.isArray(e.items)).map(e=>e.items);if(n?.length){let e=t.meta();D.remove(t).add(t,{...e,examples:n})}return t},negative:{schema:L,mimeType:`text/plain`},handler:({response:e,output:t,error:n,logger:r,request:i,input:a})=>{if(n){let t=S(n);y(t,r,i,a),e.status(t.statusCode).type(`text/plain`).send(h(t));return}if(`items`in t&&Array.isArray(t.items)){e.status(g.positive).json(t.items);return}throw Error(`Property 'items' is missing in the endpoint output`)}}),z=e=>{let t=[];return e.scope&&t.push(e.scope),e.noStore&&t.push(`no-store`),e.noCache&&t.push(`no-cache`),e.maxAge!==void 0&&t.push(`max-age=${e.maxAge}`),e.sMaxAge!==void 0&&t.push(`s-maxage=${e.sMaxAge}`),e.mustRevalidate&&t.push(`must-revalidate`),e.proxyRevalidate&&t.push(`proxy-revalidate`),e.mustUnderstand&&t.push(`must-understand`),e.immutable&&t.push(`immutable`),e.noTransform&&t.push(`no-transform`),e.staleWhileRevalidate!==void 0&&t.push(`stale-while-revalidate=${e.staleWhileRevalidate}`),e.staleIfError!==void 0&&t.push(`stale-if-error=${e.staleIfError}`),t.join(`, `)},Me={"max-age":`maxAge`,"max-stale":`maxStale`,"min-fresh":`minFresh`,"stale-if-error":`staleIfError`},Ne={"no-cache":`noCache`,"no-store":`noStore`,"no-transform":`noTransform`,"only-if-cached":`onlyIfCached`},Pe=e=>{if(!e)return;let t={};for(let n of e.toLowerCase().split(`,`)){let[e,r]=n.split(`=`),i=Me[e.trim()];if(i){let e=parseInt(r?.trim()??``,10);isNaN(e)||(t[i]=e);continue}let a=Ne[e.trim()];a&&(t[a]=!0)}return t},B=e=>new v({handler:async({request:t,response:n})=>(e&&n.setHeader(`Cache-Control`,z(e)),{get ifNoneMatch(){let e=t.headers[`if-none-match`];if(!e)return;let n=e.trim();return n===`*`?n:n.split(`,`).map(e=>e.trim().replace(/^(?:W\/)?"/,``).replace(/"$/,``))},get ifModifiedSince(){let e=t.headers[`if-modified-since`];if(!e)return;let n=new Date(e);return isNaN(n.getTime())?void 0:n},get cacheControl(){return Pe(t.headers[`cache-control`])},addCachePolicy:t=>{n.setHeader(`Cache-Control`,z({...e,...t}))},setETag:e=>{n.setHeader(`ETag`,e.startsWith(`"`)?e:`"${e}"`)},setLastModified:e=>{n.setHeader(`Last-Modified`,e.toUTCString())},setVary:(...e)=>{n.setHeader(`Vary`,e.join(`, `))},setExpires:e=>{n.setHeader(`Expires`,e.toUTCString())},clearSiteData:()=>{n.setHeader(`Clear-Site-Data`,`"cache"`)},notModified:()=>{n.status(304).end()}})}),V=e=>new v({handler:async({request:t,response:n})=>({getCookie:e=>t.signedCookies?.[e]??t.cookies?.[e],setCookie:(t,r,i)=>{n.cookie(t,r,{...e,...i})},clearCookie:(t,r)=>{n.clearCookie(t,{...e,...r})}})}),H=e=>{let t=E(`express-rate-limit`)({statusCode:429,...e,handler:(e,t,n,r)=>{n(k(r.statusCode,r.message))}}),{getKey:n,resetKey:r}=t,i={getKey:n,resetKey:r};return new b(t,{statusCode:e?.statusCode,provider:t=>({rateLimit:{...i,...t[e?.requestPropertyName??`rateLimit`]}})})};var U=class e{resultHandler;schema=void 0;statusCodes=new Set;middlewares=[];constructor(e){this.resultHandler=e}#e(t){let n=new e(this.resultHandler);return n.middlewares=this.middlewares.concat(t),n.schema=ke(this.schema,t.schema),n.statusCodes=this.statusCodes.union(t.statusCodes),n}addMiddleware(e){return this.#e(e instanceof v?e:new v(e))}useCookies(...e){return this.#e(V(...e))}useCache(...e){return this.#e(B(...e))}useRateLimit(...e){return this.#e(H(...e))}use=this.addExpressMiddleware;addExpressMiddleware(...e){return this.#e(new b(...e))}addContext(e){return this.#e(new v({handler:({ctx:t})=>e(t)}))}build({input:e=le,output:t,operationId:n,scope:r,tag:i,method:a,statusCode:o,...s}){let{middlewares:c,resultHandler:l}=this,u=new _(typeof a==`string`?[a]:a),d=typeof n==`function`?n:e=>n&&`${n}${e===`head`?`__HEAD`:``}`,f=new _(typeof r==`string`?[r]:r),p=new _(typeof i==`string`?[i]:i);return new ie({...s,middlewares:c,outputSchema:t,resultHandler:l,scopes:f,tags:p,methods:u,getOperationId:d,inputSchema:Ae(this.schema,e),statusCodes:this.statusCodes.union(new Set(typeof o==`number`?[o]:o||[]))})}buildVoid({handler:e,...t}){return this.build({...t,output:le,handler:async t=>(await e(t),{})})}};const Fe=new U(I),Ie=new U(R),W={debug:_e,info:ye,warn:A(`#FFA500`),error:xe,ctx:ve},G={debug:10,info:20,warn:30,error:40},Le=e=>o(e)&&Object.keys(G).some(t=>t in e),K=e=>e in G,Re=(e,t)=>G[e]<G[t],q=me.memoizeWith((e,t)=>`${e}${t}`,(e,t=0)=>Intl.NumberFormat(void 0,{useGrouping:!1,minimumFractionDigits:0,maximumFractionDigits:t,style:`unit`,unitDisplay:`long`,unit:e})),ze=e=>e<1e-6?q(`nanosecond`,3).format(e/1e-6):e<.001?q(`nanosecond`).format(e/1e-6):e<1?q(`microsecond`).format(e/.001):e<1e3?q(`millisecond`).format(e):e<6e4?q(`second`,2).format(e/1e3):q(`minute`,2).format(e/6e4);var J=class e{config;constructor({color:e=ge.isSupported(),level:t=m.isProduction?`warn`:`debug`,depth:n=2,ctx:r={}}={}){this.config={color:e,level:t,depth:n,ctx:r}}format(e){let{depth:t,color:n,level:r}=this.config;return Se(e,{depth:t,colors:n,breakLength:r===`debug`?80:1/0,compact:r!==`debug`||3})}print(e,t,n){let{level:r,ctx:{requestId:i,...a},color:o}=this.config;if(r===`silent`||Re(e,r))return;let s=[new Date().toISOString()];i&&s.push(o?W.ctx(i):i),s.push(o?`${W[e](e)}:`:`${e}:`,t),n!==void 0&&s.push(this.format(n)),Object.keys(a).length>0&&s.push(this.format(a)),console.log(s.join(` `))}debug(e,t){this.print(`debug`,e,t)}info(e,t){this.print(`info`,e,t)}warn(e,t){this.print(`warn`,e,t)}error(e,t){this.print(`error`,e,t)}child(t){return new e({...this.config,ctx:t})}get ctx(){return this.config.ctx}profile(e){let t=M.now();return()=>{let n=M.now()-t,{message:r,severity:i=`debug`,formatter:a=ze}=typeof e==`object`?e:{message:e};this.print(typeof i==`function`?i(n):i,r,a(n))}}},Be=class{logger;config;#e=new WeakMap;constructor(e,t){this.logger=e,this.config=t}#t(e,t,n){if(!e.isSchemaChecked){for(let e of[`input`,`output`]){let r=[O.toJSONSchema(t[`${e}Schema`],{unrepresentable:`any`})];for(let t of r){t.type&&t.type!==`object`&&this.logger.warn(`Endpoint ${e} schema is not object-based`,n);for(let e of[`allOf`,`oneOf`,`anyOf`])t[e]&&r.push(...t[e])}}if(t.getProbableRequestType()===`json`){let e=T(t.inputSchema,`input`);e&&this.logger.warn(`The final input schema of the endpoint contains an unsupported JSON payload type.`,{...n,reason:e})}for(let e of ae)for(let{mimeTypes:r,schema:i}of t.getResponses(e)){if(!r?.includes(x.json))continue;let t=T(i,`output`);t&&this.logger.warn(`The final ${e} response schema of the endpoint contains an unsupported JSON payload type.`,{...n,reason:t})}e.isSchemaChecked=!0}}#n(e,t,n,r,i){if(e.paths.has(r))return;let{pathParams:s,getLocation:c,isQueryEnabled:l}=de({method:n,path:r,security:t.security,inputSources:a(n,this.config.inputSources)});if(!(s.size===0&&!l)){e.flat??=fe(O.toJSONSchema(t.inputSchema,{unrepresentable:`any`,io:`input`,override:({zodSchema:e,jsonSchema:t})=>{(e._zod.traits.has(`$ZodPreprocess`)||`coerce`in e._zod.def&&e._zod.def.coerce)&&(t[pe]=!0)}}));for(let[t,n]of Object.entries(e.flat.properties)){if(!o(n))continue;let r=c(t);(r===`path`||r===`query`)&&(r===`path`&&!e.flat.required?.includes(t)&&this.logger.warn(`The path parameter "${t}" is declared optional in the input schema, but path parameters are always required since Express matches the route only when the segment is present.`,{...i,name:t}),!ue(n,r)&&this.logger.warn(`The ${r} parameter "${t}" has a schema that most likely would not accept the parsed data, ${r===`path`?`since path parameters always arrive as strings`:`depending on the "queryParser" config option`}. Convert the parsed value from "z.string()" using ".transform()" method, or use "z.coerce" at least.`,{...i,name:t,jsonSchema:n}))}for(let e of s)this.logger.warn(`The input schema of the endpoint is most likely missing the parameter of the path it's assigned to.`,{...i,param:e});e.paths.add(r)}}check=(e,t,n)=>{let r=this.#e.get(n);r||(r={isSchemaChecked:!1,paths:new Set},this.#e.set(n,r)),this.#t(r,n,{method:e,path:t}),this.#n(r,n,e,t,{method:e,path:t})}};const Y=e=>e.sort((e,t)=>C(t)-+C(e)||e.localeCompare(t)).join(`, `).toUpperCase(),Ve=e=>({method:t},n,r)=>{let i=Y(e);n.set({Allow:i}),r(k(405,`${t} is not allowed`,{headers:{Allow:i}}))},He=({app:e,getLogger:t,config:n,routing:r})=>{let i=m.isProduction?void 0:new Be(t(),n),a=new Map;return oe({routing:r,config:n,onEndpoint:(e,t,r)=>{i?.check(e,t,r),a.has(t)||a.set(t,new Map(n.cors?[[`options`,r]]:[])),a.get(t)?.set(e,r)},onStatic:e.use.bind(e)}),a},Ue=({app:e,config:t,getLogger:n,...r})=>{let i=He({app:e,getLogger:n,config:t,...r}),a=new Map;for(let[r,o]of i){let i=Array.from(o.keys());i.includes(`get`)&&i.push(`head`);for(let[a,s]of o){let o=[];t.cors&&o.push((e,t,n)=>{t.set(`Access-Control-Allow-Methods`,Y(i)),n()}),o.push(async(e,r)=>{let i=n(e);return s.execute({request:e,response:r,logger:i,config:t})}),e[a]?.(r,...o)}t.hintAllowedMethods!==!1&&a.set(r,Ve(i))}for(let[t,n]of a)e.all(t,n)},We=e=>`_httpMessage`in e&&typeof e._httpMessage==`object`&&e._httpMessage!==null&&`headersSent`in e._httpMessage&&typeof e._httpMessage.headersSent==`boolean`&&`setHeader`in e._httpMessage&&typeof e._httpMessage.setHeader==`function`,Ge=e=>`server`in e&&typeof e.server==`object`&&e.server!==null&&`close`in e.server&&typeof e.server.close==`function`,Ke=e=>`encrypted`in e&&typeof e.encrypted==`boolean`&&e.encrypted,qe=({},e)=>void(!e.headersSent&&e.setHeader(`connection`,`close`)),Je=e=>{let{promise:t,resolve:n,reject:r}=Promise.withResolvers();return e.close(e=>e?r(e):n()),t},Ye=({timeout:e=1e3,logger:t}={})=>{let n,r=new Set,i=new Set,a=e=>void i.delete(e),o=e=>a(e.destroy()),s=e=>void(We(e)?!e._httpMessage.headersSent&&e._httpMessage.setHeader(`connection`,`close`):o(e)),c=e=>void(n?e.destroy():i.add(e.once(`close`,()=>a(e)).once(`error`,()=>o(e)))),l=async()=>{for(let e of r)e.on(`request`,qe);t?.info(`Graceful shutdown`,{sockets:i.size,timeout:e});for(let e of i)(Ke(e)||Ge(e))&&s(e);for await(let t of Te(10,Date.now()))if(i.size===0||Date.now()-t>=e)break;for(let e of i)o(e);return Promise.allSettled(r.values().map(Je))},u={sockets:i,add:(...e)=>{for(let t of e)if(!r.has(t)){r.add(t);for(let e of[`connection`,`secureConnection`])t.on(e,c)}return u},shutdown:()=>n??=l(),get isShuttingDown(){return!!n}};return u},Xe=Symbol.for(`express-zod-api`),Ze=({errorHandler:e,getLogger:n})=>async(r,i,a,o)=>r?e.execute({error:t(r),request:i,response:a,input:null,output:null,ctx:{},logger:n(i)}):o(),Qe=({errorHandler:e,getLogger:t})=>async(n,r)=>{let i=k(404,`Can not ${n.method} ${n.path}`),a=t(n);await e.execute({request:n,response:r,logger:a,error:i,input:null,output:null,ctx:{}})},$e=e=>(t,{},n)=>{if(Object.values(t?.files||[]).flat().find(({truncated:e})=>e))return n(e);n()},et=({config:e})=>{let t=E(`cookie-parser`),{secret:n,...r}={...typeof e.cookies==`object`&&e.cookies};return t(n,Object.keys(r).length?r:void 0)},tt=e=>typeof e==`function`?e:({},e,t)=>{e.set({"Access-Control-Allow-Origin":`*`,"Access-Control-Allow-Headers":`content-type`}),t()},nt=e=>({log:t=>{/not eligible/i.test(t)||e.debug(t)}}),rt=({getLogger:e,config:t})=>{let n=E(`express-fileupload`),{limitError:r,beforeUpload:i,...a}={...typeof t.upload==`object`&&t.upload},o=[];return o.push(async(t,r,o)=>{let s=e(t);return await i?.({request:t,logger:s}),n({debug:!0,...a,abortOnLimit:!1,parseNested:!0,logger:nt(s)})(t,r,o)}),r&&o.push($e(r)),o},it=(e,{},t)=>{Buffer.isBuffer(e.body)&&(e.body={raw:e.body}),t()},at=({logger:e,config:{childLoggerProvider:t,accessLogger:n=({method:e,path:t},n)=>n.debug(`${e}: ${t}`)}})=>async(r,i,a)=>{let o=await t?.({request:r,parent:e})||e;n?.(r,o),r.res&&(r.res.locals[Xe]={logger:o}),a()},ot=e=>t=>t?.res?.locals[Xe]?.logger||e;let st=!1;const ct=e=>{st||(st=!0,process.on(`deprecation`,({message:t,namespace:n,name:r,stack:i})=>e.warn(`${r} (${n}): ${t}`,i.split(`
1
+ 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 as u,T as d,U as f,V as p,Z as m,_ as ee,a as te,c as h,d as ne,f as g,g as _,h as v,k as re,l as y,m as b,nt as x,o as ie,p as ae,s as S,t as oe,tt as C,u as w,v as T,w as se,x as ce,z as le}from"./routing-walker-BmLKqjk4.js";import{t as E}from"./peer-helpers-C4GvKwdJ.js";import{h as ue,l as de,m as fe,p as pe}from"./documentation-helpers-e3R47xpf.js";import{globalRegistry as D,z as O}from"zod";import*as me from"ramda";import k,{isHttpError as he}from"http-errors";import ge,{blue as _e,cyanBright as ve,green as ye,hex as A,italic as be,red as xe,whiteBright as j}from"ansis";import{inspect as Se}from"node:util";import{performance as M}from"node:perf_hooks";import N from"express";import Ce from"node:http";import we from"node:https";import{setInterval as Te}from"node:timers/promises";import{createRequest as Ee,createResponse as De}from"node-mocks-http";function Oe(e){return e}const ke=(e,t)=>e&&t?e.and(t):e||t,Ae=(e,t)=>e?e.and(t):t;var je=class e{#e;constructor(e){this.#e=e}async execute(...n){try{return await this.#e(...n)}catch(r){let{response:i,logger:a,error:o}=n[0],s=new l(t(r),o||void 0);e.lastResort({response:i,logger:a,error:s})}}static lastResort({error:e,logger:t,response:n}){t.error(`Result handler failure`,e);let r=h(k(500,`An error occurred while serving the result: ${e.message}.`+(e.handled?`\nOriginal error: ${e.handled.message}.`:``),{expose:he(e.cause)?e.cause.expose:!1}));n.status(500).type(`text/plain`).end(r)}},P=class extends je{#e;#t;constructor(e){super(e.handler),this.#e=e.positive,this.#t=e.negative}getPositiveResponse(e){return w(this.#e,{variant:`positive`,args:[e]})}getNegativeResponse(){return w(this.#t,{variant:`negative`,args:[]})}};const F=O.object({status:O.literal(`error`),error:O.object({message:O.string()})});D.add(F,{examples:[{status:`error`,error:{message:`Sample error message`}}]});const I=new P({positive:e=>{let t=O.object({status:O.literal(`success`),data:e}),n=s(e);return n.length&&D.add(t,{examples:n.map(e=>({status:`success`,data:e}))}),t},negative:F,handler:({error:e,input:t,output:n,request:r,response:i,logger:a})=>{if(e){let n=S(e);y(n,a,r,t),i.status(n.statusCode).set(n.headers).json({status:`error`,error:{message:h(n)}});return}i.status(g.positive).json({status:`success`,data:n})}}),L=O.string();D.add(L,{examples:[`Sample error message`]});const R=new P({positive:e=>{let t=e instanceof O.ZodObject&&`items`in e.shape&&e.shape.items instanceof O.ZodArray?e.shape.items:O.array(O.any());if(s(t).length)return t;let n=s(e).filter(e=>o(e)&&`items`in e&&Array.isArray(e.items)).map(e=>e.items);if(n?.length){let e=t.meta();D.remove(t).add(t,{...e,examples:n})}return t},negative:{schema:L,mimeType:`text/plain`},handler:({response:e,output:t,error:n,logger:r,request:i,input:a})=>{if(n){let t=S(n);y(t,r,i,a),e.status(t.statusCode).type(`text/plain`).send(h(t));return}if(`items`in t&&Array.isArray(t.items)){e.status(g.positive).json(t.items);return}throw Error(`Property 'items' is missing in the endpoint output`)}}),z=e=>{let t=[];return e.scope&&t.push(e.scope),e.noStore&&t.push(`no-store`),e.noCache&&t.push(`no-cache`),e.maxAge!==void 0&&t.push(`max-age=${e.maxAge}`),e.sMaxAge!==void 0&&t.push(`s-maxage=${e.sMaxAge}`),e.mustRevalidate&&t.push(`must-revalidate`),e.proxyRevalidate&&t.push(`proxy-revalidate`),e.mustUnderstand&&t.push(`must-understand`),e.immutable&&t.push(`immutable`),e.noTransform&&t.push(`no-transform`),e.staleWhileRevalidate!==void 0&&t.push(`stale-while-revalidate=${e.staleWhileRevalidate}`),e.staleIfError!==void 0&&t.push(`stale-if-error=${e.staleIfError}`),t.join(`, `)},Me={"max-age":`maxAge`,"max-stale":`maxStale`,"min-fresh":`minFresh`,"stale-if-error":`staleIfError`},Ne={"no-cache":`noCache`,"no-store":`noStore`,"no-transform":`noTransform`,"only-if-cached":`onlyIfCached`},Pe=e=>{if(!e)return;let t={};for(let n of e.toLowerCase().split(`,`)){let[e,r]=n.split(`=`),i=Me[e.trim()];if(i){let e=parseInt(r?.trim()??``,10);isNaN(e)||(t[i]=e);continue}let a=Ne[e.trim()];a&&(t[a]=!0)}return t},B=e=>new v({handler:async({request:t,response:n})=>(e&&n.setHeader(`Cache-Control`,z(e)),{get ifNoneMatch(){let e=t.headers[`if-none-match`];if(!e)return;let n=e.trim();return n===`*`?n:n.split(`,`).map(e=>e.trim().replace(/^(?:W\/)?"/,``).replace(/"$/,``))},get ifModifiedSince(){let e=t.headers[`if-modified-since`];if(!e)return;let n=new Date(e);return isNaN(n.getTime())?void 0:n},get cacheControl(){return Pe(t.headers[`cache-control`])},addCachePolicy:t=>{n.setHeader(`Cache-Control`,z({...e,...t}))},setETag:e=>{n.setHeader(`ETag`,e.startsWith(`"`)?e:`"${e}"`)},setLastModified:e=>{n.setHeader(`Last-Modified`,e.toUTCString())},setVary:(...e)=>{n.setHeader(`Vary`,e.join(`, `))},setExpires:e=>{n.setHeader(`Expires`,e.toUTCString())},clearSiteData:()=>{n.setHeader(`Clear-Site-Data`,`"cache"`)},notModified:()=>{n.status(304).end()}})}),V=e=>new v({handler:async({request:t,response:n})=>({getCookie:e=>t.signedCookies?.[e]??t.cookies?.[e],setCookie:(t,r,i)=>{n.cookie(t,r,{...e,...i})},clearCookie:(t,r)=>{n.clearCookie(t,{...e,...r})}})}),H=e=>{let t=E(`express-rate-limit`)({statusCode:429,...e,handler:(e,t,n,r)=>{n(k(r.statusCode,r.message))}}),{getKey:n,resetKey:r}=t,i={getKey:n,resetKey:r};return new b(t,{statusCode:e?.statusCode,provider:t=>({rateLimit:{...i,...t[e?.requestPropertyName??`rateLimit`]}})})};var U=class e{resultHandler;schema=void 0;statusCodes=new Set;middlewares=[];constructor(e){this.resultHandler=e}#e(t){let n=new e(this.resultHandler);return n.middlewares=this.middlewares.concat(t),n.schema=ke(this.schema,t.schema),n.statusCodes=this.statusCodes.union(t.statusCodes),n}addMiddleware(e){return this.#e(e instanceof v?e:new v(e))}useCookies(...e){return this.#e(V(...e))}useCache(...e){return this.#e(B(...e))}useRateLimit(...e){return this.#e(H(...e))}use=this.addExpressMiddleware;addExpressMiddleware(...e){return this.#e(new b(...e))}addContext(e){return this.#e(new v({handler:({ctx:t})=>e(t)}))}build({input:e=le,output:t,operationId:n,scope:r,tag:i,method:a,statusCode:o,...s}){let{middlewares:c,resultHandler:l}=this,u=new _(typeof a==`string`?[a]:a),d=typeof n==`function`?n:e=>n&&`${n}${e===`head`?`__HEAD`:``}`,f=new _(typeof r==`string`?[r]:r),p=new _(typeof i==`string`?[i]:i);return new ie({...s,middlewares:c,outputSchema:t,resultHandler:l,scopes:f,tags:p,methods:u,getOperationId:d,inputSchema:Ae(this.schema,e),statusCodes:this.statusCodes.union(new Set(typeof o==`number`?[o]:o||[]))})}buildVoid({handler:e,...t}){return this.build({...t,output:le,handler:async t=>(await e(t),{})})}};const Fe=new U(I),Ie=new U(R),W={debug:_e,info:ye,warn:A(`#FFA500`),error:xe,ctx:ve},G={debug:10,info:20,warn:30,error:40},Le=e=>o(e)&&Object.keys(G).some(t=>t in e),K=e=>e in G,Re=(e,t)=>G[e]<G[t],q=me.memoizeWith((e,t)=>`${e}${t}`,(e,t=0)=>Intl.NumberFormat(void 0,{useGrouping:!1,minimumFractionDigits:0,maximumFractionDigits:t,style:`unit`,unitDisplay:`long`,unit:e})),ze=e=>e<1e-6?q(`nanosecond`,3).format(e/1e-6):e<.001?q(`nanosecond`).format(e/1e-6):e<1?q(`microsecond`).format(e/.001):e<1e3?q(`millisecond`).format(e):e<6e4?q(`second`,2).format(e/1e3):q(`minute`,2).format(e/6e4);var J=class e{config;constructor({color:e=ge.isSupported(),level:t=m.isProduction?`warn`:`debug`,depth:n=2,ctx:r={}}={}){this.config={color:e,level:t,depth:n,ctx:r}}format(e){let{depth:t,color:n,level:r}=this.config;return Se(e,{depth:t,colors:n,breakLength:r===`debug`?80:1/0,compact:r!==`debug`||3})}print(e,t,n){let{level:r,ctx:{requestId:i,...a},color:o}=this.config;if(r===`silent`||Re(e,r))return;let s=[new Date().toISOString()];i&&s.push(o?W.ctx(i):i),s.push(o?`${W[e](e)}:`:`${e}:`,t),n!==void 0&&s.push(this.format(n)),Object.keys(a).length>0&&s.push(this.format(a)),console.log(s.join(` `))}debug(e,t){this.print(`debug`,e,t)}info(e,t){this.print(`info`,e,t)}warn(e,t){this.print(`warn`,e,t)}error(e,t){this.print(`error`,e,t)}child(t){return new e({...this.config,ctx:t})}get ctx(){return this.config.ctx}profile(e){let t=M.now();return()=>{let n=M.now()-t,{message:r,severity:i=`debug`,formatter:a=ze}=typeof e==`object`?e:{message:e};this.print(typeof i==`function`?i(n):i,r,a(n))}}},Be=class{logger;config;#e=new WeakMap;constructor(e,t){this.logger=e,this.config=t}#t(e,t,n){if(!e.isSchemaChecked){for(let e of[`input`,`output`]){let r=[O.toJSONSchema(t[`${e}Schema`],{unrepresentable:`any`})];for(let t of r){t.type&&t.type!==`object`&&this.logger.warn(`Endpoint ${e} schema is not object-based`,n);for(let e of[`allOf`,`oneOf`,`anyOf`])t[e]&&r.push(...t[e])}}if(t.getProbableRequestType()===`json`){let e=T(t.inputSchema,`input`);e&&this.logger.warn(`The final input schema of the endpoint contains an unsupported JSON payload type.`,{...n,reason:e})}for(let e of ae)for(let{mimeTypes:r,schema:i}of t.getResponses(e)){if(!r?.includes(x.json))continue;let t=T(i,`output`);t&&this.logger.warn(`The final ${e} response schema of the endpoint contains an unsupported JSON payload type.`,{...n,reason:t})}e.isSchemaChecked=!0}}#n(e,t,n,r,i){if(e.paths.has(r))return;let{pathParams:s,getLocation:c,isQueryEnabled:l}=de({method:n,path:r,security:t.security,inputSources:a(n,this.config.inputSources)});if(!(s.size===0&&!l)){e.flat??=fe(O.toJSONSchema(t.inputSchema,{unrepresentable:`any`,io:`input`,override:({zodSchema:e,jsonSchema:t})=>{(e._zod.traits.has(`$ZodPreprocess`)||`coerce`in e._zod.def&&e._zod.def.coerce)&&(t[pe]=!0)}}));for(let[t,n]of Object.entries(e.flat.properties)){if(!o(n))continue;let r=c(t);(r===`path`||r===`query`)&&(r===`path`&&!e.flat.required?.includes(t)&&this.logger.warn(`The path parameter "${t}" is declared optional in the input schema, but path parameters are always required since Express matches the route only when the segment is present.`,{...i,name:t}),!ue(n,r)&&this.logger.warn(`The ${r} parameter "${t}" has a schema that most likely would not accept the parsed data, ${r===`path`?`since path parameters always arrive as strings`:`depending on the "queryParser" config option`}. Convert the parsed value from "z.string()" using ".transform()" method, or use "z.coerce" at least.`,{...i,name:t,jsonSchema:n}))}for(let e of s)this.logger.warn(`The input schema of the endpoint is most likely missing the parameter of the path it's assigned to.`,{...i,param:e});e.paths.add(r)}}check=(e,t,n)=>{let r=this.#e.get(n);r||(r={isSchemaChecked:!1,paths:new Set},this.#e.set(n,r)),this.#t(r,n,{method:e,path:t}),this.#n(r,n,e,t,{method:e,path:t})}};const Y=e=>e.sort((e,t)=>C(t)-+C(e)||e.localeCompare(t)).join(`, `).toUpperCase(),Ve=e=>({method:t},n,r)=>{let i=Y(e);n.set({Allow:i}),r(k(405,`${t} is not allowed`,{headers:{Allow:i}}))},He=({app:e,getLogger:t,config:n,routing:r})=>{let i=m.isProduction?void 0:new Be(t(),n),a=new Map;return oe({routing:r,config:n,onEndpoint:(e,t,r)=>{i?.check(e,t,r),a.has(t)||a.set(t,new Map(n.cors?[[`options`,r]]:[])),a.get(t)?.set(e,r)},onStatic:e.use.bind(e)}),a},Ue=({app:e,config:t,getLogger:n,...r})=>{let i=He({app:e,getLogger:n,config:t,...r}),a=new Map;for(let[r,o]of i){let i=Array.from(o.keys());i.includes(`get`)&&i.push(`head`);for(let[a,s]of o){let o=[];t.cors&&o.push((e,t,n)=>{t.set(`Access-Control-Allow-Methods`,Y(i)),n()}),o.push(async(e,r)=>{let i=n(e);return s.execute({request:e,response:r,logger:i,config:t})}),e[a]?.(r,...o)}t.hintAllowedMethods!==!1&&a.set(r,Ve(i))}for(let[t,n]of a)e.all(t,n)},We=e=>`_httpMessage`in e&&typeof e._httpMessage==`object`&&e._httpMessage!==null&&`headersSent`in e._httpMessage&&typeof e._httpMessage.headersSent==`boolean`&&`setHeader`in e._httpMessage&&typeof e._httpMessage.setHeader==`function`,Ge=e=>`server`in e&&typeof e.server==`object`&&e.server!==null&&`close`in e.server&&typeof e.server.close==`function`,Ke=e=>`encrypted`in e&&typeof e.encrypted==`boolean`&&e.encrypted,qe=({},e)=>void(!e.headersSent&&e.setHeader(`connection`,`close`)),Je=e=>{let{promise:t,resolve:n,reject:r}=Promise.withResolvers();return e.close(e=>e?r(e):n()),t},Ye=({timeout:e=1e3,logger:t}={})=>{let n,r=new Set,i=new Set,a=e=>void i.delete(e),o=e=>a(e.destroy()),s=e=>void(We(e)?!e._httpMessage.headersSent&&e._httpMessage.setHeader(`connection`,`close`):o(e)),c=e=>void(n?e.destroy():i.add(e.once(`close`,()=>a(e)).once(`error`,()=>o(e)))),l=async()=>{for(let e of r)e.on(`request`,qe);t?.info(`Graceful shutdown`,{sockets:i.size,timeout:e});for(let e of i)(Ke(e)||Ge(e))&&s(e);for await(let t of Te(10,Date.now()))if(i.size===0||Date.now()-t>=e)break;for(let e of i)o(e);return Promise.allSettled(r.values().map(Je))},u={sockets:i,add:(...e)=>{for(let t of e)if(!r.has(t)){r.add(t);for(let e of[`connection`,`secureConnection`])t.on(e,c)}return u},shutdown:()=>n??=l(),get isShuttingDown(){return!!n}};return u},Xe=Symbol.for(`express-zod-api`),Ze=({errorHandler:e,getLogger:n})=>async(r,i,a,o)=>r?e.execute({error:t(r),request:i,response:a,input:null,output:null,ctx:{},logger:n(i)}):o(),Qe=({errorHandler:e,getLogger:t})=>async(n,r)=>{let i=k(404,`Can not ${n.method} ${n.path}`),a=t(n);await e.execute({request:n,response:r,logger:a,error:i,input:null,output:null,ctx:{}})},$e=e=>(t,{},n)=>{if(Object.values(t?.files||[]).flat().find(({truncated:e})=>e))return n(e);n()},et=({config:e})=>{let t=E(`cookie-parser`),{secret:n,...r}={...typeof e.cookies==`object`&&e.cookies};return t(n,Object.keys(r).length?r:void 0)},tt=e=>typeof e==`function`?e:({},e,t)=>{e.set({"Access-Control-Allow-Origin":`*`,"Access-Control-Allow-Headers":`content-type`}),t()},nt=e=>({log:t=>{/not eligible/i.test(t)||e.debug(t)}}),rt=({getLogger:e,config:t})=>{let n=E(`express-fileupload`),{limitError:r,beforeUpload:i,...a}={...typeof t.upload==`object`&&t.upload},o=[];return o.push(async(t,r,o)=>{let s=e(t);return await i?.({request:t,logger:s}),n({debug:!0,...a,abortOnLimit:!1,parseNested:!0,logger:nt(s)})(t,r,o)}),r&&o.push($e(r)),o},it=(e,{},t)=>{Buffer.isBuffer(e.body)&&(e.body={raw:e.body}),t()},at=({logger:e,config:{childLoggerProvider:t,accessLogger:n=({method:e,path:t},n)=>n.debug(`${e}: ${t}`)}})=>async(r,i,a)=>{let o=await t?.({request:r,parent:e})||e;n?.(r,o),r.res&&(r.res.locals[Xe]={logger:o}),a()},ot=e=>t=>t?.res?.locals[Xe]?.logger||e;let st=!1;const ct=e=>{st||(st=!0,process.on(`deprecation`,({message:t,namespace:n,name:r,stack:i})=>e.warn(`${r} (${n}): ${t}`,i.split(`
2
2
  `).slice(1))))};let X,Z,Q;const lt=({servers:e,logger:t,options:{timeout:n,beforeExit:r,events:i=[`SIGINT`,`SIGTERM`]}})=>{X??=Ye({logger:t,timeout:n}),X.add(...e),r&&(Q??=new Set).add(r),Z??=async()=>{X?.isShuttingDown||(await X?.shutdown(),Q&&await Promise.allSettled(Q.values().map(async e=>e())),process.exit())};for(let e of i)process.listeners(e).includes(Z)||process.on(e,Z)},ut=e=>{if(e.columns<62)return;let t=be(`for Angie`.padStart(52)),n=A(`#F5A9B8`),r=A(`#5BCEFA`),i=[r`8888888888${t}`,r`888`,r`888`,r`8888888 888 888 88888b. 888d888 .d88b. .d8888b .d8888b`,n`888 `Y8bd8P' 888 "88b 888P" d8P Y8b 88K 88K`,n`888 X88K 888 888 888 88888888 "Y8888b. "Y8888b.`,n`888 .d8""8b. 888 d88P 888 Y8b. X88 X88`,j`8888888888 888 888 88888P" 888 "Y8888 88888P' 88888P'`,j` 888`,j`8888888888P 888 888 d8888 8888888b. 8888888`,j` d88P 888 d88888 888 Y88b 888`,n` d88P 888 d88P888 888 888 888`,n` d88P .d88b. .d88888 d88P 888 888 d88P 888`,n` d88P d88""88b d88" 888 d88P 888 8888888P" 888`,r` d88P 888 888 888 888 d88P 888 888 888`,r` d88P Y88..88P Y88b 888 d8888888888 888 888`,r`d8888888888 "Y88P" "Y88888 d88P 888 888 8888888`];e.write(`
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.5.2`,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)=>xt(String(t),e[t]).transform(e=>[`event: ${e.event}`,`data: ${JSON.stringify(e.data)}`,``,``].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.6.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)=>xt(String(t),e[t]).transform(e=>[`event: ${e.event}`,`data: ${JSON.stringify(e.data)}`,``,``].join(`
7
7
  `)).parse({event:t,data:n}),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,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.5.2",
3
+ "version": "29.6.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": {
@@ -1 +0,0 @@
1
- import{$ as e,F as t,G as n,I as r,J as i,K as a,N as o,Q as s,R as c,S as l,W as u,X as d,b as f,j as p,nt as m,q as h,r as g,w as _}from"./routing-walker-BmLKqjk4.js";import{z as v}from"zod";import*as y from"ramda";import{isReferenceObject as b,isSchemaObject as x}from"openapi3-ts/oas32";const ee=e=>e.type===`object`,te=y.mergeDeepWith((e,t)=>{if(Array.isArray(e)&&Array.isArray(t))return y.concat(e,t);if(e===t)return t;throw Error(`Can not flatten properties`,{cause:{a:e,b:t}})}),S=new Set([`type`,`properties`,`required`,`examples`,`description`,`additionalProperties`]),C=e=>{for(let t of Object.keys(e))if(!S.has(t))return!1;return!0},w=y.pair(!0),ne=(e,t,n)=>!(`allOf`in e)||!e.allOf?[]:e.allOf.map(e=>{if(t===`throw`&&!(e.type===`object`&&C(e)))throw Error(`Can not merge`);return y.pair(n,e)}),re=e=>{let t=[];return e.anyOf&&t.push(...y.map(w,e.anyOf)),e.oneOf&&t.push(...y.map(w,e.oneOf)),t},ie=(e,t,n,r)=>{if(!a(e.propertyNames))return;let i=[];typeof e.propertyNames.const==`string`&&i.push(e.propertyNames.const),e.propertyNames.enum&&i.push(...e.propertyNames.enum.filter(e=>typeof e==`string`));let o={...Object(e.additionalProperties)};for(let e of i)t.properties[e]??=o;r||n.push(...i)},ae=(e,t,n)=>{t.examples?.length&&(e.examples=n?y.concat(e.examples||[],t.examples):c(e.examples?.filter(a)||[],t.examples.filter(a),([e,t])=>y.mergeDeepRight(e,t)))},T=(e,t=`coerce`)=>{let n=[y.pair(!1,e)],r={type:`object`,properties:{}},i=[];for(let[e,a]of n)a.description&&(r.description??=a.description),n.push(...ne(a,t,e)),n.push(...re(a)),ae(r,a,e),ee(a)&&(n.push([e,{examples:E(a)}]),a.properties&&(r.properties=(t===`throw`?te:y.mergeDeepRight)(r.properties,a.properties),!e&&a.required&&i.push(...a.required)),ie(a,r,i,e));return i.length&&(r.required=[...new Set(i)]),r},E=e=>Object.entries(e.properties||{}).reduce((e,[t,n])=>{let{examples:r=[]}=a(n)?n:{};return c(e,r.map(y.objOf(t)),([e,t])=>({...e,...t}))},[]),D=`x-coerce`,O=new Set([`array`,`object`]),k=(e,t)=>{let n=[e.items,e.prefixItems,e.additionalItems,Object.values(e.properties??{}),e.additionalProperties,e.propertyNames];for(let e of n){if(!a(e))continue;let n=Array.isArray(e)?e:[e];for(let e of n)if(a(e)&&!A(e,t))return!1}return!0},A=(e,t)=>e[`x-coerce`]===!0?!0:e.anyOf?e.anyOf.some(e=>A(e,t)):e.oneOf?e.oneOf.some(e=>A(e,t)):e.allOf?e.allOf.every(e=>A(e,t)):e.type===void 0||e.type===`string`?!0:Array.isArray(e.type)?A({anyOf:e.type.map(t=>({...e,type:t}))},t):t!==`path`&&O.has(e.type)&&k(e,t);let j;const M=()=>j??=new Set(`a-im.accept.accept-additions.accept-charset.accept-datetime.accept-encoding.accept-features.accept-language.accept-signature.access-control.access-control-request-headers.access-control-request-method.alpn.alt-used.amp-cache-transform.apply-to-redirect-ref.authorization.available-dictionary.c-ext.c-man.c-opt.c-pep.c-pep-info.cache-control.cal-managed-id.caldav-timezones.capsule-protocol.cdn-loop.cert-not-after.cert-not-before.client-cert.client-cert-chain.close.cmcd-object.cmcd-request.cmcd-session.cmcd-status.cmsd-dynamic.cmsd-static.concealed-auth-export.configuration-context.connection.content-digest.content-disposition.content-encoding.content-id.content-language.content-length.content-location.content-md5.content-range.content-script-type.content-type.cookie.cookie2.cta-common-access-token.dasl.date.dav.default-style.delta-base.deprecation.depth.derived-from.destination.detached-jws.dictionary-id.differential-id.digest.dpop.early-data.ediint-features.expect.expect-ct.ext.forwarded.from.getprofile.hobareg.host.http2-settings.if.if-match.if-modified-since.if-none-match.if-range.if-schedule-tag-match.if-unmodified-since.im.include-referred-token-binding-id.incremental.isolation.keep-alive.label.last-event-id.link.link-template.lock-token.man.max-forwards.memento-datetime.meter.method-check.method-check-expires.mime-version.negotiate.odata-entityid.odata-isolation.odata-maxversion.odata-version.opt.ordering-type.origin.origin-agent-cluster.oscore.oslc-core-version.overwrite.pep.pep-info.permissions-policy.pics-label.ping-from.ping-to.position.pragma.prefer.preference-applied.priority.profileobject.protocol.protocol-info.protocol-query.protocol-request.proxy-authorization.proxy-features.proxy-instruction.range.redirect-ref.referer.referer-root.referrer-policy.repeatability-client-id.repeatability-first-sent.repeatability-request-id.repeatability-result.replay-nonce.reporting-endpoints.repr-digest.safe.schedule-reply.schedule-tag.sec-fetch-storage-access.sec-gpc.sec-purpose.sec-token-binding.sec-websocket-extensions.sec-websocket-key.sec-websocket-protocol.sec-websocket-version.security-scheme.signature.signature-input.slug.soapaction.status-uri.sunset.surrogate-capability.tcn.te.timeout.topic.traceparent.tracestate.trailer.transfer-encoding.ttl.upgrade.urgency.uri.user-agent.variant-vary.via.want-content-digest.want-digest.want-repr-digest.want-unencoded-digest.warning.x-content-type-options.x-frame-options`.split(`.`)),N={integer:0,number:0,string:``,boolean:!1,object:{},null:null,array:[]},P=e=>e.replace(d,e=>`{${e.slice(1)}}`),F=({},e)=>{if(e.isResponse)throw new _(`Please use ez.upload() only for input.`,e);return{type:`string`,format:`binary`}},I=({jsonSchema:e})=>({...e,externalDocs:{description:`raw binary data`,url:`https://swagger.io/specification/#working-with-binary-data`}}),L=({zodSchema:e,jsonSchema:t})=>{if(!h(e,`union`)||!(`discriminator`in e._zod.def))return t;let n=e._zod.def.discriminator;return{...t,discriminator:t.discriminator??{propertyName:n}}},R=y.tryCatch(({jsonSchema:e})=>{if(!e.allOf)throw`no allOf`;return T(e,`throw`)},(e,{jsonSchema:t})=>t),z=({jsonSchema:e})=>{if(!e.anyOf||!e.anyOf.length)return e;let t=e.anyOf[0];return Object.assign(t,{type:K(t.type)})},B=e=>e,V=({jsonSchema:e},t)=>{if(t.isResponse)throw new _(`Please use ez.dateOut() for output.`,t);return e},H=({jsonSchema:e},t)=>{if(!t.isResponse)throw new _(`Please use ez.dateIn() for input.`,t);return e},U=()=>({type:`string`,format:`bigint`,pattern:`^-?\\d+$`}),W=({zodSchema:e,jsonSchema:t})=>e._zod.def.rest===null?{...t,items:{not:{}}}:t,G=e=>{let t=Array.isArray(e.type)?e.type[0]:e.type;return N?.[t]},K=e=>e===`null`?e:typeof e==`string`?[e,`null`]:e&&[...new Set(e).add(`null`)],q=new Set([`number`,`string`,`boolean`]),J=({zodSchema:e,jsonSchema:t},r)=>{let i=e._zod.def[r.isResponse?`out`:`in`],a=e._zod.def[r.isResponse?`in`:`out`];if(!h(i,`transform`))return t;let o=B(Z(a,{ctx:r}));if(x(o)){if(r.isResponse){let e=n(i,G(o));if(e&&q.has(e))return{...t,type:e}}else{let{type:e,...t}=o;return{...t,format:`${t.format||e} (preprocessed)`}}}return t},oe=({jsonSchema:e})=>{if(e.type!==`object`)return e;let t=e;return!t.properties||!(`raw`in t.properties)||!a(t.properties.raw)?e:t.properties.raw},Y=e=>e.length?y.fromPairs(y.zip(y.times(e=>`example${e+1}`,e.length),y.map(y.objOf(`dataValue`),e))):void 0,se=(e,t)=>t?.has(e)||e.startsWith(`x-`)||M().has(e),ce=({method:e,path:t,security:n,inputSources:r,isHeader:i})=>{let a=new Set(u(t)),o=r.includes(`query`),s=r.includes(`params`),c=r.includes(`headers`),l=r.includes(`cookies`)||r.includes(`signedCookies`),d;c&&n&&(d=g(n,`header`));let f;return l&&n&&(f=g(n,`cookie`)),{pathParams:a,getLocation:n=>{if(s&&a.has(n)&&a.delete(n))return`path`;if(l&&f?.has(n))return`cookie`;if(c&&(i?.(n,e,t)??se(n,d)))return`header`;if(o&&e!==`query`)return`query`},isQueryEnabled:o}},le=({path:e,method:t,flatRequest:n,makeRef:r,composition:o,getLocation:s,description:c=`${t.toUpperCase()} ${e} Parameter`})=>{let l=[];for(let[e,t]of Object.entries(n.properties)){if(!a(t))continue;let u=s(e);if(!u)continue;let d=B(t),f=o===`components`?r(t.id||JSON.stringify(t),d,t.id||i(c,e)):d;l.push({name:e,in:u,deprecated:t.deprecated,required:n.required?.includes(e)||u===`path`,description:d.description||c,schema:f,examples:Y(x(d)&&d.examples?.length?d.examples:y.pluck(e,n.examples?.filter(y.both(a,y.has(e)))||[]))})}return l},X={nullable:z,union:L,bigint:U,intersection:R,tuple:W,pipe:J,[o]:V,[p]:H,[l]:F,[f]:oe,[t]:I},ue=(e,t,n)=>{let r=[e,t],i=e=>/schema\d+$/.test(e)?void 0:e;for(let e=0;e<r.length;e++){let a=r[e];if(y.is(Object,a)){if(b(a)&&!a.$ref.startsWith(`#/components`)){let e=a.$ref.split(`/`).pop(),r=t[e];if(r){let t=r.id||i(e);a.$ref=n.makeRef(t||r,B(r),t).$ref}continue}r.push(...y.values(a))}y.is(Array,a)&&r.push(...y.values(a))}return e},Z=(e,{ctx:t,rules:n=X})=>{let{$defs:i={},properties:o={}}=v.toJSONSchema(v.object({subject:e}),{unrepresentable:`any`,io:t.isResponse?`output`:`input`,override:e=>{let i=v.globalRegistry.get(e.zodSchema)?.id;if(i){let n=t.seenIds.get(i);if(n&&n!==e.zodSchema)throw new _(`The meta id "${i}" is used by two different schemas. Please make the ids unique or reuse the same schema instance.`,t);t.seenIds.set(i,e.zodSchema)}let a=r(e.zodSchema),o=n[a&&a in n?a:e.zodSchema._zod.def.type];if(o){let n={...o(e,t)};for(let t in e.jsonSchema)delete e.jsonSchema[t];Object.assign(e.jsonSchema,n)}}});return ue(a(o.subject)?o.subject:{},i,t)},Q=(e,t)=>{if(b(e))return[e,!1];let n=!1,r=y.map(e=>{let[r,i]=Q(e,t);return n||=i,r}),i=y.omit(t),a={properties:i,examples:y.map(i),required:y.without(t),allOf:r,oneOf:r,anyOf:r},o=y.evolve(a,e);return[o,n||!!o.required?.length]},de=({method:t,path:n,schema:r,mimeTypes:a,variant:o,makeRef:c,composition:l,hasMultipleStatusCodes:u,statusCode:d,brandHandling:f,seenIds:p,description:h=`${t.toUpperCase()} ${n} ${e(o)} response ${u?d:``}`.trim()})=>{if(!s(t,a))return{description:h};let g=B(Z(r,{rules:{...f,...X},ctx:{isResponse:!0,makeRef:c,path:n,method:t,seenIds:p}})),_=[];x(g)&&g.examples&&(_.push(...g.examples),delete g.examples);let v=l===`components`?c(r,g,i(h)):g;return{description:h,content:y.fromPairs(a.map(e=>[e,{[e===m.sse?`itemSchema`:`schema`]:v,examples:Y(_)}]))}},fe=({format:e})=>{let t={type:`http`,scheme:`bearer`};return e&&(t.bearerFormat=e),t},pe=({name:e},t)=>{let n={type:`apiKey`,in:`query`,name:e};return t?.includes(`body`)&&(t?.includes(`query`)?(n[`x-in-alternative`]=`body`,n.description=`${e} CAN also be supplied within the request body`):(n[`x-in-actual`]=`body`,n.description=`${e} MUST be supplied within the request body instead of query`)),n},me=({name:e})=>({type:`apiKey`,in:`header`,name:e}),he=({name:e})=>({type:`apiKey`,in:`cookie`,name:e}),ge=({url:e})=>({type:`openIdConnect`,openIdConnectUrl:e}),$=({flows:e={},oauth2MetadataUrl:t})=>({type:`oauth2`,flows:y.map(e=>({...e,scopes:e.scopes||{}}),y.reject(y.isNil,e)),oauth2MetadataUrl:t}),_e=(e,t=[])=>{let n=e=>e.type===`basic`?{type:`http`,scheme:`basic`}:e.type===`bearer`?fe(e):e.type===`input`?pe(e,t):e.type===`header`?me(e):e.type===`cookie`?he(e):e.type===`openid`?ge(e):$(e);return e.map(e=>e.map(({deprecated:e,...t})=>({...n(t),deprecated:e})))},ve=Set.prototype.has.bind(new Set([`oauth2`,`openIdConnect`])),ye=(e,t,n)=>{let r=Array.from(t);return e.map(e=>{let t={};for(let i of e){let e=n(i);t[e]=ve(i.type)?r:[]}return t})},be=({schema:e,brandHandling:t,makeRef:n,path:r,method:i,seenIds:a})=>Z(e,{rules:{...t,...X},ctx:{isResponse:!1,makeRef:n,path:r,method:i,seenIds:a}}),xe=({method:e,path:t,bodyJsonSchema:n,hasRequiredBodyProps:r,flatRequest:o,mimeType:s,makeRef:c,composition:l,paramNames:u,description:d=`${e.toUpperCase()} ${t} Request body`})=>{let f=B(n),p=[];x(f)&&f.examples&&(p.push(...f.examples),delete f.examples);let h={schema:l===`components`?c(JSON.stringify(f),f,i(d)):f,examples:Y(p.length?p:o.examples?.filter(e=>a(e)&&!Array.isArray(e)).map(y.omit(u))||[])},g={description:d,content:{[s]:h}};return(r||s===m.raw)&&(g.required=!0),g},Se=e=>Object.entries(e).reduce((e,[t,n])=>{if(!n)return e;if(typeof n==`string`)return e.concat({name:t,description:n});let{url:r,...i}=n,a={...i,name:t};return r&&(a.externalDocs={...a.externalDocs,url:r}),e.concat(a)},[]),Ce=(e,t=50)=>!e||e.length<=t?e:e.slice(0,Math.max(1,t||0)-1)+`…`,we=e=>{let t=Array.from(e);return t.length?t:void 0};export{_e as a,Q as c,P as d,Ce as f,A as h,de as i,ce as l,T as m,be as n,ye as o,D as p,le as r,Se as s,xe as t,we as u};