express-zod-api 28.7.5 → 29.0.0-beta.3
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 +68 -39
- package/README.md +36 -33
- package/SECURITY.md +2 -1
- package/dist/documentation-helpers-BLgXFiWr.d.ts +30 -0
- package/dist/documentation.d.ts +75 -0
- package/dist/documentation.js +1 -0
- package/dist/index.d.ts +48 -870
- package/dist/index.js +6 -20
- package/dist/integration.d.ts +85 -0
- package/dist/integration.js +4 -0
- package/dist/json-schema-helpers-Bhz0qPT7.js +1 -0
- package/dist/peer-helpers-eiBZCqrL.js +1 -0
- package/dist/routing-C0jFxoT6.d.ts +742 -0
- package/dist/routing-walker--qYUjhGi.js +1 -0
- package/package.json +18 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{globalRegistry as e,z as t}from"zod";import*as n from"ramda";import{isPromise as r}from"node:util/types";import i,{isHttpError as a}from"http-errors";import o from"express";const s={json:`application/json`,upload:`multipart/form-data`,raw:`application/octet-stream`,sse:`text/event-stream`,form:`application/x-www-form-urlencoded`},c=[`get`,`post`,`put`,`delete`,`patch`,`query`],l=[...c,`head`],u=e=>c.includes(e),d=t.object({}),f=/:([A-Za-z0-9_]+)/g,ee=e=>e.match(f)?.map(e=>e.slice(1))||[],te=e=>{let t=(e.header(`content-type`)||``).toLowerCase().startsWith(s.upload);return`files`in e&&t},ne={get:[`query`,`params`],post:[`body`,`params`,`files`],put:[`body`,`params`],patch:[`body`,`params`],delete:[`query`,`params`],query:[`query`,`body`,`params`]},p=[`body`,`query`,`params`],m=e=>e.method.toLowerCase(),h=(e,t={})=>{if(e===`options`)return[];let n=e===`head`?`get`:u(e)?e:void 0;return(n?t[n]||ne[n]:void 0)||p},g=(e,t={})=>{let n=m(e);return h(n,t).filter(t=>t!==`files`||te(e)).reduce((t,n)=>Object.assign(t,e[n]),{})},_=e=>e instanceof Error?e:e instanceof t.ZodError?new t.ZodRealError(e.issues):Error(String(e)),v=e=>e instanceof t.ZodError?e.issues.map(({path:e,message:n})=>`${e.length?`${t.core.toDotPath(e)}: `:``}${n}`).join(`; `):e.message,y=(e,t)=>C(e)&&`_zod`in e&&(!t||n.path([`_zod`,`def`,`type`],e)===t),b=(e,t,r)=>e.length&&t.length?n.xprod(e,t).map(r):e.concat(t),x=e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase(),S=(...e)=>{let t=n.chain(e=>e.split(/[^A-Z0-9]/gi),e);return n.chain(e=>e.replaceAll(/[A-Z]+/g,e=>`/${e}`).split(`/`),t).map(x).join(``)},re=n.tryCatch((e,n)=>typeof t.parse(e,n),n.always(void 0)),C=e=>typeof e==`object`&&!!e,w=n.memoizeWith(()=>`static`,()=>process.env.NODE_ENV===`production`),ie=(e,t)=>!!t&&e!==`head`,T=`x-brand`,E=t=>{let{[T]:n}=e.get(t)||{};if(typeof n==`symbol`||typeof n==`string`||typeof n==`number`)return n},D=t=>{let{examples:n}=e.get(t)||{};return Array.isArray(n)?n:[]},O=Symbol(`Buffer`),k=()=>t.custom(e=>Buffer.isBuffer(e),{error:`Expected Buffer`}).meta({[T]:O}),A=Symbol(`DateIn`),ae=({examples:e,...n}={})=>t.union([t.iso.date(),t.iso.datetime({local:!0,offset:!0})]).meta({examples:e}).transform(e=>new Date(e)).pipe(t.date()).meta({...n,[T]:A}),j=Symbol(`DateOut`),M=(e={})=>t.date().transform(e=>e.toISOString()).pipe(t.iso.datetime()).meta({...e,[T]:j});var N=class extends Error{name=`RoutingError`;cause;constructor(e,t,n){super(e),this.cause={method:t,path:n}}},oe=class extends Error{name=`DocumentationError`;cause;constructor(e,{method:t,path:n,isResponse:r}){super(e),this.cause=`${r?`Response`:`Input`} schema of an Endpoint assigned to ${t.toUpperCase()} method of ${n} path.`}},P=class extends Error{name=`IOSchemaError`},se=class extends P{cause;name=`DeepCheckError`;constructor(e){super(`Found`,{cause:e}),this.cause=e}},F=class extends P{cause;name=`OutputValidationError`;constructor(e){let n=new t.ZodError(e.issues.map(({path:e,...t})=>({...t,path:[`output`,...e]})));super(v(n),{cause:e}),this.cause=e}},I=class extends P{cause;name=`InputValidationError`;constructor(e){super(v(e),{cause:e}),this.cause=e}},L=class extends Error{cause;handled;name=`ResultHandlerError`;constructor(e,t){super(v(e),{cause:e}),this.cause=e,this.handled=t}},ce=class extends Error{name=`MissingPeerError`;constructor(e){super(`Missing peer dependency: ${e}. Please install it to use the feature.`)}};const R=Symbol(`Form`),le=e=>(e instanceof t.ZodObject?e:t.object(e)).meta({[T]:R}),z=Symbol(`Upload`),B=e=>C(e)&&`name`in e&&`encoding`in e&&`mimetype`in e&&`data`in e&&`tempFilePath`in e&&`truncated`in e&&`size`in e&&`md5`in e&&`mv`in e,V=()=>t.custom(e=>B(e)&&typeof e.name==`string`&&typeof e.encoding==`string`&&typeof e.mimetype==`string`&&Buffer.isBuffer(e.data)&&typeof e.tempFilePath==`string`&&typeof e.truncated==`boolean`&&typeof e.size==`number`&&typeof e.md5==`string`&&typeof e.mv==`function`,{error:({input:e})=>({message:`Expected file upload, received ${typeof e}`})}).meta({[T]:z}),H=Symbol(`Raw`),U=t.object({raw:k()}),W=e=>U.extend(e).meta({[T]:H});function ue(e){return e?W(e):U.meta({[T]:H})}const G=(e,{io:r,condition:i})=>n.tryCatch(()=>void t.toJSONSchema(e,{io:r,unrepresentable:`any`,override:({zodSchema:e})=>{if(i(e))throw new se(e)}}),e=>e.cause)(),de=(e,{io:r})=>{let i=[t.toJSONSchema(e,{io:r,unrepresentable:`any`})];for(let e=0;e<i.length;e++){let t=i[e];if(n.is(Object,t)){if(t.$ref===`#`)return!0;i.push(...n.values(t))}n.is(Array,t)&&i.push(...n.values(t))}return!1},fe=e=>G(e,{condition:e=>{let t=E(e);return typeof t==`symbol`&&[z,H,R].includes(t)},io:`input`}),pe=[`nan`,`symbol`,`map`,`set`,`bigint`,`void`,`promise`,`never`,`function`],me=(e,t)=>G(e,{io:t,condition:e=>{let n=E(e),{type:r}=e._zod.def;return!!(pe.includes(r)||n===O||t===`input`&&(r===`date`||n===j)||t===`output`&&(n===A||n===H||n===z))}});var he=class{},K=class extends he{#e;#t;#n;constructor({input:e,security:t,handler:n}){super(),this.#e=e,this.#t=t,this.#n=n}get security(){return this.#t}get schema(){return this.#e}async execute({input:e,...n}){try{let t=await(this.#e||d).parseAsync(e);return this.#n({...n,input:t})}catch(e){throw e instanceof t.ZodError?new I(e):e}}},q=class extends K{constructor(e,{provider:t=()=>({}),transformer:n=e=>e}={}){super({handler:async({request:i,response:a})=>{let{promise:o,resolve:s,reject:c}=Promise.withResolvers(),l=e=>{if(e&&e instanceof Error)return c(n(e));s(t(i,a))},u=e(i,a,l);return r(u)&&u.catch(l),o}})}};const ge=(e,{variant:n,args:r,...i})=>{if(typeof e==`function`&&(e=e(...r)),e instanceof t.ZodType)return[{schema:e,...i}];if(Array.isArray(e)&&!e.length)throw new L(Error(`At least one ${n} response schema required.`));return(Array.isArray(e)?e:[e]).map(({schema:e,statusCode:t,mimeType:n})=>({schema:e,statusCodes:typeof t==`number`?[t]:t||i.statusCodes,mimeTypes:typeof n==`string`?[n]:n===void 0?i.mimeTypes:n}))},_e=(e,t,{url:n},r)=>!e.expose&&t.error(`Server side error`,{error:e,url:n,payload:r}),ve=e=>a(e)?e:i(e instanceof I?400:500,v(e),{cause:e.cause||e}),ye=e=>w()&&!e.expose?i(e.statusCode).message:e.message,be=e=>Object.entries(e._zod.def.shape).reduce((e,[t,r])=>b(e,D(r).map(n.objOf(t)),([e,t])=>({...e,...t})),[]);var J=class{nest(e){return{...e,"":this}}},xe=class r extends J{#e;#t;#n=n.once(()=>{if(D(this.#e.outputSchema).length||!y(this.#e.outputSchema,`object`))return;let t=be(this.#e.outputSchema);if(!t.length)return;let n=this.#e.outputSchema.meta();e.remove(this.#e.outputSchema).add(this.#e.outputSchema,{...n,examples:t})});constructor(e){super(),this.#e=e}#r(e){return new r({...this.#e,...e})}deprecated(){return this.#r({deprecated:!0})}get isDeprecated(){return this.#e.deprecated||!1}get description(){return this.#e.description}get summary(){return this.#e.summary}get methods(){return Object.freeze(this.#e.methods)}get inputSchema(){return this.#e.inputSchema}get outputSchema(){return this.#e.outputSchema}getProbableRequestType(e){return e===`query`?`form`:this.#t??=(()=>{let e=fe(this.#e.inputSchema);if(e){let t=E(e);if(t===z)return`upload`;if(t===H)return`raw`;if(t===R)return`form`}return`json`})()}getResponses(e){return e===`positive`&&this.#n(),Object.freeze(e===`negative`?this.#e.resultHandler.getNegativeResponse():this.#e.resultHandler.getPositiveResponse(this.#e.outputSchema))}get security(){let e=n.pluck(`security`,this.#e.middlewares||[]);return n.reject(n.isNil,e)}get scopes(){return Object.freeze(this.#e.scopes||[])}get tags(){return Object.freeze(this.#e.tags||[])}getOperationId(e){return this.#e.getOperationId?.(e)}async#i(e){try{return await this.#e.outputSchema.parseAsync(e)}catch(e){throw e instanceof t.ZodError?new F(e):e}}async#a({method:e,logger:t,ctx:n,response:r,...i}){for(let a of this.#e.middlewares||[])if(!(e===`options`&&!(a instanceof q))&&(Object.assign(n,await a.execute({...i,ctx:n,response:r,logger:t})),r.writableEnded)){t.warn(`A middleware has closed the stream. Accumulated context:`,n);break}}async#o({input:e,...n}){let r;try{r=await this.#e.inputSchema.parseAsync(e)}catch(e){throw e instanceof t.ZodError?new I(e):e}return this.#e.handler({...n,input:r})}async#s(e){await this.#e.resultHandler.execute(e)}async execute({request:e,response:t,logger:n,config:r}){let i=m(e),a={},o,s=g(e,r.inputSources);try{if(await this.#a({method:i,input:s,request:e,response:t,logger:n,ctx:a}),t.writableEnded)return;if(i===`options`)return void t.status(200).end();let r=await this.#o({input:s,logger:n,ctx:a});if(t.writableEnded)return;o={output:await this.#i(r),error:null}}catch(e){o={output:null,error:_(e)}}await this.#s({...o,input:s,request:e,response:t,logger:n,ctx:a})}};const Y={positive:200,negative:400},Se=Object.keys(Y);var X=class{#e;constructor(...e){this.#e=e}apply(e,t){return t(e,o.static(...this.#e))}};const Ce=e=>(t,...n)=>{e(t,...n),t===`get`&&e(`head`,...n)},we=e=>{let[t,n]=e.trim().split(/ (.+)/,2);return n&&u(t)?[n,t]:[e]},Te=e=>e.trim().split(`/`).filter(Boolean).join(`/`),Z=({recognizeMethodDependentRoutes:e=!0},t,n)=>Object.entries(t).map(([t,r])=>{let[i,a]=e&&u(t)&&r instanceof J?[`/`,t]:we(t);return[[n||``].concat(Te(i)||[]).join(`/`),r,a]}),Q=(e,t)=>{throw new N(`Route with explicit method can only be assigned with Endpoint`,e,t)},Ee=(e,t,n)=>{if(!(!n||n.includes(e)))throw new N(`Method ${e} is not supported by the assigned Endpoint.`,e,t)},$=(e,t,n)=>{let r=`${e} ${t}`;if(n.has(r))throw new N(`Route has a duplicate`,e,t);n.add(r)},De=({routing:e,config:t,onEndpoint:n,onStatic:r})=>{let i=Z(t,e),a=new Set;for(let e=0;e<i.length;e++){let[o,s,c]=i[e];if(s instanceof J)if(c)$(c,o,a),Ee(c,o,s.methods),n(c,o,s);else{let{methods:e=[`get`]}=s;for(let t of e)$(t,o,a),n(t,o,s)}else c&&Q(c,o),s instanceof X?r&&s.apply(o,r):i.splice(e+1,0,...Z(t,s,o))}};export{k as A,ee as B,F as C,j as D,M as E,d as F,S as G,C as H,_ as I,x as J,f as K,g as L,E as M,D as N,ae as O,b as P,h as R,ce as S,N as T,w as U,re as V,y as W,u as X,l as Y,s as Z,z as _,Se as a,oe as b,ye as c,q as d,K as f,ue as g,H as h,Y as i,O as j,A as k,_e as l,de as m,Ce as n,xe as o,me as p,ie as q,X as r,ve as s,De as t,ge as u,V as v,L as w,I as x,le as y,v as z};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-zod-api",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "29.0.0-beta.3",
|
|
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": {
|
|
@@ -23,6 +23,18 @@
|
|
|
23
23
|
".": {
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"default": "./dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./integration": {
|
|
28
|
+
"types": "./dist/integration.d.ts",
|
|
29
|
+
"default": "./dist/integration.js"
|
|
30
|
+
},
|
|
31
|
+
"./documentation": {
|
|
32
|
+
"types": "./dist/documentation.d.ts",
|
|
33
|
+
"default": "./dist/documentation.js"
|
|
34
|
+
},
|
|
35
|
+
"./dist/*": {
|
|
36
|
+
"types": "./dist/*.d.ts",
|
|
37
|
+
"default": "./dist/*.js"
|
|
26
38
|
}
|
|
27
39
|
},
|
|
28
40
|
"files": [
|
|
@@ -30,12 +42,12 @@
|
|
|
30
42
|
"*.md"
|
|
31
43
|
],
|
|
32
44
|
"engines": {
|
|
33
|
-
"node": "^22.19.0 || ^24.
|
|
45
|
+
"node": "^22.19.0 || ^24.11.0 || ^26.0.0"
|
|
34
46
|
},
|
|
35
47
|
"dependencies": {
|
|
36
48
|
"ansis": "^4.2.0",
|
|
37
|
-
"node-mocks-http": "^1.
|
|
38
|
-
"openapi3-ts": "^4.
|
|
49
|
+
"node-mocks-http": "^1.18.0",
|
|
50
|
+
"openapi3-ts": "^4.6.0",
|
|
39
51
|
"ramda": "^0.32.0"
|
|
40
52
|
},
|
|
41
53
|
"peerDependencies": {
|
|
@@ -52,7 +64,7 @@
|
|
|
52
64
|
"http-errors": "^2.0.1",
|
|
53
65
|
"typescript": "^5.1.3 || ^6.0.2",
|
|
54
66
|
"zod": "^4.3.4",
|
|
55
|
-
"@express-zod-api/zod-plugin": "^
|
|
67
|
+
"@express-zod-api/zod-plugin": "^6.0.0-beta.0"
|
|
56
68
|
},
|
|
57
69
|
"peerDependenciesMeta": {
|
|
58
70
|
"@express-zod-api/zod-plugin": {
|
|
@@ -113,7 +125,7 @@
|
|
|
113
125
|
"typescript": "^6.0.2",
|
|
114
126
|
"undici": "^8.2.0",
|
|
115
127
|
"zod": "^4.4.3",
|
|
116
|
-
"@express-zod-api/zod-plugin": "^
|
|
128
|
+
"@express-zod-api/zod-plugin": "^6.0.0-beta.0"
|
|
117
129
|
},
|
|
118
130
|
"keywords": [
|
|
119
131
|
"nodejs",
|