UNPKG

@spailybot/moleculer-auto-openapi

Version:
4 lines (3 loc) 37.5 kB
"use strict";var ke=Object.create;var U=Object.defineProperty;var He=Object.getOwnPropertyDescriptor;var Be=Object.getOwnPropertyNames;var qe=Object.getPrototypeOf,Ge=Object.prototype.hasOwnProperty;var We=(a,t)=>{for(var e in t)U(a,e,{get:t[e],enumerable:!0})},Re=(a,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Be(t))!Ge.call(a,n)&&n!==e&&U(a,n,{get:()=>t[n],enumerable:!(r=He(t,n))||r.enumerable});return a};var T=(a,t,e)=>(e=a!=null?ke(qe(a)):{},Re(t||!a||!a.__esModule?U(e,"default",{value:a,enumerable:!0}):e,a)),Ye=a=>Re(U({},"__esModule",{value:!0}),a);var ht={};We(ht,{Alias:()=>R,ECacheMode:()=>ve,HTTP_METHODS:()=>I,JOKER_METHOD:()=>S,OPENAPI_VERSIONS_SUPPORTED:()=>_e,OpenApiMixin:()=>lt,PathAction:()=>V,Route:()=>$,default:()=>mt,mixin:()=>K});module.exports=Ye(ht);var Te="unknown-action",ze={server:"x-moleculer-web-server"},Je={optional:"x-fastest-optional",description:"x-fastest-description",summary:"x-fastest-summary",deprecated:"x-fastest-deprecated"},O={...ze,...Je},I=(l=>(l.GET="get",l.PUT="put",l.POST="post",l.DELETE="delete",l.OPTIONS="options",l.HEAD="head",l.PATCH="patch",l.TRACE="trace",l))(I||{}),_e=["3.1"],xe="3.1",Z=Object.values(I),X=a=>Z.includes(a==null?void 0:a.toLowerCase()),S="*",N="rest",Q=["oneOf","allOf","anyOf"],ee=["put","post","patch"],dt=Object.values(I).filter(a=>!ee.includes(a)),w="application/json",k="file",Ie=`{{summary}} ({{action}}){{autoAlias}}`,Me="//unpkg.com/swagger-ui-dist",te=/^[a-zA-Z0-9._-]+$/,H={json:["application/json"],urlencoded:["application/x-www-form-urlencoded"],text:["text/plain"],multipart:["multipart/form-data"],stream:["application/octet-stream"]};var Le=T(require("moleculer"),1);var ve=(r=>(r.NEXT_CALL="next-call",r.REFRESH="refresh",r.TIMEOUT="timeout",r))(ve||{});var Ke={type:"object",properties:{rows:{type:"array",items:{type:"object"}},totalCount:{type:"number"}}},Ze={type:"array",items:{type:"object"}},Xe={type:"object"},Qe={type:"object",properties:{name:{examples:["InternalServerError"],type:"string",description:"The name of the error"},message:{examples:["Example"],type:"string",description:"an helping message"},code:{type:"number",description:"the status code of the error (can be different of the HTTP status code)"},type:{type:"string",description:"additional information for the error"},data:{type:"object"}},required:["name","message","code"]},et={description:"Server errors: 500, 501, 400, 404 and etc...",content:{"application/json":{schema:{allOf:[{$ref:"#/components/schemas/Error"},{examples:[{name:"InternalServerError",message:"Internal Server Error",code:500}]}]}}}},tt={description:"Need auth",content:{"application/json":{schema:{allOf:[{$ref:"#/components/schemas/Error"},{type:"object",examples:[{name:"UnAuthorizedError",message:"Unauthorized",code:401}]}]}}}},rt={description:"Fields invalid",content:{"application/json":{schema:{allOf:[{$ref:"#/components/schemas/Error"},{type:"object",examples:[{name:"MoleculerClientError",message:"Error message",code:422,data:[{name:"fieldName",message:"Field invalid"},{name:"arrayField[0].fieldName",message:"Whats wrong"},{name:"object.fieldName",message:"Whats wrong"}]}]}]}}}},nt={description:"",content:{"application/json":{schema:{oneOf:[{$ref:"#/components/schemas/DbMixinList"},{$ref:"#/components/schemas/DbMixinFindList"},{$ref:"#/components/schemas/Item"}]}}}},st={description:"File not exist",content:{"application/json":{schema:{allOf:[{$ref:"#/components/schemas/Error"},{type:"object",examples:[{name:"MoleculerClientError",message:"File missing in the request",code:400}]}]}}}},at={description:"File too big",content:{"application/json":{schema:{allOf:[{$ref:"#/components/schemas/Error"},{type:"object",examples:[{name:"PayloadTooLarge",message:"Payload too large",code:413,type:"PAYLOAD_TOO_LARGE",data:{fieldname:"file",filename:"4b2005c0b8.png",encoding:"7bit",mimetype:"image/png"}}]}]}}}},it={DbMixinList:Ke,DbMixinFindList:Ze,Item:Xe,Error:Qe},ot={ServerError:et,UnauthorizedError:tt,ValidationError:rt,ReturnedData:nt,FileNotExist:st,FileTooBig:at},re={schemas:it,responses:ot};var ne=T(require("path/posix"),1);var je=a=>{var t;return a.fullName?a.fullName:a.version!=null&&((t=a.settings)==null?void 0:t.$noVersionPrefix)!==!0?(typeof a.version=="number"?"v"+a.version:a.version)+"."+a.name:a.name},we=(a,t)=>{let e=[],r;for(;(r=a.exec(t))!==null;)r.index===a.lastIndex&&a.lastIndex++,e.push([...r.slice(1)]);return e},P=(a="")=>ne.default.resolve("/",ne.default.normalize(a)),Ve=a=>a===S||a===N||X(a),$e=a=>a===S||X(a);function se(a){return a?(t,e)=>{var r;return((r=t[a])==null?void 0:r.localeCompare(e[a],"en",{sensitivity:"base"}))??-1}:(t,e)=>t.localeCompare(e,"en",{sensitivity:"base"})}var Ce=T(require("path/posix"),1);var V=class{actionType;path;method;action;actionName;get fullPath(){return this.alias.fullPath}alias;constructor(t,e,r){this.alias=t,this.actionType=t.type,this.path=t.path,this.method=e,r&&this.setAction(r)}setAction(t){this.action=t}};var De=T(require("path/posix"),1);var R=class{fullPath;get path(){return this._path}set path(t){this._path=P(t)}get method(){return this._method}set method(t){if(!$e(t))throw new Error(`"${t}" is not a valid method`);this._method=t.toLowerCase()}route;type;_method="*";_path="";action;actionSchema;service;openapi;skipped=!1;busboyConfig;constructor(t,e){this.route=e,this.type=t.type,this.busboyConfig=t.busboyConfig,this.method=t.method??S,this.path=t.path??"/",this.fullPath=De.default.join((e==null?void 0:e.path)??"/",t.path??"/"),this.action=t.action,t.openapi===!1?this.skipped=!0:this.openapi=t.openapi}isJokerAlias(){return this.method===S}getMethods(){return(this.method===S?Z:[this.method])??[]}toJSON(){return{method:this.method,type:this.type,path:this.path,action:this.action,openapi:this.openapi}}getPaths(){return this.getMethods().map(t=>new V(this,t,this.actionSchema))}};var B=class{constructor(t,e,r={},n=!0){this.logger=t;this.route=e;this.aliases=r;this.skipUnresolvedActions=n}getAliases(){return Object.entries(this.aliases??{}).flatMap(([t,e])=>{let r=this.extractAliasInformation(t,e),n=this.getSubAliases(r??{}).map(s=>{let o=new R(s,this.route);return o.skipped=!0,o});return r?r.action&&!r.action.match(te)?(this.logger.error(`alias "${t}" from route "${this.route.path}" can't be added ton openapi . because the name "${r.action}" need to match pattern ${te.toString()}`),n):this.getSubAliases(r).map(s=>new R(s,this.route)):(this.logger.warn(`alias "${t}" from route "${this.route.path}" is skipped`),n)})}extractAliasSubInformations(t){if((r=>!!r&&["action","handler"].some(n=>!!r[n]))(t))return t;if(Array.isArray(t)){let r=t.reduce((n,s)=>!s||typeof s!="string"?n:s,void 0);return!r&&this.skipUnresolvedActions?void 0:{action:r}}else return typeof t!="string"?this.skipUnresolvedActions?void 0:{action:void 0}:{action:t}}extractAliasInformation(t,e){var s;let r=this.extractAliasSubInformations(e);if(!r)return;let n=t.split(/\s+/);if(n.length===1&&(r.path=r.path??n[0]),n.length>1&&(r.path=r.path??n[1],r.method=r.method??n[0]),!r.actionType&&((s=r.action)!=null&&s.includes(":"))){let[o,i]=r.action.split(":");r.type=o,r.action=i}if(r.method?r.method=r.method.toLowerCase():r.method=S,!Ve(r.method)){this.logger.warn(`"${r.method}" is not a valid http method`);return}return r}getSubAliases(t){if(t.method!==N)return[t];let e=t.action,r={list:{method:"get",action:`${e}.list`,path:`${t.path}`},get:{method:"get",action:`${e}.get`,path:`${t.path}/:id`},create:{method:"post",action:`${e}.create`,path:`${t.path}`},update:{method:"put",action:`${e}.update`,path:`${t.path}/:id`},patch:{method:"patch",action:`${e}.patch`,path:`${t.path}/:id`},remove:{method:"delete",action:`${e}.remove`,path:`${t.path}/:id`}};return Object.entries(r).filter(([n])=>(t.only?t.only.includes(n):!0)&&(t.except?!t.except.includes(n):!0)).map(([,n])=>({...t,...n}))}};var $=class a{constructor(t,e,r,n,s=!0){this.logger=t;this.skipUnresolvedActions=s;this.path=a.formatPath(e==null?void 0:e.path,r),this.bodyParsers=e.bodyParsers,this.busboyConfig=e.busboyConfig,this.autoAliases=e.autoAliases??!1,this.openapi=e.openapi,this.openApiService=n,this.apiService=r,this.aliases=new B(this.logger,this,e.aliases,this.skipUnresolvedActions).getAliases()}aliases;path;bodyParsers;autoAliases;openapi;openApiService;apiService;busboyConfig;static formatPath(t,e){var r;return P(Ce.default.join(((r=e==null?void 0:e.settings)==null?void 0:r.path)??"/",t??"/"))}searchAlias(t){return this.aliases.find(e=>{var r,n,s,o;return(e.method.toLowerCase()===S||((r=e.method)==null?void 0:r.toLowerCase())===((n=t.methods)==null?void 0:n.toLowerCase()))&&P((s=e.path)==null?void 0:s.toLowerCase())===P((o=t.path)==null?void 0:o.toLowerCase())})}};var q=class{constructor(t){this.logger=t;this.logger.debug("RoutesParser.constructor()")}async parse(t,e,r,n){var f;this.logger.debug("RoutesParser.parse()");let s=new Map,o=new Map;n.forEach(p=>Object.values(p.actions??{}).forEach(c=>{typeof c=="boolean"||typeof c=="function"||!c.name||s.set(c.name,{service:p,action:c})}));let i=je(e),l=((f=e.settings)==null?void 0:f.routes)||[];return Array.isArray(l)?(l.forEach(p=>{var d;let c=p.name??p.path;if(this.logger.debug(`RoutesParser.parse() - check route ${c}`),(p==null?void 0:p.openapi)===!1){this.logger.debug(`RoutesParser.parse() - skip route ${c} because openapi = false`);return}let h=new $(this.logger,p,e,(d=t.service)==null?void 0:d.schema,r);o.set(`${i}-${h.path}`,h)}),(await this.fetchAliasesForService(t,i)??[]).filter((p,c,h)=>c===h.findIndex(d=>d.fullPath===p.fullPath&&d.methods===p.methods)).flatMap(p=>{this.logger.debug(`RoutesParser.parse() - checking alias ${p.path} for path ${p.fullPath}`);let c=o.get(`${i}-${P(p.routePath)}`);if(!c){this.logger.debug(`RoutesParser.parse() - alias ${p.fullPath} is skipped because not linked to a route (can be normal if route use openapi = false)`);return}let h=c==null?void 0:c.searchAlias(p);if(!h){if(c&&!c.autoAliases){this.logger.error(`fail to get alias configuration for alias ${p.methods} "${p.fullPath}"`);return}this.logger.debug(`RoutesParser.parse() - alias ${p.fullPath} seems to use autoAliases`);let d=new R({path:p.path,method:p.methods,action:p.actionName??void 0,openapi:c==null?void 0:c.openapi},c);return p.fullPath&&(d.fullPath=p.fullPath),d}if(h.skipped){this.logger.debug(`RoutesParser.parse() - skip alias ${h.fullPath} because openapi = false`);return}return h}).filter(Boolean).map(p=>{if(!p.action)return p;let c=s.get(p.action);if(!c)return this.logger.warn(`fail to get details about action "${p.action}"`),r?void 0:p;if(c.action.openapi!==!1)return p.actionSchema=c.action,p.service=c.service,p}).filter(Boolean)):(this.logger.debug(`RoutesParser.parse() - service ${i} seems to not be a moleculer-web services`),[])}fetchAliasesForService(t,e){return t.call(`${e}.listAliases`,{withActionSchema:!1,grouping:!1})}};var Fe=a=>{let t=typeof a;if(["boolean","object","number","string","integer","array"].includes(t))return t},A=a=>typeof a.default=="function"?void 0:a.default;var G=class{constructor(t,e){this.validator=t;this.additionalMappersFn=e;this.mappers=pt(this.getMapperFn()),this.load()}mappers;getMapperFn(){return{getSchemaObjectFromSchema:(...t)=>this.getSchemaObjectFromSchema(...t),getSchemaObjectFromRule:(...t)=>this.getSchemaObjectFromRule(...t)}}_loadingPromise;async load(){if(this._loadingPromise)return this._loadingPromise;this._loadingPromise=new Promise(async(t,e)=>{var r;try{let n=this.getMapperFn();Object.entries(await((r=this.additionalMappersFn)==null?void 0:r.call(this,n.getSchemaObjectFromRule,n.getSchemaObjectFromSchema))??{}).forEach(([s,o])=>{this.mappers[s]=o}),t()}catch(n){e(n)}}),await this._loadingPromise}getValidationRules(t){return Object.fromEntries(Object.entries(t).filter(([e])=>!e.startsWith("$$")))}getMetas(t){return Object.fromEntries(Object.entries(t).filter(([e])=>e.startsWith("$$")))}getSchemaObjectFromSchema(t){return Object.fromEntries(Object.entries(this.getValidationRules(t)).map(([e,r])=>[e,this.getSchemaObjectFromRule(r,void 0,t)]).filter(Boolean))}getSchemaObjectFromRootSchema(t){if(t.$$root!==!0)throw new Error("this function only support $$root objects");return delete t.$$root,this.getSchemaObjectFromRule(t)}getSchemaObjectFromRule(t,e,r){var g,f,p;if(!this.validator||!((g=this.mappers)!=null&&g.string))throw new Error(`bad initialisation . validator ? ${!!this.validator} | string mapper ${!!((f=this.mappers)!=null&&f.string)}`);let n=typeof t=="object"?Array.isArray(t)?[...t]:{...t}:t,s=Array.isArray(n)||typeof n!="object"||!n.$$oa?[]:[{property:"description",extension:O.description},{property:"summary",extension:O.summary},{property:"deprecated",extension:O.deprecated}].map(({property:c,extension:h})=>{var d;return[h,(d=n.$$oa)==null?void 0:d[c]]}),o=(p=this.validator.getRuleFromSchema(n))==null?void 0:p.schema,i={...e,...o},m=(this.mappers[i.type]||this.mappers.string)(i,r);if(m)return i.optional&&(m[O.optional]=!0),s.forEach(([c,h])=>{m[c]=h}),m}},pt=({getSchemaObjectFromRule:a,getSchemaObjectFromSchema:t})=>({any:e=>{let r=A(e);return{default:r,examples:r?[r]:void 0}},array:e=>{let r=(e.items?a(e.items,{enum:e.enum}):void 0)??{},n=A(e),s={type:"array",examples:n?[n]:void 0,uniqueItems:e.unique,default:n,items:r};return e.length?(s.maxItems=e.length,s.minItems=e.length):(s.maxItems=e.max,s.minItems=e.min),s},boolean:e=>{let r=A(e);return{type:"boolean",default:r,examples:r!==void 0?[r]:[!0,!1]}},class:()=>{},currency:e=>{let r=A(e),n;if(e.customRegex)n=e.customRegex.toString();else{let s=e.currencySymbol??null,o=e.thousandSeparator??",",i=e.decimalSeparator??".",l=e.symbolOptional?"?":"",m=s?`\\${s}${l}`:"",g="(?=.*\\d)^(-?~1|~1-?)(([0-9]\\d{0,2}(~2\\d{3})*)|0)?(\\~3\\d{1,2})?$".replace(/~1/g,m).replace("~2",o).replace("~3",i);n=new RegExp(g).source}return{type:"string",pattern:n,default:r,examples:r?[r]:void 0,format:"currency"}},date:e=>{let r=A(e);if(!e.convert)return;let n=new Date((r==null?void 0:r.toString())??""),s=isNaN(n.getTime())?new Date:n,o=[s.toISOString(),s.getTime()];return{type:"string",default:r,format:"date-time",examples:o}},email:e=>{let r=A(e),n=/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,s=/^\S+@\S+\.\S+$/,o=e.mode=="precise"?n:s;return{type:"string",format:"email",default:r,pattern:new RegExp(o).source,maxLength:e.max,minLength:e.min,examples:[r??"foo@bar.com"]}},enum:e=>a({type:"string",enum:e.values}),equal:(e,r)=>{let n=A(e);return e.field&&(r!=null&&r[e.field])?a(r==null?void 0:r[e.field]):{type:e.strict?Fe(e.value):"string",default:n,examples:n?[n]:void 0,enum:e.value?[e.value]:void 0}},forbidden:()=>{},function:()=>{},luhn:e=>{let r=A(e);return{type:"string",default:r,pattern:"^(\\d{1,4} ){3}\\d{1,4}$",examples:r?[r]:void 0,format:"luhn"}},mac:e=>{let r=A(e),n=/^((([a-f0-9][a-f0-9]+-){5}|([a-f0-9][a-f0-9]+:){5})([a-f0-9][a-f0-9])$)|(^([a-f0-9][a-f0-9][a-f0-9][a-f0-9]+[.]){2}([a-f0-9][a-f0-9][a-f0-9][a-f0-9]))$/i;return{type:"string",default:r,pattern:new RegExp(n).source,examples:r?[r]:["01:C8:95:4B:65:FE","01C8.954B.65FE","01-C8-95-4B-65-FE"],format:"mac"}},multi:e=>{let r=A(e);return Array.isArray(e.rules)?{oneOf:e.rules.map(s=>a(s)).filter(Boolean),default:r,examples:r?[r]:void 0}:void 0},number:e=>{var o;let r=A(e),n=r??((o=e.enum)==null?void 0:o[0])??e.min??e.max,s={type:"number",default:r,examples:n?[n]:void 0};return e.positive&&(s.minimum=0),e.negative&&(s.maximum=0),e.max&&(s.maximum=e.max),e.min&&(s.minimum=e.min),e.equal&&(s.maximum=e.equal,s.minimum=e.equal),s},object:e=>{let r=A(e),n=e.props??e.properties,s=n?t(n):void 0;return{type:"object",minProperties:e.minProps,maxProperties:e.maxProps,default:r,properties:s,examples:r?[r]:void 0}},record:e=>{let r=A(e),n=e.value?a(e.value):void 0;return{type:"object",default:r,additionalProperties:n}},string:e=>{var i;let r=A(e),n={default:r,type:"string"};e.length?(n.maxLength=e.length,n.minLength=e.length):(n.maxLength=e.max,n.minLength=e.min);let s;e.pattern?n.pattern=new RegExp(e.pattern).source:e.contains?(n.pattern=`.*${e.contains}.*`,s=e.contains):e.numeric?(n.pattern="^[0-9]+$",n.format="numeric",s="12345"):e.alpha?(n.pattern="^[a-zA-Z]+$",n.format="alpha",s="abcdef"):e.alphanum?(n.pattern="^[a-zA-Z0-9]+$",n.format="alphanum",s="abc123"):e.alphadash?(n.pattern="^[a-zA-Z0-9_-]+$",n.format="alphadash",s="abc-123"):e.singleLine?(n.pattern="^[^\\r\\n]*$",n.format="single-line",s="abc 123"):e.hex?(n.pattern="^([0-9A-Fa-f]{2})+$",n.format="hex",s="48656c6c6f20576f726c64"):e.base64&&(n.pattern="^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$",n.format="byte",s="aGVsbG8gd29ybGQ="),n.enum=e.enum;let o=r??((i=e.enum)==null?void 0:i[0])??s;return o&&(n.examples=[o]),n},tuple:e=>{let r=A(e),n=a({type:"array",default:r,length:2});return e.items&&(n.items={oneOf:e.items.map(s=>a(s)).filter(Boolean)}),r&&(n.examples=[r]),n},url:e=>{let r=A(e);return{type:"string",format:"url",default:r,examples:[r??"https://foobar.com"]}},uuid:e=>{let r=A(e),n;switch(e.version){case 0:n="00000000-0000-0000-0000-000000000000";break;case 1:n="45745c60-7b1a-11e8-9c9c-2d42b21b1a3e";break;case 2:n="9a7b330a-a736-21e5-af7f-feaf819cdc9f";break;case 3:n="9125a8dc-52ee-365b-a5aa-81b0b3681cf6";break;case 4:default:n="10ba038e-48da-487b-96e8-8d3b99b6d18a";break;case 5:n="fdda765f-fc57-5604-a269-52a7df8164ec";break;case 6:n="a9030619-8514-6970-e0f9-81b9ceb08a5f";break}return{type:"string",format:"uuid",default:r,examples:r?[r]:[n]}},objectID:e=>{let r=A(e),n="507f1f77bcf86cd799439011";return{type:"string",format:"ObjectId",default:r,minLength:n.length,maxLength:n.length,examples:r?[r]:[n]}},custom:()=>{}});var W=class{static generateResponses(t,e){var s;let r=t.responses??{},n="200";if(t.response){let o={description:""};if(t.response.description===void 0)o.content={[e]:t.response};else{let i=t.response;o.description=i.description,o.headers=i.headers,o.links=i.links,n=((s=i.statusCode)==null?void 0:s.toString())??n,i.content&&(o.content={[i.type??e]:i.content})}r[n]=o}return r}static mergeObjects(t,e={}){if(!e)throw new Error("need an input object to apply merge");return Object.entries(e).forEach(([r,n])=>{if(n===!1){delete t[r];return}t[r]=n}),t}static mergeCommons(t,e=[]){return e.reduce((r,n)=>{let s=r??{components:{}};return s!=null&&s.components||(s.components={}),n&&Object.keys(n).forEach(o=>{let i=o;if(i==="components"){Object.keys(n.components??{}).forEach(l=>{var g;let m=l;s.components||(s.components={}),s.components[m]||(s.components[m]={}),this.mergeObjects(s.components[m],(g=n==null?void 0:n.components)==null?void 0:g[m])});return}if(i==="responses"){s!=null&&s[i]||(s[i]={}),this.mergeObjects(s[i],n==null?void 0:n[i]);return}if(i==="tags"){s.tags=(n.tags??[]).reduce((l=[],m)=>m===null?[]:typeof m!="string"?(m.name&&t.set(m.name,{...t.get(m.name)??{},...m}),l):(t.set(m,{...t.get(m)??{},name:m}),[...l,m]),s.tags);return}if(n[i]===!1&&typeof s[i]!="boolean"){delete s[i];return}s[i]=n[i]}),s},{})}static merge(t,e,r,n,s,o){var i,l,m,g,f,p;return[r==null?void 0:r.openapi,(i=s==null?void 0:s.settings)!=null&&i.addServiceNameToTags&&((l=r==null?void 0:r.service)!=null&&l.name)?{tags:[r.service.name]}:void 0,(g=(m=r==null?void 0:r.service)==null?void 0:m.settings)==null?void 0:g.openapi,n==null?void 0:n.openapi].reduce((c,h)=>{var d;return h&&(h.responses=this.generateResponses(h,((d=s==null?void 0:s.settings)==null?void 0:d.defaultResponseContentType)??w),c=this.mergeCommons(t,[c,h]),c.summary=h.summary??c.summary,c.security=h.security??c.security),c},this.mergeCommons(t,[(f=s==null?void 0:s.settings)==null?void 0:f.openapi,(p=o==null?void 0:o.settings)==null?void 0:p.openapi,e.openapi]))}};var Y=class{constructor(t,e,r,n){this.logger=t;this.converter=new G(e,n),this.document=r}components={schemas:{},responses:{},parameters:{},examples:{},requestBodies:{},headers:{},securitySchemes:{},links:{},callbacks:{},pathItems:{}};document;converter;isLoaded;async load(){await this.converter.load(),this.isLoaded=!0}generate(t,e){var o;this.isLoaded||this.logger.warn("generator : converter is not loaded, custom mapper can be not be enabled");let r=new Map;this.document.openapi&&(this.logger.warn("setting manually the openapi version is not supported"),delete this.document.openapi);let n={openapi:`${t}.0`,...this.document,servers:this.document.servers??[],tags:[],components:this.cleanComponents(this.document.components)};n.responses&&delete n.responses;let s=new Map;return e.sort(se("fullPath")),e.forEach(i=>{var c,h,d,b,F;n.paths||(n.paths={});let l=i.route,{apiService:m,openApiService:g}=l,f=this.formatParamUrl(P(i.fullPath)),p=((c=n.paths)==null?void 0:c[f])??{};i.isJokerAlias()&&(p.description=(d=(h=i.actionSchema)==null?void 0:h.openapi)==null?void 0:d.description,p.summary=(F=(b=i.actionSchema)==null?void 0:b.openapi)==null?void 0:F.summary),i.getPaths().forEach(M=>{var me,le,he,ue,de,fe,ge,Ae,Oe,ye,Se,be;let y=M.method,oe=`${f}.${y}`,E=p[y];if(E){if((E[O.server]||(me=E.servers)!=null&&me.length)&&((ue=(he=(le=i.route.apiService.settings)==null?void 0:le.openapi)==null?void 0:he.server)!=null&&ue.url)&&!((de=E.servers)!=null&&de.find(j=>{var x,Pe,Ee;return j.url===((Ee=(Pe=(x=i.route.apiService.settings)==null?void 0:x.openapi)==null?void 0:Pe.server)==null?void 0:Ee.url)}))){let j=i.route.apiService.settings.openapi.server;if(!((fe=E.servers)!=null&&fe.length)){E.servers=[];let x=E[O.server];x&&E.servers.push(x)}E.servers.push(j),this.addServerToDocument(n,j);return}let v=s.get(oe);this.logger.warn(`${y.toUpperCase()} ${f} is already register by action ${v??"<unamedAction>"} skip`);return}s.set(oe,(ge=M.action)==null?void 0:ge.name);let u=W.merge(r,l,i,M.action,g,m),{parameters:pe,requestBody:Ne}=this.extractParameters(y,f,i)??{};u!=null&&u.parameters&&pe.push(...u.parameters),this.components=this.mergeComponents(this.components,this.cleanComponents(u.components));let L={summary:i.isJokerAlias()||u==null?void 0:u.summary,description:i.isJokerAlias()||u==null?void 0:u.description,deprecated:u.deprecated,operationId:u==null?void 0:u.operationId,externalDocs:u==null?void 0:u.externalDocs,security:u==null?void 0:u.security,tags:this.handleTags(n,r,u==null?void 0:u.tags),parameters:pe,requestBody:Ne,responses:u==null?void 0:u.responses};if((Oe=(Ae=i.route.apiService.settings)==null?void 0:Ae.openapi)!=null&&Oe.server){let v=i.route.apiService.settings.openapi.server;L[O.server]=v,this.addServerToDocument(n,v)}let ce={summary:(u==null?void 0:u.summary)??"",action:i.action??Te,autoAlias:i.route.autoAliases?"[autoAlias]":""},D=(be=(Se=(ye=i.route)==null?void 0:ye.openApiService)==null?void 0:Se.settings)==null?void 0:be.summaryTemplate;(typeof D=="string"||D===void 0)&&(L.summary=Object.entries(ce).reduce((v,[j,x])=>v.replace(new RegExp(`{{${j}}}`,"g"),x??""),D??Ie).trim()),typeof D=="function"&&(L.summary=D(ce)),p[y]=L}),n.paths[f]=p}),(o=n.tags)==null||o.sort(se("name")),n.components=this.mergeComponents(n.components,this.components),this.removeExtensions(n)}addServerToDocument(t,e){t.servers||(t.servers=[]),t.servers.some(r=>r.url===e.url)||t.servers.push(e)}mergeComponents(t,e){return Object.keys(e).reduce((r,n)=>Object.keys(e==null?void 0:e[n]).length?{...r,[n]:{...t[n],...e[n]}}:r,{...t})}addQueryParameters(t,e,r,n){var o;if((o=e.openapi)!=null&&o.queryParameters)return e.openapi.queryParameters.map(i=>({...i,in:"query"}));let s=this.getParameters(r,n,!1);return Object.entries(s).forEach(([i,l])=>{let m=this.converter.getSchemaObjectFromRule(l);if(!m)return;let g=this.getComponent(m),f={name:i,in:"query",style:m.type==="object"?"deepObject":void 0,explode:m.type==="object"?!0:void 0,required:g[O.optional]!==!0||void 0,schema:m};if(!t.some(p=>p.name===i)){t.push(f);return}t=t.map(p=>p.name!==i?p:{...f,in:"path",required:!0})}),t}getRequestBody(t,e,r,n,s=[]){var l,m,g,f,p,c;if((l=t.openapi)!=null&&l.requestBody)return(m=t.openapi)==null?void 0:m.requestBody;if(!t.action)return;let o=(n==null?void 0:n.$$oa)??{},i=this.getParameters(e,r,!0);if(Object.keys(i).length>0){let h={...n,...i},d=this.createRequestBodyFromParams(t.action,h,s),b=Object.entries(((g=t.route)==null?void 0:g.bodyParsers)||{}).filter(([,y])=>!!y).flatMap(([y])=>H[y]??[]),F=(b!=null&&b.length?b:[(c=(p=(f=t.route)==null?void 0:f.openApiService)==null?void 0:p.settings)==null?void 0:c.defaultResponseContentType])??[w],M=!1;if(this.isReferenceObject(d)){let y=this.getComponentByRef(d.$ref);if(!y)throw new Error(`fail to get schema from path ${d.$ref}`);M=(y.required??[]).length>0}return{description:o.description,summary:o.summary,required:M,content:Object.fromEntries(F.map(y=>[y,{schema:d}]))}}}extractParameters(t,e,r){var f,p,c,h;let n=((f=r==null?void 0:r.actionSchema)==null?void 0:f.params)??{},s=this.converter.getMetas(n),o=["multipart","stream"].includes(r.type??""),i=(p=r.openapi)!=null&&p.pathParameters?r.openapi.pathParameters.map(d=>({...d,in:"path"})):this.extractParamsFromUrl(e),m={parameters:this.addQueryParameters(i,r,o?"get":t,n)},g=i.map(d=>d.name);return o?m.requestBody=(c=r.openapi)!=null&&c.requestBody?(h=r.openapi)==null?void 0:h.requestBody:this.generateFileUploadBody(r,g):m.requestBody=this.getRequestBody(r,t,n,s,g),m}getParameters(t,e,r){let n=ee.includes(t);return Object.fromEntries(Object.entries(this.converter.getValidationRules(e)).map(([s,o])=>{var m;let i=(m=o==null?void 0:o.$$oa)==null?void 0:m.in;if((i?i==="body":n)===r)return[s,o]}).filter(Boolean))}generateFileUploadBody(t,e){var o,i,l,m,g,f,p,c,h;let r=t.type?H[t.type]:H.multipart,n={},s={type:"string",format:"binary"};if(t.type==="stream")n.type=s.type,n.format=s.format;else{if(((i=(o=t.actionSchema)==null?void 0:o.params)==null?void 0:i.$$root)===!0)throw new Error("$$root parameters is not supported on multipart");let d=((m=(l=t.busboyConfig)==null?void 0:l.limits)==null?void 0:m.files)??((p=(f=(g=t==null?void 0:t.route)==null?void 0:g.busboyConfig)==null?void 0:f.limits)==null?void 0:p.files),b=((h=(c=t.route.openApiService)==null?void 0:c.settings)==null?void 0:h.multiPartFileFieldName)??k;n.allOf=[{type:"object",properties:{[b]:d===1?s:{type:"array",items:s,maxItems:d}},required:[b]}]}return{required:!0,content:{[r[0]]:{schema:n}}}}isReferenceObject(t){return!!(t!=null&&t.$ref)}getComponent(t){if(!this.isReferenceObject(t))return t;let e=this.getComponentByRef(t.$ref);if(!e)throw new Error(`fail to get component "${t.$ref}`);return e}getComponentByRef(t){let e=t.split("/").filter(r=>r!=="");if(!(e.length<4||e[0]!=="#"||e[1]!=="components"||!Object.keys(this.components).includes(e[2])))return e.slice(2).reduce((r,n)=>r&&r.hasOwnProperty(n)?r[n]:void 0,this.components)}createRequestBodyFromParams(t,e,r=[],n={}){if(e.$$root===!0)return this.converter.getSchemaObjectFromRootSchema(e);let s=this.converter.getSchemaObjectFromSchema(e),o=Object.fromEntries(Object.entries(s).filter(([i,l])=>!r.includes(i)&&l));return this._createSchemaComponentFromObject(t,o,n)}extractParamsFromUrl(t=""){return[...we(/{(\w+)}/g,t).flat()].map(e=>({name:e,in:"path",required:!0,schema:{type:"string"}}))}_createSchemaComponentFromObject(t,e,r={}){this.components.schemas||(this.components.schemas={});let n=[],s=Object.fromEntries(Object.entries(e).map(([o,i])=>{let l=`${t}.${o}`;return i[O.optional]!=!0&&n.push(o),[o,this._createSchemaPartFromRule(l,i)]}));return this.components.schemas[t]&&this.logger.warn(`Generator - schema ${t} already exist and will be overwrite`),this.components.schemas[t]={type:"object",properties:s,required:n.length>0?n:void 0,default:r.default},{$ref:`#/components/schemas/${t}`}}formatParamUrl(t=""){let e=t.indexOf("/:");if(e===-1)return t;let r=t.indexOf("/",++e);return r===-1?t.slice(0,e)+"{"+t.slice(++e)+"}":this.formatParamUrl(t.slice(0,e)+"{"+t.slice(++e,r)+"}"+t.slice(r))}_createSchemaPartFromRule(t,e){let r=this.extractSystemParams(e);if(e.description=r.description,e.title=r.summary,e.deprecated=r.deprecated,e.type=="object"&&e.properties)return{summary:e.title,deprecated:e.deprecated,description:e.description,...this._createSchemaComponentFromObject(t,e.properties,{default:e.default})};if(e.type==="array"&&e.items)return{...e,items:this._createSchemaPartFromRule(t,e.items)};if(Q.some(n=>e[n])){let n=0;Q.forEach(s=>{e[s]&&(e[s]=e[s].map(o=>{if(o.type!=="object")return o;let i=`${t}.${n++}`;return this._createSchemaPartFromRule(i,o)}))})}return e}extractSystemParams(t={}){return{optional:t==null?void 0:t[O.optional],description:t==null?void 0:t[O.description],summary:t==null?void 0:t[O.summary],deprecated:t==null?void 0:t[O.deprecated]}}removeExtensions(t){return Array.isArray(t)?t.map(e=>this.removeExtensions(e)):typeof t=="object"?(Object.values(O).forEach(e=>{delete t[e]}),Object.fromEntries(Object.entries(t).map(([e,r])=>[e,this.removeExtensions(r)]))):t}cleanComponents(t={}){return Object.fromEntries(Object.entries(t).map(([e,r])=>[e,Object.fromEntries(Object.entries(r).map(([n,s])=>s===!1?void 0:[n,s]).filter(Boolean))]))}handleTags(t,e,r=[]){let n=Array.from(new Set(r));return t.tags||(t.tags=[]),n.forEach(s=>{let o=e.get(s);!t.tags.some(({name:i})=>i===s)&&o&&t.tags.push(o)}),n}};var ct=Le.default.Errors.MoleculerError,ae={onlyLocal:!1,openapi:{info:{description:"",version:"0.0.1",title:"Api docs"},tags:[],paths:{},components:{schemas:re.schemas,securitySchemes:{},responses:re.responses},responses:{200:{$ref:"#/components/responses/ReturnedData"},401:{$ref:"#/components/responses/UnauthorizedError"},422:{$ref:"#/components/responses/ValidationError"},default:{$ref:"#/components/responses/ServerError"}}},cacheOpenApi:!0,skipUnresolvedActions:!0,cacheMode:"next-call",summaryTemplate:`{{summary}} ({{action}}) {{autoAlias}}`,returnAssetsAsStream:!0,defaultResponseContentType:w,multiPartFileFieldName:k,addServiceNameToTags:!1,UIOptions:{}},z=class{broker;settings;logger;validator;constructor(t,e){this.broker=t;let r=this.broker.validator;if(r.constructor.name!="FastestValidator"&&r.validator)throw new Error("only fastest validator is allowed");this.logger=this.broker.getLogger("moleculer-openapi-generator"),this.validator=r.validator,this.settings={...ae,...e}}fetchServicesWithActions(t,e=!0,r=this.settings.onlyLocal){return t.call("$node.services",{withActions:e,onlyLocal:r??!1})}async mapAliases(t,e){this.logger.debug("mapAliases()");let r=e.filter(s=>{var o;return(o=s==null?void 0:s.settings)==null?void 0:o.routes});if(this.logger.debug(`mapAliases() : ${(r==null?void 0:r.length)??0} moleculer-web services found`),!(r!=null&&r.length))throw new ct("fail to identify service hosting moleculer-web");let n=new q(this.logger);return(await Promise.all(r.map(async s=>await n.parse(t,s,this.settings.skipUnresolvedActions??!0,e)))).flat()}async getAliases(t){let e=await this.fetchServicesWithActions(t);return this.mapAliases(t,e)}async generateSchema(t,{filterAliasesFn:e,addMappers:r}){let n="3.1",s=await e(t,await this.getAliases(t)),o=new Y(this.logger,this.validator,JSON.parse(JSON.stringify(this.settings.openapi)),r);return await o.load(),o.generate(n,s)}};var Ue=T(require("moleculer"),1),J=T(require("fs"),1);var C=T(require("path/posix"),1),ie=Ue.default.Errors.MoleculerError,_={},K={name:"openapi",settings:ae,events:{async"$api.aliases.regenerated"(){let a="generateDocs",{cacheMode:t}=this.settings;if(t!=="timeout"&&this.broker.cacher&&this.actions[a]){let e=this.broker.cacher.getCacheKey(`${this.fullName}.${a}`,{},{},[]);await this.broker.cacher.clean(`${e}*`)}this.actions.regenerateOpenApiPaths().catch(e=>{this.logger.error(`regenerateOpenApiPaths failed with error : ${e.toString()}`)}),t==="refresh"&&await this.actions[a]()}},actions:{generateDocs:{rest:{path:"/openapi.json",method:"GET"},cache:{enabled(){return this.settings.cacheOpenApi??!0},keygen:(a,t)=>t.version?`${a}|${(t==null?void 0:t.version)||xe}`:a,ttl:600},openapi:{tags:["OpenApi"]},handler(a){return this.getGenerator().generateSchema(a,{filterAliasesFn:this.filterAliases,addMappers:this.addMappers})}},assets:{rest:{path:"/assets/:file",method:"GET"},openapi:{summary:"OpenAPI assets",description:"Return files from swagger-ui-dist folder",tags:["OpenApi"]},params:{file:{type:"enum",values:["swagger-ui.css","swagger-ui.css.map","swagger-ui-bundle.js","swagger-ui-bundle.js.map","swagger-ui-standalone-preset.js","swagger-ui-standalone-preset.js.map"]}},async handler(a){let{file:t}=a.params;t.indexOf(".css")>-1?a.meta.$responseType="text/css":t.indexOf(".js")>-1?a.meta.$responseType="text/javascript":a.meta.$responseType="application/octet-stream";let e=`${await this.getSwaggerPath()}/${t}`;return this.settings.returnAssetsAsStream?J.default.createReadStream(e):J.default.promises.readFile(e)}},ui:{rest:{path:"/ui",method:"GET"},openapi:{summary:"OpenAPI ui",description:"You can provide any schema file in query param",tags:["OpenApi"]},params:{url:{$$oa:{summary:"Schema file"},type:"string",optional:!0}},async handler(a){a.meta.$responseType="text/html; charset=utf-8";let t=await this.getOpenApiPaths(),e=t.assetsPath,r={swaggerSettings:{deepLinking:!0,showExtensions:!0,layout:"StandaloneLayout",...this.settings.UIOptions,url:a.params.url||t.schemaPath,dom_id:"#swagger-ui",oauth2RedirectUrl:t.oauth2RedirectPath},oauth:this.settings.UIOauthOptions};return`<html lang="en"><head><title>OpenAPI UI</title><style>body{ margin: 0;} </style></head><body><div id="swagger-ui"><p>Loading...</p><noscript>If you see json, you need to update your dependencies</noscript></div><script type="application/json" id="__SWAGGER_SETTINGS__">${JSON.stringify(r)} </script><script>var assetsURL="${e}"; var configElement=document.getElementById("__SWAGGER_SETTINGS__"); if (!configElement){ throw new Error("fail to load configurations");} var settings=JSON.parse(configElement.textContent); window.onload=function (){ var cssLink=document.createElement("link"); cssLink.rel="stylesheet"; cssLink.href=assetsURL + "/swagger-ui.css"; document.head.appendChild(cssLink); function initSwaggerUIDependentCode(){ var ui=SwaggerUIBundle( Object.assign(settings.swaggerSettings,{ presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset], plugins: [SwaggerUIBundle.plugins.DownloadUrl],}) ); if(settings.oauth){ ui.initOAuth(settings.oauth)}} var scripts=[assetsURL + "/swagger-ui-bundle.js", assetsURL + "/swagger-ui-standalone-preset.js"]; var scriptsLoaded=0; function loadScript(script, callback){ var scriptElement=document.createElement("script"); scriptElement.src=script; scriptElement.onload=()=>{ scriptsLoaded++; if (scriptsLoaded===scripts.length){ callback();}}; document.body.appendChild(scriptElement);} for (var i=0; i < scripts.length; i++){ loadScript(scripts[i], initSwaggerUIDependentCode);}}; </script></body></html>`}},oauth2Redirect:{rest:{path:"/oauth2-redirect",method:"GET"},openapi:{summary:"OpenAPI OAuth2 redirect",description:"This fill will handle the OAuth2",tags:["OpenApi"]},cache:!1,async handler(a){if(!this)throw new ie("unknown error");return a.meta.$responseType="text/html; charset=utf-8",J.default.promises.readFile(`${await(this==null?void 0:this.getSwaggerPath())}/oauth2-redirect.html`)}},regenerateOpenApiPaths:{visibility:"private",throttle:1e4,async handler(a){(await this.getGenerator().getAliases(a)).filter(e=>{var r;return((r=e.service)==null?void 0:r.name)===this.name}).forEach(e=>{var r;e.action===`${this.name}.ui`&&(_.uiPath=e.fullPath),e.action===`${this.name}.assets`&&(_.assetsPath=(r=e.fullPath)==null?void 0:r.replace("/:file","")),e.action===`${this.name}.oauth2Redirect`&&(_.oauth2RedirectPath=e.fullPath),e.action===`${this.name}.generateDocs`&&(_.schemaPath=e.fullPath)}),this.getOpenApiPaths()}}},methods:{getOpenApiPaths(){var t,e,r,n;this.settings.schemaPath&&this.logger.warn("settings.schemaPath is deprecated, use settings.openApiPaths.schemaPath instead"),this.settings.assetsPath&&this.logger.warn("settings.assetsPath is deprecated, use settings.openApiPaths.assetsPath instead"),typeof this.settings.openApiPaths=="string"&&(this.settings.openApiPaths={schemaPath:C.default.join(this.settings.openApiPaths,"openapi.json"),uiPath:C.default.join(this.settings.openApiPaths,"ui"),oauth2RedirectPath:C.default.join(this.settings.openApiPaths,"oauth2-redirect"),assetsPath:C.default.join(this.settings.openApiPaths,"assets")});let a={assetsPath:this.settings.assetsPath??((t=this.settings.openApiPaths)==null?void 0:t.assetsPath)??_.assetsPath??Me,schemaPath:this.settings.schemaPath??((e=this.settings.openApiPaths)==null?void 0:e.schemaPath)??_.schemaPath,uiPath:((r=this.settings.openApiPaths)==null?void 0:r.uiPath)??_.uiPath,oauth2RedirectPath:((n=this.settings.openApiPaths)==null?void 0:n.oauth2RedirectPath)??_.oauth2RedirectPath};return["assetsPath","schemaPath","uiPath","oauth2RedirectPath"].forEach(s=>{if(!a[s])throw new ie(`fail to get path for settings ${s}`)}),a},getSwaggerPath:async()=>{try{return(await import("swagger-ui-dist")).getAbsoluteFSPath()}catch{throw new ie("fail to load swagger ui")}},getGenerator(){if(!this.generator)throw new Error("no generator, bad initialization");return this.generator},filterAliases:(a,t)=>t,addMappers:(a,t)=>({})},created(){this.generator=new z(this.broker,this.settings)},async started(){this.logger.info("\u{1F4DC} OpenAPI Docs server is available")}};var mt=K;var lt=K;0&&(module.exports={Alias,ECacheMode,HTTP_METHODS,JOKER_METHOD,OPENAPI_VERSIONS_SUPPORTED,OpenApiMixin,PathAction,Route,mixin});