UNPKG

zod-sockets

Version:

Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers

16 lines (14 loc) 23.4 kB
import"node:http";import*as e from"ramda";import{globalRegistry as t,z as n}from"zod";import r from"node:assert/strict";import{bgHex as i,hex as a,italic as o}from"ansis";import s from"yaml";const c=e.tryCatch((e,t)=>typeof n.parse(e,t),e.always(void 0)),l=e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase(),u=e=>e.charAt(0).toLowerCase()+e.slice(1),d=(...e)=>e.flatMap(e=>e.split(/[^A-Z0-9]/gi)).flatMap(e=>e.replaceAll(/[A-Z]+/g,e=>`/${e}`).split(`/`)).map(l).join(``),f=e=>e instanceof Error?e:e instanceof n.ZodError?new n.ZodRealError(e.issues):Error(String(e)),p=e=>e instanceof n.ZodError?e.issues.map(({path:e,message:t})=>`${e.length?`${n.core.toDotPath(e)}: `:``}${t}`).join(`; `):e.message,m=(t,n)=>h(t)&&`_zod`in t&&(n?e.path([`_zod`,`def`,`type`],t)===n:!0),h=e=>typeof e==`object`&&!!e;var g=class extends Error{name=`IOSchemaError`},_=class extends g{cause;name=`InputValidationError`;constructor(e){super(p(e),{cause:e}),this.cause=e}},v=class extends g{cause;name=`OutputValidationError`;constructor(e){let t=new n.ZodError(e.issues.map(({path:e,...t})=>({...t,path:[`output`,...e]})));super(p(t),{cause:e}),this.cause=e}};const y=e=>{let t=e.trim();return t.startsWith(`/`)?t:`/${t}`};var b=class{},ee=class extends b{#e;#t;#n;#r;#i;constructor(e){super(),this.#e=e.event,this.#t=e.ns||`/`,this.#n=e.input,this.#r=`output`in e?e.output:void 0,this.#i=e.handler}get event(){return this.#e}get namespace(){return this.#t}get inputSchema(){return this.#n}get outputSchema(){return this.#r}#a(t){let r=this.#r?e.init(t):t;try{return this.#n.parse(r)}catch(e){throw e instanceof n.ZodError?new _(e):e}}#o(t){if(!this.#r)return;let r=n.function({input:this.#r,output:n.void()});try{return r.parse(e.last(t))}catch(e){if(!(e instanceof n.ZodError))throw e;let r=[Math.max(0,t.length-1)],i=e.issues.map(e=>({...e,path:r}));throw new _(new n.ZodRealError(i))}}#s(e){if(this.#r)try{return this.#r.parse(e)}catch(e){throw e instanceof n.ZodError?new v(e):e}}async execute({params:e,logger:t,...n}){let r=this.#a(e);t.debug(`${this.#e}: parsed input (${this.#r?`excl.`:`no`} ack)`,r);let i=this.#o(e),a=await this.#i({input:r,logger:t,...n}),o=this.#s(a);i&&o&&(t.debug(`${this.#e}: parsed output`,o),i(...o))}},x=class e{timeout;startupLogo;security;namespaces;constructor({timeout:e=2e3,startupLogo:t=!0,namespaces:n={},security:r=[]}={}){this.timeout=e,this.startupLogo=t,this.namespaces=n,this.security=r}addNamespace({path:t=`/`,emission:r={},metadata:i=n.object({}),hooks:a={},security:o=[]}){let{namespaces:s,...c}=this,l={emission:r,hooks:a,metadata:i,security:o};return new e({...c,namespaces:{...s,[t]:l}})}};const te=({startupLogo:e,timeout:t,security:n,emission:r,hooks:i,metadata:a}={})=>new x({startupLogo:e,timeout:t,security:n}).addNamespace({emission:r,metadata:a,hooks:i}),S=e=>({join:async t=>e.join(t),leave:async t=>typeof t==`string`?e.leave(t):Promise.all(t.map(t=>e.leave(t))).then(()=>{})}),C=({sockets:e,...t})=>e.map(e=>({id:e.id,handshake:e.handshake,rooms:Array.from(e.rooms),getData:()=>e.data||{},emit:w({subject:e,...t}),...S(e)}));function w({subject:e,emission:t,timeout:n}){return async(i,...a)=>{let o=`id`in e;r(i in t,Error(`Unsupported event ${i}`));let{schema:s,ack:c}=t[i],l=s.parse(a);if(!c)return e.emit(String(i),...l)||!0;let u=await e.timeout(n).emitWithAck(String(i),...l);return(o?c:c.array()).parse(u)}}const T=({subject:e,...t})=>n=>({getClients:async()=>C({sockets:await e.in(n).fetchSockets(),...t}),broadcast:w({...t,subject:e.to(n)})}),ne={onConnection:({client:{id:e,getData:t},logger:n})=>n.debug(`Client connected`,{...t(),id:e}),onDisconnect:({client:{id:e,getData:t},logger:n,reason:r})=>n.debug(`Client disconnected`,{...t(),id:e,reason:r}),onAnyIncoming:({event:e,client:{id:t,getData:n},logger:r})=>r.debug(`${e} from ${t}`,n()),onAnyOutgoing:({event:e,logger:t,payload:n})=>t.debug(`Sending ${e}`,n),onStartup:({logger:e})=>e.debug(`Ready`),onError:({logger:e,event:t,error:n})=>e.error(t?`${t} handling error`:`Error`,n)},re=` ,, MMM"""AMV `7MM .M"""bgd `7MM mm M’ AMV MM ,MI "Y MM MM ` AMV ,pW"Wq. ,M""bMM `MMb. ,pW"Wq. ,p6"bo MM ,MP’ .gP"Ya mmMMmm ,pP"Ybd AMV 6W’ `Wb ,AP MM `YMMNq. 6W’ `Wb 6M’ OO MM ;Y ,M’ Yb MM 8I `" AMV , 8M M8 8MI MM . `MM 8M M8 8M MM;Mm 8M"""""" MM `YMMMa. AMV ,M YA. ,A9 `Mb MM Mb dM YA. ,A9 YM. , MM `Mb. YM. , MM L. I8 AMVmmmmMM `Ybmd9’ `Wbmd"MML. P"Ybmmd" `Ybmd9’ YMbmd’ .JMML. YA. `Mbmmd’ `Mbmo M9mmmP’ ${o(`for Jennie`.padEnd(40))}${`Proudly supports non-binary community.`.padStart(57)} `,E=e.cond([[e.gt(3),e.always(a(`#FCF434`))],[e.gt(5),e.always(a(`#FFF`))],[e.gt(8),e.always(a(`#9C59D1`))],[e.T,e.always(i(`#383838`).hex(`#888`))]]),D=()=>re.split(` `).slice(1).map((e,t)=>E(t)(e.padEnd(97))).join(` `),O=async({io:e,actions:t,target:n,config:{namespaces:r,timeout:i,startupLogo:a=!0},logger:o=console})=>{for(let n in r){let a=e.of(y(n)),{emission:s,hooks:c,metadata:l}=r[n],{onConnection:u,onDisconnect:d,onAnyIncoming:p,onAnyOutgoing:m,onStartup:h,onError:g}={...ne,...c},_={emission:s,timeout:i},v={logger:o,withRooms:T({subject:e,metadata:l,..._}),all:{getClients:async()=>C({sockets:await a.fetchSockets(),metadata:l,..._}),getRooms:()=>Array.from(a.adapter.rooms.keys()),broadcast:w({subject:e,..._})}};a.on(`connection`,async e=>{let r={emit:w({subject:e,..._}),broadcast:w({subject:e.broadcast,..._}),id:e.id,handshake:e.handshake,getRequest:()=>e.request,isConnected:()=>e.connected,getRooms:()=>Array.from(e.rooms),getData:()=>e.data||{},setData:t=>{l.parse(t),e.data=t},...S(e)},i={...v,client:r,withRooms:T({subject:a,metadata:l,..._})};await u(i),e.onAny((e,...t)=>p({event:e,payload:t,...i})),e.onAnyOutgoing((e,...t)=>m({event:e,payload:t,...i}));for(let r of t)if(r.namespace===n){let{event:t}=r;e.on(t,async(...e)=>{try{return await r.execute({params:e,...i})}catch(n){return g({...i,event:t,payload:e,error:f(n)})}})}e.on(`disconnect`,e=>d({...i,reason:e}))}),await h(v)}return(a?console.log:()=>{})(D()),o.debug(`Running`,`v6.0.0`),o.info(`Listening`,n.address()),e.attach(n)};var ie=class{config;constructor(e){this.config=e}build(e){return new ee(e)}};const k=(...e)=>e,A=(r,i,a=3)=>{if(!i)return n.function({input:r,output:n.void()});let o=n.function({input:i,output:n.void()}),s=r._zod.def.rest;if(!s||a<=0)return n.function({input:n.tuple(k(...r._zod.def.items,o)),output:n.void()});let c=t.get(s)?.description,l=e.range(0,a).map(i=>{let a=[...r._zod.def.items].concat(e.range(1,i+1).map(e=>{let r=n.clone(s);return t.add(r,{description:`${c||`rest`}${e}`}),r}),o);return n.function({input:n.tuple(k(...a)),output:n.void()})});return n.union(l)},ae=(t,{io:r})=>{let i=[n.toJSONSchema(t,{io:r,unrepresentable:`any`,override:({jsonSchema:e})=>{typeof e.default==`bigint`&&delete e.default}})];for(;i.length;){let t=i.shift();if(e.is(Object,t)){if(t.$ref===`#`)return!0;i.push(...e.values(t))}e.is(Array,t)&&i.push(...e.values(t))}return!1},j=(e,{onEach:t,rules:n,onMissing:r,ctx:i={}})=>{let a=n[e._zod.def.type],o=e=>j(e,{ctx:i,onEach:t,rules:n,onMissing:r}),s=a?a(e,{...i,next:o}):r(e,i),c=t&&t(e,{prev:s,...i});return c?{...s,...c}:s};var oe=class t{ts;f;exportModifier;#e;static#t=/^[A-Za-z_$][A-Za-z0-9_$]*$/;constructor(e){this.ts=e,this.f=this.ts.factory,this.exportModifier=[this.f.createModifier(this.ts.SyntaxKind.ExportKeyword)],this.#e=[this.ts.SyntaxKind.AnyKeyword,this.ts.SyntaxKind.BigIntKeyword,this.ts.SyntaxKind.BooleanKeyword,this.ts.SyntaxKind.NeverKeyword,this.ts.SyntaxKind.NumberKeyword,this.ts.SyntaxKind.ObjectKeyword,this.ts.SyntaxKind.StringKeyword,this.ts.SyntaxKind.SymbolKeyword,this.ts.SyntaxKind.UndefinedKeyword,this.ts.SyntaxKind.UnknownKeyword,this.ts.SyntaxKind.VoidKeyword]}addJsDoc=(e,t)=>this.ts.addSyntheticLeadingComment(e,this.ts.SyntaxKind.MultiLineCommentTrivia,`* ${t} `,!0);printNode=(e,t)=>{let n=this.ts.createSourceFile(`print.ts`,``,this.ts.ScriptTarget.Latest,!1,this.ts.ScriptKind.TS);return this.ts.createPrinter(t).printNode(this.ts.EmitHint.Unspecified,e,n)};makeId=e=>this.f.createIdentifier(e);makePropertyIdentifier=e=>typeof e==`string`&&t.#t.test(e)?this.makeId(e):this.literally(e);ensureTypeNode=(t,n)=>typeof t==`number`?this.f.createKeywordTypeNode(t):typeof t==`string`||this.ts.isIdentifier(t)?this.f.createTypeReferenceNode(t,n&&e.map(this.ensureTypeNode,n)):t;makeUnion=e=>{let t=new Map;for(let n of e)t.set(this.isPrimitive(n)?n.kind:n,n);return this.f.createUnionTypeNode(Array.from(t.values()))};makeInterfaceProp=(t,n,{isOptional:r,hasUndefined:i=r,isDeprecated:a,comment:o}={})=>{let s=this.ensureTypeNode(n),c=this.f.createPropertySignature(void 0,this.makePropertyIdentifier(t),r?this.f.createToken(this.ts.SyntaxKind.QuestionToken):void 0,i?this.makeUnion([s,this.ensureTypeNode(this.ts.SyntaxKind.UndefinedKeyword)]):s),l=e.reject(e.isNil,[a?`@deprecated`:void 0,o]);return l.length?this.addJsDoc(c,l.join(` `)):c};makeConst=(e,t,{type:n,expose:r}={})=>this.f.createVariableStatement(r&&this.exportModifier,this.f.createVariableDeclarationList([this.f.createVariableDeclaration(e,void 0,n?this.ensureTypeNode(n):void 0,t)],this.ts.NodeFlags.Const));makeType=(e,t,{expose:n,comment:r,params:i}={})=>{let a=this.f.createTypeAliasDeclaration(n?this.exportModifier:void 0,e,i&&this.makeTypeParams(i),t);return r?this.addJsDoc(a,r):a};makeInterface=(e,t,{expose:n,comment:r}={})=>{let i=this.f.createInterfaceDeclaration(n?this.exportModifier:void 0,e,void 0,void 0,t);return r?this.addJsDoc(i,r):i};makeTypeParams=t=>(Array.isArray(t)?t.map(t=>e.pair(t,void 0)):Object.entries(t)).map(([e,t])=>{let{type:n,init:r}=typeof t==`object`&&`init`in t?t:{type:t};return this.f.createTypeParameterDeclaration([],e,n?this.ensureTypeNode(n):void 0,r?this.ensureTypeNode(r):void 0)});literally=e=>typeof e==`number`?this.f.createNumericLiteral(e):typeof e==`bigint`?this.f.createBigIntLiteral(e.toString()):typeof e==`boolean`?e?this.f.createTrue():this.f.createFalse():e===null?this.f.createNull():this.f.createStringLiteral(e);makeLiteralType=e=>this.f.createLiteralTypeNode(this.literally(e));isPrimitive=e=>this.#e.includes(e.kind)};const M={name:e.path([`name`,`text`]),type:e.path([`type`]),optional:e.path([`questionToken`])},se=({_zod:{def:e}},{api:t})=>{let n=e.values.map(e=>e===void 0?t.ensureTypeNode(t.ts.SyntaxKind.UndefinedKeyword):t.makeLiteralType(e));return n.length===1?n[0]:t.makeUnion(n)},ce=({_zod:{def:e}},{next:t,api:n})=>{let r=[...e.parts],i=()=>{let e=``;for(;r.length;){let t=r.shift();if(m(t)){r.unshift(t);break}e+=t??``}return e},a=n.f.createTemplateHead(i()),o=[];for(;r.length;){let e=t(r.shift()),a=i(),s=r.length?n.f.createTemplateMiddle:n.f.createTemplateTail;o.push(n.f.createTemplateLiteralTypeSpan(e,s(a)))}return o.length?n.f.createTemplateLiteralType(a,o):n.makeLiteralType(a.text)},le=(e,{isResponse:r,next:i,makeAlias:a,api:o})=>{let s=()=>{let a=Object.entries(e._zod.def.shape).map(([e,a])=>{let{description:s,deprecated:c}=t.get(a)||{},l=(r?a._zod.optout:a._zod.optin)===`optional`,u=l&&!(a instanceof n.core.$ZodExactOptional);return o.makeInterfaceProp(e,i(a),{comment:s,isDeprecated:c,isOptional:l,hasUndefined:u})});return o.f.createTypeLiteralNode(a)};return ae(e,{io:r?`output`:`input`})?a(e,s):s()},ue=({_zod:{def:e}},{next:t,api:n})=>n.f.createArrayTypeNode(t(e.element)),N=({_zod:{def:t}},{api:n})=>n.makeUnion(e.map(n.makeLiteralType,Object.values(t.entries))),P=({_zod:{def:e}},{next:t,api:n})=>n.makeUnion(e.options.map(t)),F=({_zod:{def:e}},{next:t,api:n})=>n.makeUnion([t(e.innerType),n.makeLiteralType(null)]),I=({_zod:{def:e}},{next:t,api:n})=>n.f.createTupleTypeNode(e.items.map(t).concat(e.rest===null?[]:n.f.createRestTypeNode(t(e.rest)))),L=({_zod:{def:e}},{next:t,api:n})=>{let[r,i]=[e.keyType,e.valueType].map(t),a=n.ensureTypeNode(`Record`,[r,i]);return e.mode===`loose`?n.f.createIntersectionTypeNode([a,n.ensureTypeNode(`Record`,[`PropertyKey`,i])]):a},R=e.tryCatch((t,n)=>{if(!n.every(t.ts.isTypeLiteralNode))throw Error(`Not objects`);let r=e.chain(e.prop(`members`),n),i=e.uniqWith((...t)=>{if(!e.eqBy(M.name,...t))return!1;if(e.both(e.eqBy(M.type),e.eqBy(M.optional))(...t))return!0;throw Error(`Has conflicting prop`)},r);return t.f.createTypeLiteralNode(i)},(e,t,n)=>t.f.createIntersectionTypeNode(n)),z=({_zod:{def:e}},{next:t,api:n})=>R(n,[e.left,e.right].map(t)),B=e=>({},{api:t})=>t.ensureTypeNode(t.ts.SyntaxKind[e]),V=({_zod:{def:e}},{next:t})=>t(e.innerType),H=(e,t)=>e.ensureTypeNode(t?e.ts.SyntaxKind.UnknownKeyword:e.ts.SyntaxKind.AnyKeyword),U={string:B(`StringKeyword`),number:B(`NumberKeyword`),bigint:B(`BigIntKeyword`),boolean:B(`BooleanKeyword`),any:B(`AnyKeyword`),undefined:B(`UndefinedKeyword`),never:B(`NeverKeyword`),void:B(`VoidKeyword`),unknown:B(`UnknownKeyword`),null:({},{api:e})=>e.makeLiteralType(null),array:ue,tuple:I,record:L,object:le,literal:se,template_literal:ce,intersection:z,union:P,default:V,enum:N,optional:V,nonoptional:V,nullable:F,catch:V,pipe:({_zod:{def:e}},{next:t,isResponse:n,api:r})=>{let i=e[n?`out`:`in`],a=e[n?`in`:`out`];if(!m(i,`transform`))return t(i);let o=t(a),s={[r.ts.SyntaxKind.AnyKeyword]:``,[r.ts.SyntaxKind.BigIntKeyword]:BigInt(0),[r.ts.SyntaxKind.BooleanKeyword]:!1,[r.ts.SyntaxKind.NumberKeyword]:0,[r.ts.SyntaxKind.ObjectKeyword]:{},[r.ts.SyntaxKind.StringKeyword]:``,[r.ts.SyntaxKind.UndefinedKeyword]:void 0}[o.kind],l=c(i,m(a,`date`)?new Date:s),u={number:r.ts.SyntaxKind.NumberKeyword,bigint:r.ts.SyntaxKind.BigIntKeyword,boolean:r.ts.SyntaxKind.BooleanKeyword,string:r.ts.SyntaxKind.StringKeyword,undefined:r.ts.SyntaxKind.UndefinedKeyword,object:r.ts.SyntaxKind.ObjectKeyword};return r.ensureTypeNode(l&&u[l]||H(r,n))},lazy:({_zod:{def:e}},{makeAlias:t,next:n})=>t(e.getter,()=>n(e.getter())),readonly:V,function:(e,{next:r,api:i})=>{let{input:a,output:o}=e._zod.def;if(!m(a,`tuple`))throw Error(`z.function()::input must be a tuple`);let s=a._zod.def.items.map((e,n)=>{let{description:a}=t.get(e)||{};return i.f.createParameterDeclaration(void 0,void 0,i.f.createIdentifier(a?u(d(a)):`${m(e,`function`)?`cb`:`p`}${n+1}`),void 0,r(e))}),{rest:c}=a._zod.def;if(c){let{description:e}=t.get(c)||{};s.push(i.f.createParameterDeclaration(void 0,i.f.createToken(i.ts.SyntaxKind.DotDotDotToken),i.f.createIdentifier(e?u(d(e)):`rest`),void 0,r(n.array(c))))}return i.f.createFunctionTypeNode(void 0,s,r(o))}},W=(e,t)=>j(e,{rules:U,onMissing:({},{isResponse:e,api:t})=>H(t,e),ctx:t}),G=[`emission`,`actions`];var de=class e{api;#e=[];#t={};#n={path:`path`,socket:`Socket`,socketBase:`SocketBase`,ioClient:`socket.io-client`,emission:d(G[0]),actions:d(G[1])};registry={};#r(e,t,n){let r=this.#t[e].get(t)?.name?.text;if(!r){r=`Type${this.#t[e].size+1}`;let i=this.api.makeLiteralType(null);this.#t[e].set(t,this.api.makeType(r,i)),this.#t[e].set(t,this.api.makeType(r,n()))}return this.api.ensureTypeNode(r)}constructor({typescript:e,config:{namespaces:t},actions:n,maxOverloads:r=3}){this.api=new oe(e),this.#e.push(this.api.f.createImportDeclaration(void 0,this.api.f.createImportClause(this.api.ts.SyntaxKind.TypeKeyword,void 0,this.api.f.createNamedImports([this.api.f.createImportSpecifier(!1,this.api.f.createIdentifier(this.#n.socket),this.api.f.createIdentifier(this.#n.socketBase))])),this.api.f.createStringLiteral(this.#n.ioClient)));for(let[e,{emission:i}]of Object.entries(t)){this.#t[e]=new Map,this.registry[e]={emission:[],actions:[]};let t={makeAlias:this.#r.bind(this,e),api:this.api};for(let[n,{schema:a,ack:o}]of Object.entries(i)){let i=W(A(a,o,r),{isResponse:!0,...t});this.registry[e].emission.push({event:n,node:i})}for(let i of n)if(i.namespace===e){let{event:n,inputSchema:a,outputSchema:o}=i,s=W(A(a,o,r),{isResponse:!1,...t});this.registry[e].actions.push({event:n,node:s})}}for(let e in this.registry){let t=d(e)||d(`root`),n=this.api.makeConst(this.#n.path,this.api.f.createStringLiteral(y(e)),{expose:!0});this.api.addJsDoc(n,`@desc The actual path of the ${t} namespace`);let r=Object.entries(this.registry[e]).map(([e,t])=>this.api.makeInterface(d(e),t.map(({event:e,node:t})=>this.api.makeInterfaceProp(e,t)),{expose:!0})),i=this.api.makeType(this.#n.socket,this.api.ensureTypeNode(this.#n.socketBase,[this.#n.emission,this.#n.actions]),{expose:!0});this.api.addJsDoc(i,`@example const socket: ${t}.${this.#n.socket} = io(${t}.${this.#n.path})`),this.#e.push(this.api.f.createModuleDeclaration(this.api.exportModifier,this.api.f.createIdentifier(t),this.api.f.createModuleBlock([n,...this.#t[e].values(),...r,i]),this.api.ts.NodeFlags.Namespace))}}static async create(t){return new e({...t,typescript:(await import(`typescript`)).default})}print(e){return this.#e.map(t=>this.api.printNode(t,e)).join(` `)}},fe=class{document;constructor(e){this.document={asyncapi:`3.0.0`,...e,servers:{},channels:{},components:{}}}addServer(e,t){return this.document.servers={...this.document.servers,[e]:t},this}addChannel(e,t){return this.document.channels={...this.document.channels,[e]:t},this}addOperation(e,t){return this.document.operations={...this.document.operations,[e]:t},this}addSecurityScheme(e,t){return this.document.components={...this.document.components,securitySchemes:{...this.document.components?.securitySchemes,[e]:t}},this}addSchema(e,t){return this.document.components={...this.document.components,schemas:{...this.document.components?.schemas,[e]:t}},this}getSpec(){return this.document}getSpecAsJson(e,t){return JSON.stringify(this.document,e,t)}getSpecAsYaml(){return s.stringify(this.document)}};function K(e){return`$ref`in e}const pe={integer:0,number:0,string:``,boolean:!1,object:{},null:null,array:[]},me=({zodSchema:e,jsonSchema:t})=>{if(!m(e,`union`)||!(`discriminator`in e._zod.def))return t;let n=e._zod.def.discriminator;return{...t,discriminator:t.discriminator??{propertyName:n}}},he=({jsonSchema:e})=>{if(!e.anyOf)return e;let t=e.anyOf[0];return Object.assign(t,{type:ye(t.type)})},ge=()=>({type:`string`,format:`bigint`,pattern:`^-?\\d+$`}),_e=({zodSchema:e,jsonSchema:t})=>e._zod.def.rest===null?{...t,items:{not:{}}}:t,ve=e=>{let t=Array.isArray(e.type)?e.type[0]:e.type;return pe?.[t]},ye=e=>e===`null`?e:typeof e==`string`?[e,`null`]:e&&[...new Set(e).add(`null`)],q=({zodSchema:e,jsonSchema:t},n)=>{let r=e._zod.def[n.isResponse?`out`:`in`],i=e._zod.def[n.isResponse?`in`:`out`];if(!m(r,`transform`))return t;let a=J(Y(i,{ctx:n}));if(!K(a))if(n.isResponse){let e=c(r,m(i,`date`)?new Date:ve(a));if(e&&[`number`,`string`,`boolean`].includes(e))return{...t,type:e}}else{let{type:e,...t}=a;return{...t,format:`${t.format||e} (preprocessed)`}}return t},J=e=>e,be={nullable:he,union:me,bigint:ge,tuple:_e,pipe:q},xe=(t,n,r)=>{let i=[t,n];for(;i.length;){let t=i.shift();if(e.is(Object,t)){if(K(t)&&!t.$ref.startsWith(`#/components`)){let e=n[t.$ref.split(`/`).pop()];e&&(t.$ref=r.makeRef(e.id||e,J(e)).$ref);continue}i.push(...e.values(t))}e.is(Array,t)&&i.push(...e.values(t))}return t},Y=(e,{ctx:t,rules:r=be})=>{let{$defs:i={},properties:a={}}=n.toJSONSchema(n.object({subject:e}),{unrepresentable:`any`,io:t.isResponse?`output`:`input`,override:e=>{let n=r[e.zodSchema._zod.def.type];if(n){let r={...n(e,t)};for(let t in e.jsonSchema)delete e.jsonSchema[t];Object.assign(e.jsonSchema,r)}}});return xe(h(a.subject)?a.subject:{},i,t)},X=e=>{let{examples:n}=t.get(e)||{};if(Array.isArray(n))return n;if(m(e,`tuple`)){let t=[];for(let n of e._zod.def.items){let e=X(n);e.length&&t.push(e[0])}if(t.length!==e._zod.def.items.length)return[];if(e._zod.def.rest){let n=X(e._zod.def.rest);n.length&&t.push(n[0])}if(t.length)return[t]}return[]},Z=({event:e,schema:t,isResponse:n,isAck:r,makeRef:i})=>{let a={name:r?void 0:e,title:r?`Acknowledgement for ${e}`:e,payload:J(Y(t,{ctx:{isResponse:n,makeRef:i}}))},o=X(t).map(e=>({payload:e}));return o.length&&(a.examples=o),a},Q=({isResponse:e,channelId:t,messageId:n,ackId:r,event:i,ns:a,securityIds:o})=>({action:e?`send`:`receive`,channel:{$ref:`#/channels/${t}`},messages:[{$ref:`#/channels/${t}/messages/${n}`}],title:i,summary:`${e?`Outgoing`:`Incoming`} event ${i}`,description:`The message ${e?`produced`:`consumed`} by the application within the ${a} namespace`,security:o&&o.length?o.map(e=>({$ref:`#/components/securitySchemes/${e}`})):void 0,reply:r?{address:{location:`$message.payload#`,description:`Last argument: acknowledgement handler`},channel:{$ref:`#/channels/${t}`},messages:[{$ref:`#/channels/${t}/messages/${r}`}]}:void 0}),$=(e,{extra:t,makeRef:r})=>Object.assign(J(Y(n.object(e),{ctx:{isResponse:!1,makeRef:r}})),t);var Se=class extends fe{#e=new Map;#t(e,t,n=this.#e.get(e)){return n||(n=`Schema${this.#e.size+1}`,this.#e.set(e,n)),this.addSchema(n,t),{$ref:`#/components/schemas/${n}`}}#n(){return{bindingVersion:`0.1.0`,method:`GET`,headers:$({connection:n.literal(`Upgrade`).optional(),upgrade:n.literal(`websocket`).optional()},{makeRef:this.#t.bind(this)}),query:$({EIO:n.literal(`4`).describe(`The version of the protocol`),transport:n.enum([`polling`,`websocket`]).describe(`The name of the transport`),sid:n.string().optional().describe(`The session identifier`)},{makeRef:this.#t.bind(this),extra:{externalDocs:{description:`Engine.IO Protocol`,url:`https://socket.io/docs/v4/engine-io-protocol/`}}})}}constructor({actions:e,config:{namespaces:t,security:n},title:r,version:i,documentId:a,description:o,contact:s,license:c,servers:l={}}){super({info:{title:r,version:i,contact:s,license:c,description:o},id:a,defaultContentType:`text/plain`});let f=[];for(let[e,t]of Object.entries(n)){let n=u(d(`server security ${e}`));this.addSecurityScheme(n,t),f.push(n)}for(let e in l){let t=new URL(l[e].url);this.addServer(e,{description:l[e].description,host:t.host,pathname:t.pathname,protocol:t.protocol.slice(0,-1),security:f.length?f.map(e=>({$ref:`#/components/securitySchemes/${e}`})):void 0}),this.document.id||(this.document.id=`urn:${t.host.split(`.`).concat(t.pathname.slice(1).split(`/`)).join(`:`)}`)}let p=this.#n();for(let[n,{emission:r,security:i}]of Object.entries(t)){let t=y(n),a=d(t)||`Root`,o={},s=[];for(let[e,t]of Object.entries(i)){let n=u(d(`${a} security ${e}`));this.addSecurityScheme(n,t),s.push(n)}for(let[e,{schema:n,ack:i}]of Object.entries(r)){let r={event:e,makeRef:this.#t.bind(this)},s=u(d(`${a} outgoing ${e}`)),c=u(d(`${a} ack for outgoing ${e}`));o[s]=Z({...r,schema:n,isResponse:!0}),i&&(o[c]=Z({...r,schema:i,isResponse:!1,isAck:!0})),this.addOperation(d(`${a} send operation ${e}`),Q({...r,ns:t,channelId:a,messageId:s,isResponse:!0,ackId:i&&c}))}for(let n of e)if(n.namespace===t){let{event:e,inputSchema:r,outputSchema:i}=n,c={event:e,makeRef:this.#t.bind(this)},l=u(d(`${a} incoming ${e}`)),f=u(d(`${a} ack for incoming ${e}`));o[l]=Z({...c,schema:r,isResponse:!1}),i&&(o[f]=Z({...c,schema:i,isResponse:!0,isAck:!0})),this.addOperation(d(`${a} recv operation ${e}`),Q({event:e,ns:t,channelId:a,messageId:l,isResponse:!1,ackId:i&&f,securityIds:s}))}this.addChannel(a,{address:t,title:`Namespace ${t}`,bindings:{ws:p},messages:o})}}};export{b as AbstractAction,ie as ActionsFactory,x as Config,Se as Documentation,_ as InputValidationError,de as Integration,v as OutputValidationError,O as attachSockets,te as createSimpleConfig};