express-zod-api 29.8.1 → 29.8.2

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,15 @@
2
2
 
3
3
  ## Version 29
4
4
 
5
+ ### v29.8.2
6
+
7
+ - Fixed alias production for Integration generator:
8
+ - Recursive and lazy schemas that are reused both for input and output used to get the same alias;
9
+ - In certain cases the direction affects the generated type, for example for schemas having `.default()`;
10
+ - This version emits an alias for each direction for such schemas (even if they are the same);
11
+ - An alias that used to be named `Type1` will now be either `InputType1` or `ResponseType1` or both;
12
+ - The issue was found and reported by [@giovio](https://github.com/giovio).
13
+
5
14
  ### v29.8.1
6
15
 
7
16
  - Fixed the `HEAD` method of the generated client to avoid parsing the response body by the default implementation.
package/README.md CHANGED
@@ -89,6 +89,7 @@ Therefore, many basic tasks can be achieved faster and easier, in particular:
89
89
 
90
90
  These people contributed to the improvement of the framework by reporting bugs, making changes, and suggesting ideas:
91
91
 
92
+ [<img src="https://github.com/giovio.png" alt="@giovio" width="50" />](https://github.com/giovio)
92
93
  [<img src="https://github.com/marco-carvalho.png" alt="@marco-carvalho" width="50" />](https://github.com/marco-carvalho)
93
94
  [<img src="https://github.com/BetterAndBetterII.png" alt="@BetterAndBetterII" width="50" />](https://github.com/BetterAndBetterII)
94
95
  [<img src="https://github.com/pycanis.png" alt="@pycanis" width="50" />](https://github.com/pycanis)
@@ -940,7 +941,7 @@ import {
940
941
  const yourResultHandler = new ResultHandler({
941
942
  positive: (data) => ({
942
943
  schema: z.object({ data }),
943
- mimeType: "application/json", // optinal or array
944
+ mimeType: "application/json", // optional or array
944
945
  }),
945
946
  negative: z.object({ error: z.string() }),
946
947
  handler: ({ error, input, output, request, response, logger }) => {
package/dist/index.js CHANGED
@@ -3,4 +3,4 @@ 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.8.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=/[\r\n\0]/g,Ct=({events:e,event:t,data:n,id:r,retry:i})=>{if(!Object.prototype.hasOwnProperty.call(e,t))throw Error(`Unknown event: ${t}`);let a=e[t].parse(n),o=`event: ${t}\n`;return r!==void 0&&(o+=`id: ${r}\n`),i!==void 0&&(o+=`retry: ${i}\n`),o+`data: ${JSON.stringify(a)}\n\n`},wt=e=>e.headersSent||e.writeHead(200,{connection:`keep-alive`,"content-type":x.sse,"cache-control":`no-cache`}),Tt=(e,{eventId:t=!1,retry:n}={})=>{let r=0,i;if(n!==void 0&&!(Number.isInteger(n)&&n>0))throw Error(`Invalid SSE retry value "${n}": must be a positive integer.`);return t&&(i=typeof t==`function`?(e,n)=>t(e,n).replace(St,``):(e,t)=>`${e}##${t}`),new v({handler:async({request:t,response:a})=>{let o=new AbortController,s=setTimeout(()=>wt(a),1e4);return t.once(`close`,()=>{clearTimeout(s),o.abort()}),{isClosed:()=>a.writableEnded||a.closed,signal:o.signal,lastEventId:i&&t.get(`last-event-id`),emit:(t,o)=>{wt(a);let s=Ct({events:e,data:o,retry:n,id:i&&i(String(t),++r),event:String(t)});a.write(s,`utf-8`),a.flush?.()}}}})},Et=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 Dt=class extends U{constructor(e,t){for(let t of Object.keys(e))if(t.match(St))throw Error(`Invalid SSE event name "${t}": must not contain line breaks or null characters.`);super(Et(e)),this.middlewares=[Tt(e,t)]}};const Ot=[`total`,`limit`,`offset`],$=[`nextCursor`,`limit`];function kt({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`&&Ot.includes(n))throw Error(`ez.paginated: itemsName must not match reserved keys for offset output (${Ot.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 At={dateIn:c,dateOut:e,form:ee,upload:n,raw:ce,buffer:u,paginated:kt};export{J as BuiltinLogger,se as DocumentationError,U as EndpointsFactory,Dt 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,At as ez,f as getMessageFromError,yt as testEndpoint,bt as testMiddleware};
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.8.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=/[\r\n\0]/g,Ct=({events:e,event:t,data:n,id:r,retry:i})=>{if(!Object.prototype.hasOwnProperty.call(e,t))throw Error(`Unknown event: ${t}`);let a=e[t].parse(n),o=`event: ${t}\n`;return r!==void 0&&(o+=`id: ${r}\n`),i!==void 0&&(o+=`retry: ${i}\n`),o+`data: ${JSON.stringify(a)}\n\n`},wt=e=>e.headersSent||e.writeHead(200,{connection:`keep-alive`,"content-type":x.sse,"cache-control":`no-cache`}),Tt=(e,{eventId:t=!1,retry:n}={})=>{let r=0,i;if(n!==void 0&&!(Number.isInteger(n)&&n>0))throw Error(`Invalid SSE retry value "${n}": must be a positive integer.`);return t&&(i=typeof t==`function`?(e,n)=>t(e,n).replace(St,``):(e,t)=>`${e}##${t}`),new v({handler:async({request:t,response:a})=>{let o=new AbortController,s=setTimeout(()=>wt(a),1e4);return t.once(`close`,()=>{clearTimeout(s),o.abort()}),{isClosed:()=>a.writableEnded||a.closed,signal:o.signal,lastEventId:i&&t.get(`last-event-id`),emit:(t,o)=>{wt(a);let s=Ct({events:e,data:o,retry:n,id:i&&i(String(t),++r),event:String(t)});a.write(s,`utf-8`),a.flush?.()}}}})},Et=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 Dt=class extends U{constructor(e,t){for(let t of Object.keys(e))if(t.match(St))throw Error(`Invalid SSE event name "${t}": must not contain line breaks or null characters.`);super(Et(e)),this.middlewares=[Tt(e,t)]}};const Ot=[`total`,`limit`,`offset`],$=[`nextCursor`,`limit`];function kt({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`&&Ot.includes(n))throw Error(`ez.paginated: itemsName must not match reserved keys for offset output (${Ot.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 At={dateIn:c,dateOut:e,form:ee,upload:n,raw:ce,buffer:u,paginated:kt};export{J as BuiltinLogger,se as DocumentationError,U as EndpointsFactory,Dt 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,At as ez,f as getMessageFromError,yt as testEndpoint,bt as testMiddleware};
@@ -6,8 +6,8 @@ import{F as e,G as t,I as n,J as r,N as i,Q as a,b as o,et as s,j as c,n as l,nt
6
6
  `)};makeDefaultImplementation=e=>{let t=`${x.method}, ${x.path}, ${x.params}, ${x.ctx}`,n=C([`get`,`head`,`delete`]).join(`, `),r=`!${x.hasBody} || ${x.hasFiles} ? ${x.undefined} : { "Content-Type": ${x.isBlob} ? "${u.raw}" : "${u.json}" };`,i=`${x.response}.${w(`headers`)}.${w(`get`)}("content-type")`,a=`\`?\${new ${URLSearchParams.name}(${x.params})}\``;return[`const ${x.defaultImplementation}: ${x.Implementation}<${x.DefaultContext}> = async (${t}) => {`,` const ${x.isBlob} = ${x.params} instanceof Blob;`,` const ${x.hasFiles} = !${x.isBlob} && Object.${w(`values`)}(${x.params}).${w(`some`)}((one) => one instanceof Blob || one instanceof ${x.File});`,` const ${x.hasBody} = ![${n}].includes(${x.method});`,` const ${x.searchParams} = ${x.isBlob} || ${x.hasBody} ? "" : ${a};`,` const ${x.headers} = ${r}`,` let ${x.body}: RequestInit["${x.body}"] = ${x.undefined};`,` if (${x.hasBody}) {`,` if (${x.isBlob}) {`,` ${x.body} = ${x.params};`,` } else if (${x.hasFiles}) {`,` ${x.body} = new ${FormData.name}();`,` for (const [${x.key}, ${x.value}] of Object.${w(`entries`)}(${x.params}))`,` if (${x.value} !== undefined) ${x.body}.${w(`append`)}(${x.key}, ${x.value});`,` } else {`,` ${x.body} = JSON.${w(`stringify`)}(${x.params});`,` }`,` }`,` let init: RequestInit = {`,` ${w(`method`)}: ${x.method}.${w(`toUpperCase`)}(),`,` ${w(`credentials`)}: ${e?`"include"`:x.undefined},`,` ${x.headers},`,` ${x.body},`,` };`,` if (${x.ctx}?.${x.override}) init = ${x.ctx}.${x.override}(init);`,` const ${x.response} = await ${fetch.name}(`,` new ${URL.name}(\`\${${x.path}}\${${x.searchParams}}\`, "${this.serverUrl}"),`,` init,`,` );`,` const ${x.contentType} = ${i};`,` if (${x.method} === "head" || !${x.contentType}) return;`,` if (${x.contentType}.${w(`startsWith`)}("${u.json}")) return ${x.response}.${w(`json`)}();`,` if (${x.contentType}.${w(`startsWith`)}("text/")) return ${x.response}.${w(`text`)}();`,` return ${x.response}.${w(`blob`)}();`,`};`].join(`
7
7
  `)};makeSubscriptionClass=(e,t)=>{let n=`${x.substitute}(${x.parseRequest}(${x.request})[1], ${x.params})`,r=`Extract<R, { ${w(`event`)}: E }>["${w(`data`)}"]`,i=`(${x.msg} as ${MessageEvent.name}).${w(`data`)}`;return[`export class ${e}<`,` K extends Extract<${x.Request}, \`get \${string}\`>,`,` R extends Extract<${S.positive}[K], { ${w(`event`)}: string }>,`,`> {`,` public ${x.source}: EventSource;`,` public constructor(${x.request}: K, ${x.params}: ${S.input}[K]) {`,` const [${x.path}, ${x.rest}] = ${n};`,` const ${x.searchParams} = \`?\${new ${URLSearchParams.name}(${x.rest})}\`;`,` this.${x.source} = new EventSource(`,` new URL(\`\${${x.path}}\${${x.searchParams}}\`, "${this.serverUrl}"),`,` { ${w(`withCredentials`)}: ${t?`true`:x.undefined} }`,` );`,` }`,` public ${x.on}<E extends R["${w(`event`)}"]>(`,` ${w(`event`)}: E,`,` ${x.handler}: (${x.data}: ${r}) => void | Promise<void>,`,` ) {`,` this.${x.source}.${w(`addEventListener`)}(${x.event}, (${x.msg}) =>`,` ${x.handler}(JSON.${w(`parse`)}(${i})),`,` );`,` return this;`,` }`,`}`].join(`
8
8
  `)};makeUsageStatements=(e,t)=>[`const ${x.client} = new ${e}();`,`${x.client}.${x.provide}("get /v1/user/retrieve", { id: "10" });`,`new ${t}("get /v1/events/stream", {}).${x.on}("time", (time) => {});`].join(`
9
- `)};const T=b.factory,E=/^[A-Za-z_$][A-Za-z0-9_$]*$/,D=new Set([b.SyntaxKind.AnyKeyword,b.SyntaxKind.BigIntKeyword,b.SyntaxKind.BooleanKeyword,b.SyntaxKind.NeverKeyword,b.SyntaxKind.NumberKeyword,b.SyntaxKind.ObjectKeyword,b.SyntaxKind.StringKeyword,b.SyntaxKind.SymbolKeyword,b.SyntaxKind.UndefinedKeyword,b.SyntaxKind.UnknownKeyword,b.SyntaxKind.VoidKeyword]),O=e=>typeof e==`number`?T.createNumericLiteral(e):typeof e==`bigint`?T.createBigIntLiteral(e.toString()):typeof e==`boolean`?e?T.createTrue():T.createFalse():e===null?T.createNull():T.createStringLiteral(e),k=e=>T.createIdentifier(e),A=e=>typeof e==`string`&&E.test(e)?k(e):O(e),j=(e,t)=>typeof e==`number`?T.createKeywordTypeNode(e):typeof e==`string`||b.isIdentifier(e)?T.createTypeReferenceNode(e,t&&y.map(j,t)):e,M=e=>{let t=new Map;for(let n of e)t.set(N(n)?n.kind:n,n);return T.createUnionTypeNode(Array.from(t.values()))},N=e=>D.has(e.kind),P=(e,t)=>b.addSyntheticLeadingComment(e,b.SyntaxKind.MultiLineCommentTrivia,`* ${t} `,!0),F=(e,t)=>{let n=b.createSourceFile(`print.ts`,``,b.ScriptTarget.Latest,!1,b.ScriptKind.TS);return b.createPrinter(t).printNode(b.EmitHint.Unspecified,e,n)},te=(e,t,{isOptional:n,hasUndefined:r=n,isDeprecated:i,comment:a}={})=>{let o=j(t),s=T.createPropertySignature(void 0,A(e),n?T.createToken(b.SyntaxKind.QuestionToken):void 0,r?M([o,j(b.SyntaxKind.UndefinedKeyword)]):o),c=y.reject(y.isNil,[i?`@deprecated`:void 0,a]);return c.length?P(s,c.join(` `)):s},I=e=>T.createLiteralTypeNode(O(e)),L=(e,{rules:t,onMissing:r,ctx:i={}})=>{let a=n(e),o=a&&a in t?t[a]:t[e._zod.def.type],s=e=>L(e,{ctx:i,rules:t,onMissing:r});return o?o(e,{...i,next:s}):r(e,i)},R={name:y.path([`name`,`text`]),type:y.path([`type`]),optional:y.path([`questionToken`])},z=({_zod:{def:e}})=>{let t=e.values.map(e=>e===void 0?j(b.SyntaxKind.UndefinedKeyword):I(e));return t.length===1?t[0]:M(t)},B=({_zod:{def:e}},{next:t})=>{let{parts:n}=e,r=0,i=()=>{let e=``;for(;r<n.length;){let t=n[r];if(f(t))break;r++,e+=t??``}return e},a=T.createTemplateHead(i()),o=[];for(;r<n.length;){let e=t(n[r++]),a=i(),s=r<n.length?T.createTemplateMiddle:T.createTemplateTail;o.push(T.createTemplateLiteralTypeSpan(e,s(a)))}return o.length?T.createTemplateLiteralType(a,o):I(a.text)},V=(e,{isResponse:t,next:n,makeAlias:r})=>{let i=()=>{let r=Object.entries(e._zod.def.shape).map(([e,r])=>{let{description:i,deprecated:a}=_.get(r)||{},o=(t?r._zod.optout:r._zod.optin)!==void 0,s=o&&!(r instanceof v.core.$ZodExactOptional);return te(e,n(r),{comment:i,isDeprecated:a,isOptional:o,hasUndefined:s})});return T.createTypeLiteralNode(r)};return h(e,{io:t?`output`:`input`})?r(e,i):i()},H=({_zod:{def:e}},{next:t})=>T.createArrayTypeNode(t(e.element)),U=({_zod:{def:e}})=>M(y.map(I,Object.values(e.entries))),W=({_zod:{def:e}},{next:t})=>M(e.options.map(t)),G=({_zod:{def:e}},{next:t})=>M([t(e.innerType),I(null)]),K=({_zod:{def:e}},{next:t})=>T.createTupleTypeNode(e.items.map(t).concat(e.rest===null?[]:T.createRestTypeNode(t(e.rest)))),q=({_zod:{def:e}},{next:t})=>{let[n,r]=[e.keyType,e.valueType].map(t),i=j(`Record`,[n,r]);return e.mode===`loose`?T.createIntersectionTypeNode([i,j(`Record`,[`PropertyKey`,r])]):i},J=y.tryCatch(e=>{if(!e.every(b.isTypeLiteralNode))throw Error(`Not objects`);let t=y.chain(y.prop(`members`),e),n=y.uniqWith((...e)=>{if(!y.eqBy(R.name,...e))return!1;if(y.both(y.eqBy(R.type),y.eqBy(R.optional))(...e))return!0;throw Error(`Has conflicting prop`)},t);return T.createTypeLiteralNode(n)},(e,t)=>T.createIntersectionTypeNode(t)),Y=({_zod:{def:e}},{next:t})=>J([e.left,e.right].map(t)),X=e=>()=>j(e),Z=({_zod:{def:e}},{next:t})=>t(e.innerType),Q=e=>j(e?b.SyntaxKind.UnknownKeyword:b.SyntaxKind.AnyKeyword),ne=({_zod:{def:e}},{next:n,isResponse:r})=>{let i=e[r?`out`:`in`],a=e[r?`in`:`out`];if(!f(i,`transform`))return n(i);let o=n(a),s={[b.SyntaxKind.AnyKeyword]:``,[b.SyntaxKind.BigIntKeyword]:BigInt(0),[b.SyntaxKind.BooleanKeyword]:!1,[b.SyntaxKind.NumberKeyword]:0,[b.SyntaxKind.ObjectKeyword]:{},[b.SyntaxKind.StringKeyword]:``,[b.SyntaxKind.UndefinedKeyword]:void 0}[o.kind],c=t(i,s),l={number:b.SyntaxKind.NumberKeyword,bigint:b.SyntaxKind.BigIntKeyword,boolean:b.SyntaxKind.BooleanKeyword,string:b.SyntaxKind.StringKeyword,undefined:b.SyntaxKind.UndefinedKeyword,object:b.SyntaxKind.ObjectKeyword};return j(c&&l[c]||Q(r))},re=()=>I(null),ie=({_zod:{def:e}},{makeAlias:t,next:n})=>t(e.getter,()=>n(e.getter())),ae=()=>j(`Blob`),oe=(e,{next:t})=>t(e._zod.def.shape.raw),se={string:X(b.SyntaxKind.StringKeyword),number:X(b.SyntaxKind.NumberKeyword),bigint:X(b.SyntaxKind.BigIntKeyword),boolean:X(b.SyntaxKind.BooleanKeyword),any:X(b.SyntaxKind.AnyKeyword),undefined:X(b.SyntaxKind.UndefinedKeyword),[i]:X(b.SyntaxKind.StringKeyword),[c]:X(b.SyntaxKind.StringKeyword),never:X(b.SyntaxKind.NeverKeyword),void:X(b.SyntaxKind.UndefinedKeyword),unknown:X(b.SyntaxKind.UnknownKeyword),null:re,array:H,tuple:K,record:q,object:V,literal:z,template_literal:B,intersection:Y,union:W,default:Z,enum:U,optional:Z,nonoptional:Z,nullable:G,catch:Z,pipe:ne,lazy:ie,readonly:Z,[e]:ae,[o]:oe},$=(e,{brandHandling:t,ctx:n})=>L(e,{rules:{...t,...se},onMissing:({},{isResponse:e})=>Q(e),ctx:n});var ce=class extends ee{#e=[];#t=new Map;#n;#r(e,t){let n=this.#t.get(e);if(!n){n=`Type${this.#t.size+1}`,this.#t.set(e,n);let r=t();this.#e.push(e=>`type ${n} = ${F(r,e)};`)}return j(n)}constructor({routing:e,config:t,brandHandling:n,variant:i=`client`,clientClassName:o=`Client`,subscriptionClassName:s=`Subscription`,serverUrl:c=`https://example.com`,noBodySchema:u=v.undefined(),hasHeadMethod:f=!0,hasCredentials:h=!1}){super(c);let g={makeAlias:this.#r.bind(this)},_={brandHandling:n,ctx:{...g,isResponse:!1}},y={brandHandling:n,ctx:{...g,isResponse:!0}},b=!1,x=(e,t,n)=>{let i=r.bind(null,e,t),{isDeprecated:o,inputSchema:s,tags:c}=n,l=`${e} ${t}`,f=i(`input`),m=p(n.security,`cookie`);m.size&&(b=!0);let h=$(s,_);this.#e.push(e=>{let t=F(h,e);return[`/** ${l} */`,`type ${f} = ${m.size?this.makeOmit(t,m,`security cookies`):t};`].join(`
10
- `)});let g=d.reduce((t,r)=>{let o=n.getResponses(r),s=[];for(let[t,{schema:n,mimeTypes:c,statusCodes:d}]of o.entries()){let o=a(e,c),f=i(r,`variant`,`${t+1}`),p=$(o?n:u,y);this.#e.push(e=>`/** ${l} */\ntype ${f} = ${F(p,e)};`);for(let e of d)s.push(` ${e}: ${f};`)}let c=i(r,`response`,`variants`);return this.#e.push(`/** ${l} */\ninterface ${c} {\n${s.join(`
11
- `)}\n}`),Object.assign(t,{[r]:c})},{});this.paths.add(t);let v={input:f,positive:this.someOf(g.positive),negative:this.someOf(g.negative),response:`${S.positive}["${l}"] | ${S.negative}["${l}"]`,encoded:`${g.positive} & ${g.negative}`};this.registry.set(l,{isDeprecated:o,store:v}),this.tags.set(l,c)};m({routing:e,config:t,onEndpoint:f?l(x):x}),this.#e.push(this.makeSomeOfType(),this.makePathType(),this.makeMethodType(),...this.makePublicInterfaces(),this.makeRequestType()),i!==`types`&&(this.#e.push(this.makeEndpointTags(),this.makeParseRequestFn(),this.makeSubstituteFn(),this.makeImplementationType(),this.makePaginationType(),this.makeDefaultContextType(),this.makeDefaultImplementation(h&&b),this.makeClientClass(o),this.makeSubscriptionClass(s,h&&b)),this.#n=this.makeUsageStatements(o,s))}print(e){let t=this.#e.map(t=>typeof t==`function`?t(e):t);return this.#n&&t.push(`// Usage example:\n/*\n${this.#n}*/`),t.join(`
9
+ `)};const T=b.factory,E=/^[A-Za-z_$][A-Za-z0-9_$]*$/,D=new Set([b.SyntaxKind.AnyKeyword,b.SyntaxKind.BigIntKeyword,b.SyntaxKind.BooleanKeyword,b.SyntaxKind.NeverKeyword,b.SyntaxKind.NumberKeyword,b.SyntaxKind.ObjectKeyword,b.SyntaxKind.StringKeyword,b.SyntaxKind.SymbolKeyword,b.SyntaxKind.UndefinedKeyword,b.SyntaxKind.UnknownKeyword,b.SyntaxKind.VoidKeyword]),O=e=>typeof e==`number`?T.createNumericLiteral(e):typeof e==`bigint`?T.createBigIntLiteral(e.toString()):typeof e==`boolean`?e?T.createTrue():T.createFalse():e===null?T.createNull():T.createStringLiteral(e),k=e=>T.createIdentifier(e),A=e=>typeof e==`string`&&E.test(e)?k(e):O(e),j=(e,t)=>typeof e==`number`?T.createKeywordTypeNode(e):typeof e==`string`||b.isIdentifier(e)?T.createTypeReferenceNode(e,t&&y.map(j,t)):e,M=e=>{let t=new Map;for(let n of e)t.set(N(n)?n.kind:n,n);return T.createUnionTypeNode(Array.from(t.values()))},N=e=>D.has(e.kind),P=(e,t)=>b.addSyntheticLeadingComment(e,b.SyntaxKind.MultiLineCommentTrivia,`* ${t} `,!0),F=(e,t)=>{let n=b.createSourceFile(`print.ts`,``,b.ScriptTarget.Latest,!1,b.ScriptKind.TS);return b.createPrinter(t).printNode(b.EmitHint.Unspecified,e,n)},te=(e,t,{isOptional:n,hasUndefined:r=n,isDeprecated:i,comment:a}={})=>{let o=j(t),s=T.createPropertySignature(void 0,A(e),n?T.createToken(b.SyntaxKind.QuestionToken):void 0,r?M([o,j(b.SyntaxKind.UndefinedKeyword)]):o),c=y.reject(y.isNil,[i?`@deprecated`:void 0,a]);return c.length?P(s,c.join(` `)):s},I=e=>T.createLiteralTypeNode(O(e)),L=(e,{rules:t,onMissing:r,ctx:i={}})=>{let a=n(e),o=a&&a in t?t[a]:t[e._zod.def.type],s=e=>L(e,{ctx:i,rules:t,onMissing:r});return o?o(e,{...i,next:s}):r(e,i)},R={name:y.path([`name`,`text`]),type:y.path([`type`]),optional:y.path([`questionToken`])},z=({_zod:{def:e}})=>{let t=e.values.map(e=>e===void 0?j(b.SyntaxKind.UndefinedKeyword):I(e));return t.length===1?t[0]:M(t)},B=({_zod:{def:e}},{next:t})=>{let{parts:n}=e,r=0,i=()=>{let e=``;for(;r<n.length;){let t=n[r];if(f(t))break;r++,e+=t??``}return e},a=T.createTemplateHead(i()),o=[];for(;r<n.length;){let e=t(n[r++]),a=i(),s=r<n.length?T.createTemplateMiddle:T.createTemplateTail;o.push(T.createTemplateLiteralTypeSpan(e,s(a)))}return o.length?T.createTemplateLiteralType(a,o):I(a.text)},V=(e,{isResponse:t,next:n,makeAlias:r})=>{let i=()=>{let r=Object.entries(e._zod.def.shape).map(([e,r])=>{let{description:i,deprecated:a}=_.get(r)||{},o=(t?r._zod.optout:r._zod.optin)!==void 0,s=o&&!(r instanceof v.core.$ZodExactOptional);return te(e,n(r),{comment:i,isDeprecated:a,isOptional:o,hasUndefined:s})});return T.createTypeLiteralNode(r)};return h(e,{io:t?`output`:`input`})?r(e,i):i()},H=({_zod:{def:e}},{next:t})=>T.createArrayTypeNode(t(e.element)),U=({_zod:{def:e}})=>M(y.map(I,Object.values(e.entries))),W=({_zod:{def:e}},{next:t})=>M(e.options.map(t)),G=({_zod:{def:e}},{next:t})=>M([t(e.innerType),I(null)]),K=({_zod:{def:e}},{next:t})=>T.createTupleTypeNode(e.items.map(t).concat(e.rest===null?[]:T.createRestTypeNode(t(e.rest)))),q=({_zod:{def:e}},{next:t})=>{let[n,r]=[e.keyType,e.valueType].map(t),i=j(`Record`,[n,r]);return e.mode===`loose`?T.createIntersectionTypeNode([i,j(`Record`,[`PropertyKey`,r])]):i},J=y.tryCatch(e=>{if(!e.every(b.isTypeLiteralNode))throw Error(`Not objects`);let t=y.chain(y.prop(`members`),e),n=y.uniqWith((...e)=>{if(!y.eqBy(R.name,...e))return!1;if(y.both(y.eqBy(R.type),y.eqBy(R.optional))(...e))return!0;throw Error(`Has conflicting prop`)},t);return T.createTypeLiteralNode(n)},(e,t)=>T.createIntersectionTypeNode(t)),Y=({_zod:{def:e}},{next:t})=>J([e.left,e.right].map(t)),X=e=>()=>j(e),Z=({_zod:{def:e}},{next:t})=>t(e.innerType),Q=e=>j(e?b.SyntaxKind.UnknownKeyword:b.SyntaxKind.AnyKeyword),ne=({_zod:{def:e}},{next:n,isResponse:r})=>{let i=e[r?`out`:`in`],a=e[r?`in`:`out`];if(!f(i,`transform`))return n(i);let o=n(a),s={[b.SyntaxKind.AnyKeyword]:``,[b.SyntaxKind.BigIntKeyword]:BigInt(0),[b.SyntaxKind.BooleanKeyword]:!1,[b.SyntaxKind.NumberKeyword]:0,[b.SyntaxKind.ObjectKeyword]:{},[b.SyntaxKind.StringKeyword]:``,[b.SyntaxKind.UndefinedKeyword]:void 0}[o.kind],c=t(i,s),l={number:b.SyntaxKind.NumberKeyword,bigint:b.SyntaxKind.BigIntKeyword,boolean:b.SyntaxKind.BooleanKeyword,string:b.SyntaxKind.StringKeyword,undefined:b.SyntaxKind.UndefinedKeyword,object:b.SyntaxKind.ObjectKeyword};return j(c&&l[c]||Q(r))},re=()=>I(null),ie=({_zod:{def:e}},{makeAlias:t,next:n})=>t(e.getter,()=>n(e.getter())),ae=()=>j(`Blob`),oe=(e,{next:t})=>t(e._zod.def.shape.raw),se={string:X(b.SyntaxKind.StringKeyword),number:X(b.SyntaxKind.NumberKeyword),bigint:X(b.SyntaxKind.BigIntKeyword),boolean:X(b.SyntaxKind.BooleanKeyword),any:X(b.SyntaxKind.AnyKeyword),undefined:X(b.SyntaxKind.UndefinedKeyword),[i]:X(b.SyntaxKind.StringKeyword),[c]:X(b.SyntaxKind.StringKeyword),never:X(b.SyntaxKind.NeverKeyword),void:X(b.SyntaxKind.UndefinedKeyword),unknown:X(b.SyntaxKind.UnknownKeyword),null:re,array:H,tuple:K,record:q,object:V,literal:z,template_literal:B,intersection:Y,union:W,default:Z,enum:U,optional:Z,nonoptional:Z,nullable:G,catch:Z,pipe:ne,lazy:ie,readonly:Z,[e]:ae,[o]:oe},$=(e,{brandHandling:t,ctx:n})=>L(e,{rules:{...t,...se},onMissing:({},{isResponse:e})=>Q(e),ctx:n});var ce=class extends ee{#e=[];#t=new Map([[!1,new Map],[!0,new Map]]);#n;#r(e,t,n){let r=this.#t.get(e),i=r.get(t);if(!i){i=`${e?`Response`:`Input`}Type${r.size+1}`,r.set(t,i);let a=n();this.#e.push(e=>`type ${i} = ${F(a,e)};`)}return j(i)}constructor({routing:e,config:t,brandHandling:n,variant:i=`client`,clientClassName:o=`Client`,subscriptionClassName:s=`Subscription`,serverUrl:c=`https://example.com`,noBodySchema:u=v.undefined(),hasHeadMethod:f=!0,hasCredentials:h=!1}){super(c);let g={brandHandling:n,ctx:{isResponse:!1,makeAlias:this.#r.bind(this,!1)}},_={brandHandling:n,ctx:{isResponse:!0,makeAlias:this.#r.bind(this,!0)}},y=!1,b=(e,t,n)=>{let i=r.bind(null,e,t),{isDeprecated:o,inputSchema:s,tags:c}=n,l=`${e} ${t}`,f=i(`input`),m=p(n.security,`cookie`);m.size&&(y=!0);let h=$(s,g);this.#e.push(e=>{let t=F(h,e);return[`/** ${l} */`,`type ${f} = ${m.size?this.makeOmit(t,m,`security cookies`):t};`].join(`
10
+ `)});let v=d.reduce((t,r)=>{let o=n.getResponses(r),s=[];for(let[t,{schema:n,mimeTypes:c,statusCodes:d}]of o.entries()){let o=a(e,c),f=i(r,`variant`,`${t+1}`),p=$(o?n:u,_);this.#e.push(e=>`/** ${l} */\ntype ${f} = ${F(p,e)};`);for(let e of d)s.push(` ${e}: ${f};`)}let c=i(r,`response`,`variants`);return this.#e.push(`/** ${l} */\ninterface ${c} {\n${s.join(`
11
+ `)}\n}`),Object.assign(t,{[r]:c})},{});this.paths.add(t);let b={input:f,positive:this.someOf(v.positive),negative:this.someOf(v.negative),response:`${S.positive}["${l}"] | ${S.negative}["${l}"]`,encoded:`${v.positive} & ${v.negative}`};this.registry.set(l,{isDeprecated:o,store:b}),this.tags.set(l,c)};m({routing:e,config:t,onEndpoint:f?l(b):b}),this.#e.push(this.makeSomeOfType(),this.makePathType(),this.makeMethodType(),...this.makePublicInterfaces(),this.makeRequestType()),i!==`types`&&(this.#e.push(this.makeEndpointTags(),this.makeParseRequestFn(),this.makeSubstituteFn(),this.makeImplementationType(),this.makePaginationType(),this.makeDefaultContextType(),this.makeDefaultImplementation(h&&y),this.makeClientClass(o),this.makeSubscriptionClass(s,h&&y)),this.#n=this.makeUsageStatements(o,s))}print(e){let t=this.#e.map(t=>typeof t==`function`?t(e):t);return this.#n&&t.push(`// Usage example:\n/*\n${this.#n}*/`),t.join(`
12
12
 
13
13
  `)}async printFormatted({printerOptions:e,format:t}={}){let n=t;if(!n){try{let e=g(`prettier`).format;n=t=>e(t,{filepath:`client.ts`})}catch{}try{let e=g(`oxfmt`).format;n=async t=>{let{code:n,errors:r}=await e(`client.ts`,t);if(r.length)throw Error(`OxFmt failed to format the code`,{cause:r});return n}}catch{}}this.#n&&n&&(this.#n=await n(this.#n));let r=this.print(e);return n?n(r):r}};export{ce as Integration};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-zod-api",
3
- "version": "29.8.1",
3
+ "version": "29.8.2",
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": {