imposters 0.2.3 → 0.2.4
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/bin/cli.cjs +2 -2
- package/dist/cjs/cli/version.js +1 -1
- package/dist/esm/cli/version.js +1 -1
- package/package.json +1 -1
package/bin/cli.cjs
CHANGED
|
@@ -638,7 +638,7 @@ Quitting wizard mode...`));return ko(an(y))}return Z(g)}))}case"ShowVersion":{le
|
|
|
638
638
|
<div id="stub-list">
|
|
639
639
|
${ju(G1(e.stubs).value)}
|
|
640
640
|
</div>`;return Jx({title:`${e.config.name} \u2014 Stubs`,imposterName:e.config.name,port:e.config.port,activeTab:"stubs"},t)};var aa=(e,t=200)=>new Response(e,{status:t,headers:{"content-type":"text/html; charset=utf-8"}}),YYe=e=>{let t=e.match(/^\/stubs\/(.+)$/);return t?t[1]:null},GYe=e=>async t=>{let r=new URL(t.url);if(!r.pathname.startsWith("/_admin"))return null;let n=r.pathname.slice(7)||"/",o=t.method.toUpperCase();if(o==="GET"&&(n==="/"||n===""))return e.runPromise(q.gen(function*(){let a=yield*Ct.get(e.stubsRef),c=yield*e.requestLogger.getCount(e.id),u=yield*e.requestLogger.getEntries(e.id,{limit:10});return aa(jYe({config:e.config,stubCount:a.length,requestCount:c,recentRequests:u.slice().reverse()}).value)}));if(o==="GET"&&n==="/stubs")return e.runPromise(q.gen(function*(){let a=yield*Ct.get(e.stubsRef);return aa(WYe({config:e.config,stubs:a}).value)}));if(o==="POST"&&n==="/stubs")try{let a=await t.formData(),c=a.get("predicates"),u=a.get("responses"),l=a.get("responseMode")||"sequential";if(!u)return aa(J1("Responses field is required.").value,200);let p,f;try{p=JSON.parse(c||"[]"),f=JSON.parse(u)}catch{return aa(J1("Invalid JSON in predicates or responses.").value,200)}if(!Array.isArray(f)||f.length===0)return aa(J1("Responses must be a non-empty array.").value,200);let g={id:zt.make(crypto.randomUUID().slice(0,8)),predicates:p,responses:f,responseMode:l};return await e.runPromise(q.gen(function*(){yield*e.repo.addStub(e.id,g).pipe(q.catchAll(()=>q.void));let y=yield*e.repo.getStubs(e.id).pipe(q.catchAll(()=>q.succeed([])));return yield*Ct.set(e.stubsRef,y),aa(G1(y).value)}))}catch{return aa(J1("Failed to parse form data.").value,200)}let s=o==="DELETE"?YYe(n):null;if(s!==null)return e.runPromise(q.gen(function*(){yield*e.repo.removeStub(e.id,s).pipe(q.catchAll(()=>q.void));let a=yield*e.repo.getStubs(e.id).pipe(q.catchAll(()=>q.succeed([])));return yield*Ct.set(e.stubsRef,a),aa(G1(a).value)}));let i=o==="PUT"?YYe(n):null;if(i!==null)try{let a=await t.formData(),c=a.get("predicates"),u=a.get("responses"),l=a.get("responseMode");return await e.runPromise(q.gen(function*(){yield*e.repo.updateStub(e.id,i,f=>({...f,...c?{predicates:JSON.parse(c)}:{},...u?{responses:JSON.parse(u)}:{},...l?{responseMode:l}:{}})).pipe(q.catchAll(()=>q.void));let p=yield*e.repo.getStubs(e.id).pipe(q.catchAll(()=>q.succeed([])));return yield*Ct.set(e.stubsRef,p),aa(G1(p).value)}))}catch{return aa(J1("Failed to parse form data.").value,200)}if(o==="GET"&&n==="/requests")return e.runPromise(q.gen(function*(){let a=yield*e.requestLogger.getEntries(e.id,{limit:100});return aa(VYe({config:e.config,entries:a}).value)}));if(o==="GET"&&n==="/requests/list"){let a=r.searchParams;return e.runPromise(q.gen(function*(){let c={limit:100},u=a.get("method");u&&(c.method=u);let l=a.get("path");l&&(c.path=l);let p=a.get("status");p&&(c.status=Number(p));let f=yield*e.requestLogger.getEntries(e.id,c);return aa(QS(f.slice().reverse()).value)}))}if(o==="POST"&&n==="/requests/test")try{let a=await t.formData(),c=a.get("method")||"GET",u=a.get("path")||"/",l=a.get("body"),p=a.get("contentType")||"application/json",f=a.get("headers")||"",d={};p&&l&&(d["content-type"]=p);for(let v of f.split(`
|
|
641
|
-
`)){let k=v.indexOf(":");k>0&&(d[v.slice(0,k).trim()]=v.slice(k+1).trim())}let g=Date.now(),y=await fetch(`http://localhost:${e.config.port}${u}`,{method:c,headers:d,...l&&c!=="GET"&&c!=="HEAD"?{body:l}:{}}),w=Date.now()-g,S=await y.text(),I={};return y.headers.forEach((v,k)=>{I[k]=v}),aa($Ye({status:y.status,headers:I,body:S,duration:w}).value)}catch(a){return aa(`<div class="bg-red-50 border border-red-200 text-red-700 rounded p-3">Request failed: ${String(a)}</div>`)}if(o==="DELETE"&&n==="/requests")return e.runPromise(q.gen(function*(){return yield*e.requestLogger.clear(e.id),aa(QS([]).value)}));if(o==="GET"&&n.startsWith("/requests/")){let a=n.slice(10);if(a&&!a.includes("/"))return e.runPromise(q.gen(function*(){let c=yield*e.requestLogger.getEntryById(e.id,a);if(c===null)return aa("<h1>Request not found</h1>",404);let u=null;if(c.response.matchedStubId)try{u=(yield*e.repo.getStubs(e.id).pipe(q.catchAll(()=>q.succeed([])))).find(p=>p.id===c.response.matchedStubId)??null}catch{}return aa(zYe({config:e.config,entry:c,matchedStub:u}).value)}))}return aa("<h1>Not Found</h1>",404)};var bM=class extends it.Tag("FiberManager")(){},lpe=Zt.scoped(bM,q.gen(function*(){let e=yield*aS.make();return{start:(o,s)=>aS.run(e,o,s),stop:o=>aS.remove(e,o),isRunning:o=>aS.has(e,o)}}));var JYe=Fa(require("node:http"),1),Kx=class extends it.Tag("ServerFactory")(){},T9=Zt.succeed(Kx,{create:e=>{let t=JYe.createServer(async(r,n)=>{try{let o=`http://localhost:${e.port}${r.url}`,s=new Headers;for(let[p,f]of Object.entries(r.headers))f&&s.set(p,Array.isArray(f)?f.join(", "):f);let i;r.method!=="GET"&&r.method!=="HEAD"&&(i=await new Promise(p=>{let f="";r.on("data",d=>{f+=d.toString()}),r.on("end",()=>p(f))}));let a=new Request(o,{method:r.method??"GET",headers:s,...i!==void 0&&i!==""?{body:i}:{}}),c=await e.fetch(a),u={};c.headers.forEach((p,f)=>{u[f]=p}),n.writeHead(c.status,u);let l=await c.text();n.end(l)}catch(o){n.writeHead(500),n.end(JSON.stringify({error:"Internal server error",details:String(o)}))}});return t.listen(e.port),{port:e.port,stop:r=>{r&&typeof t.closeAllConnections=="function"&&t.closeAllConnections(),t.close()}}}}),KYe=Zt.succeed(Kx,{create:e=>globalThis.Bun.serve(e)});var ppe=class extends js.TaggedError("ImposterServerError"){},GA=class extends it.Tag("ImposterServer")(){},ZYe=Zt.effect(GA,q.gen(function*(){let e=yield*Ks,t=yield*bM,r=yield*Kx,n=yield*Gx,o=yield*YA,s=yield*yM,i=yield*Ct.make(Kt.empty());return{start:f=>q.gen(function*(){let d=yield*e.get(f),g=d.config,y=yield*Ct.make(d.stubs),w=yield*Ct.make(g.proxy),S=yield*FYe();yield*Ct.update(i,Kt.set(f,{stubsRef:y,proxyConfigRef:w}));let I=yield*q.runtime(),v=Kg.runPromise(I),k=GYe({id:f,config:g,stubsRef:y,repo:e,requestLogger:n,runPromise:v}),P=async Q=>{let ee=await k(Q);return ee!==null?ee:v(q.gen(function*(){let he=Date.now(),_e=yield*Ct.get(y),xe=yield*q.promise(()=>IYe(Q)),ct=kYe(xe,_e),Ke,Ut=!1;if(ct){let yr=ct.responses,ds=yield*S.getNextIndex(f,ct.id,yr.length,ct.responseMode),L=yr[ds],V=L.delay;V!==void 0&&V>0&&(yield*q.sleep(`${V} millis`)),Ke=yield*q.promise(()=>PYe(L,xe))}else{let yr=yield*Ct.get(w);if(yr){let ds=new URL(Q.url);if(Ke=yield*s.forward(xe,yr,ds).pipe(q.catchTag("ProxyError",L=>q.succeed(new Response(JSON.stringify({error:"Proxy failed",target:L.targetUrl,reason:L.reason}),{status:502,headers:{"content-type":"application/json"}})))),Ut=!0,yr.mode==="record"&&Ke.status<500){let L=Ke.clone(),V=yield*s.recordAsStub(xe,L);yield*e.addStub(f,V).pipe(q.catchAll(()=>q.void));let rt=yield*e.getStubs(f).pipe(q.catchAll(()=>q.succeed([])));yield*Ct.set(y,rt)}}else Ke=new Response(JSON.stringify({error:"No matching stub found",method:xe.method,path:xe.path}),{status:404,headers:{"content-type":"application/json"}})}let ur=yield*q.promise(()=>Ke.text()),St={};Ke.headers.forEach((yr,ds)=>{St[ds]=yr}),Ke=new Response(ur,{status:Ke.status,headers:Ke.headers});let _t=ur.length>10240?ur.slice(0,10240):ur||void 0,ho=Date.now()-he,Bt={id:zt.make(crypto.randomUUID()),imposterId:zt.make(f),timestamp:Hh(he),request:{method:xe.method,path:xe.path,headers:xe.headers,query:xe.query,body:xe.body},response:{status:Ke.status,headers:St,..._t!==void 0?{body:_t}:{},...ct?{matchedStubId:zt.make(ct.id)}:{},proxied:Ut},duration:ho};return yield*n.log(Bt).pipe(q.catchAll(()=>q.void)),yield*o.recordRequest(Bt).pipe(q.catchAll(()=>q.void)),Ke}).pipe(q.catchAllCause(he=>q.succeed(new Response(JSON.stringify({error:"Internal server error",details:String(he)}),{status:500,headers:{"content-type":"application/json"}})))))},B=q.acquireRelease(q.try({try:()=>r.create({port:g.port,fetch:P}),catch:Q=>new ppe({imposterId:f,reason:`Failed to bind port ${g.port}: ${Q}`})}),Q=>q.sync(()=>Q.stop(!0))).pipe(q.andThen(q.never),q.scoped).pipe(q.onError(()=>q.gen(function*(){yield*Ct.update(i,Kt.remove(f)),yield*e.update(f,Q=>({...Q,config:NS({...Q.config,status:"stopped"})})).pipe(q.catchAll(()=>q.void)),yield*S.reset(f)})));yield*t.start(f,B),yield*e.update(f,Q=>({...Q,config:NS({...Q.config,status:"running"})})).pipe(q.catchTag("ImposterNotFoundError",()=>q.void))}),stop:f=>q.gen(function*(){yield*t.stop(f),yield*Ct.update(i,Kt.remove(f)),yield*e.update(f,d=>({...d,config:NS({...d.config,status:"stopped"})})).pipe(q.catchAll(()=>q.void)),yield*n.removeImposter(f)}),updateStubs:f=>q.gen(function*(){let d=yield*e.getStubs(f).pipe(q.catchAll(()=>q.succeed([]))),g=yield*Ct.get(i),y=Kt.get(g,f);y._tag==="Some"&&(yield*Ct.set(y.value.stubsRef,d))}),updateProxyConfig:f=>q.gen(function*(){let d=yield*e.get(f).pipe(q.catchAll(()=>q.succeed(null)));if(d===null)return;let g=yield*Ct.get(i),y=Kt.get(g,f);y._tag==="Some"&&(yield*Ct.set(y.value.proxyConfigRef,d.config.proxy))}),isRunning:f=>t.isRunning(f)}}));var Om=class extends it.Tag("AppConfig")(){},XHt=cc.all({adminPort:cc.number("ADMIN_PORT").pipe(cc.withDefault(2525)),portRangeMin:cc.number("PORT_RANGE_MIN").pipe(cc.withDefault(3e3)),portRangeMax:cc.number("PORT_RANGE_MAX").pipe(cc.withDefault(4e3)),maxImposters:cc.number("MAX_IMPOSTERS").pipe(cc.withDefault(100)),logLevel:cc.literal("debug","info","warn","error")("LOG_LEVEL").pipe(cc.withDefault("info"))}),fpe=Zt.effect(Om,XHt);var dpe=class extends js.TaggedError("PortAllocatorError"){},hpe=class extends js.TaggedError("PortExhaustedError"){},FS=class extends it.Tag("PortAllocator")(){},XYe=Zt.effect(FS,q.gen(function*(){let e=yield*Om,t=yield*Ct.make(vo.empty());return{allocate:s=>s!==void 0?Ct.modify(t,i=>vo.has(i,s)?[q.fail(new dpe({reason:`Port ${s} is already allocated`,port:s})),i]:[q.succeed(s),vo.add(i,s)]).pipe(q.flatten):Ct.modify(t,i=>{for(let a=e.portRangeMin;a<=e.portRangeMax;a++)if(!vo.has(i,a))return[q.succeed(a),vo.add(i,a)];return[q.fail(new hpe({rangeMin:e.portRangeMin,rangeMax:e.portRangeMax})),i]}).pipe(q.flatten),release:s=>Ct.update(t,vo.remove(s)),isAvailable:s=>Ct.get(t).pipe(q.map(i=>!vo.has(i,s)))}}));var EM=e=>De(function*(){let t=e.config,r=yield*wa,n=Uo(r-id(t.createdAt));return{id:zt.make(t.id),name:zt.make(t.name),port:gc.make(t.port),protocol:"HTTP",status:t.status,endpointCount:e.stubs.length,createdAt:t.createdAt,adminUrl:zt.make(`http://localhost:${t.port}`),adminPath:zt.make("/_admin"),uptime:bb(n),...t.proxy!==void 0?{proxy:t.proxy}:{}}}),eGe=(e,t,r)=>({total:e,limit:hM.make(t),offset:r,hasMore:r+t<e});var tGe=Od.group(Wx,"imposters",e=>e.handle("createImposter",({payload:t})=>De(function*(){let r=yield*Ks,n=yield*Ud,o=yield*FS,s=yield*Om;if((yield*r.getAll).length>=s.maxImposters)return yield*Z(new Ld({message:`Maximum number of imposters (${s.maxImposters}) reached`}));let a=yield*n.generateShort,c=t.name??zt.make(a),u=yield*o.allocate(t.port).pipe(zf({PortAllocatorError:f=>Z(new Rm({message:f.reason})),PortExhaustedError:f=>Z(new Ld({message:`No available ports in range ${f.rangeMin}-${f.rangeMax}`}))})),l=NS({id:a,name:c,port:u,status:"stopped",createdAt:UK(),...t.proxy!==void 0?{proxy:t.proxy}:{}}),p=yield*r.create(l);return yield*EM(p)})).handle("listImposters",({urlParams:t})=>De(function*(){let o=(yield*(yield*Ks).getAll).filter(c=>t.status===void 0||c.config.status===t.status).filter(()=>t.protocol===void 0||t.protocol==="HTTP");o.sort((c,u)=>id(c.config.createdAt)-id(u.config.createdAt));let s=o.length,i=o.slice(t.offset,t.offset+t.limit);return{imposters:yield*Ng(i.map(EM)),pagination:eGe(s,t.limit,t.offset)}})).handle("getImposter",({path:t})=>De(function*(){let n=yield*(yield*Ks).get(t.id).pipe(Lr("ImposterNotFoundError",o=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:o.id}))));return yield*EM(n)})).handle("updateImposter",({path:t,payload:r})=>De(function*(){let n=yield*Ks,o=yield*FS,s=yield*GA,i=yield*n.get(t.id).pipe(Lr("ImposterNotFoundError",g=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:g.id})))),a=yield*s.isRunning(t.id),c=r.status==="running",u=r.status==="stopped",l=r.port!==void 0&&r.port!==i.config.port;l&&a&&(yield*s.stop(t.id));let p;l&&(p=yield*o.allocate(r.port).pipe(zf({PortAllocatorError:g=>Z(new Rm({message:g.reason})),PortExhaustedError:g=>Z(new Ld({message:`No available ports in range ${g.rangeMin}-${g.rangeMax}`}))})));let f=r.proxy===void 0?{}:r.proxy===null?{proxy:void 0}:{proxy:r.proxy};yield*n.update(t.id,g=>({...g,config:NS({...g.config,...r.name!==void 0?{name:r.name}:{},...r.status!==void 0?{status:r.status}:{},...p!==void 0?{port:p}:{},...f})})).pipe(Lr("ImposterNotFoundError",g=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:g.id}))),F2(()=>p!==void 0?o.release(p):ke)),p!==void 0&&(yield*o.release(i.config.port)),r.proxy!==void 0&&(yield*s.updateProxyConfig(t.id)),c&&!a?yield*s.start(t.id).pipe(Lr("ImposterServerError",g=>Z(new Ld({message:g.reason}))),Lr("ImposterNotFoundError",g=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:g.id})))):u&&a&&!l?yield*s.stop(t.id):l&&a&&(yield*s.start(t.id).pipe(Lr("ImposterServerError",g=>Z(new Ld({message:g.reason}))),Lr("ImposterNotFoundError",g=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:g.id})))));let d=yield*n.get(t.id).pipe(Lr("ImposterNotFoundError",g=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:g.id}))));return yield*EM(d)})).handle("deleteImposter",({path:t,urlParams:r})=>De(function*(){let n=yield*Ks,o=yield*FS,s=yield*GA,i=yield*YA,a=yield*n.get(t.id).pipe(Lr("ImposterNotFoundError",l=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:l.id}))));if(!r.force&&a.config.status!=="stopped")return yield*Z(new Rm({message:`Imposter is ${a.config.status}, use force=true to delete`}));(yield*s.isRunning(t.id))&&(yield*s.stop(t.id)),yield*n.remove(t.id).pipe(Lr("ImposterNotFoundError",l=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:l.id})))),yield*o.release(a.config.port),yield*i.resetStats(t.id);let u=yield*ie(wa,l=>Hh(l));return{message:zt.make(`Imposter ${t.id} deleted`),id:zt.make(t.id),deletedAt:u}})).handle("addStub",({path:t,payload:r})=>De(function*(){let n=yield*Ks,o=yield*Ud,s=yield*GA,i=yield*o.generateShort,a={id:zt.make(i),predicates:r.predicates,responses:r.responses,responseMode:r.responseMode},c=yield*n.addStub(t.imposterId,a).pipe(Lr("ImposterNotFoundError",l=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:l.id}))));return(yield*s.isRunning(t.imposterId))&&(yield*s.updateStubs(t.imposterId)),c})).handle("listStubs",({path:t})=>De(function*(){return yield*(yield*Ks).getStubs(t.imposterId).pipe(Lr("ImposterNotFoundError",n=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:n.id}))))})).handle("updateStub",({path:t,payload:r})=>De(function*(){let n=yield*Ks,o=yield*GA,s=yield*n.updateStub(t.imposterId,t.stubId,a=>({...a,...r.predicates!==void 0?{predicates:r.predicates}:{},...r.responses!==void 0?{responses:r.responses}:{},...r.responseMode!==void 0?{responseMode:r.responseMode}:{}})).pipe(Lr("ImposterNotFoundError",a=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:a.id}))),Lr("StubNotFoundError",a=>Z(new cn({message:"Stub not found",resourceType:"stub",resourceId:a.stubId}))));return(yield*o.isRunning(t.imposterId))&&(yield*o.updateStubs(t.imposterId)),s})).handle("deleteStub",({path:t})=>De(function*(){let r=yield*Ks,n=yield*GA,o=yield*r.removeStub(t.imposterId,t.stubId).pipe(Lr("ImposterNotFoundError",i=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:i.id}))),Lr("StubNotFoundError",i=>Z(new cn({message:"Stub not found",resourceType:"stub",resourceId:i.stubId}))));return(yield*n.isRunning(t.imposterId))&&(yield*n.updateStubs(t.imposterId)),o})).handle("listRequests",({path:t,urlParams:r})=>De(function*(){let n=yield*Ks,o=yield*Gx;return yield*n.get(t.id).pipe(Lr("ImposterNotFoundError",s=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:s.id})))),yield*o.getEntries(t.id,{limit:r.limit,...r.method!==void 0?{method:r.method}:{},...r.path!==void 0?{path:r.path}:{},...r.status!==void 0?{status:r.status}:{}})})).handle("clearRequests",({path:t})=>De(function*(){let r=yield*Ks,n=yield*Gx;return yield*r.get(t.id).pipe(Lr("ImposterNotFoundError",o=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:o.id})))),yield*n.clear(t.id),{message:`Request log cleared for imposter ${t.id}`}})).handle("getImposterStats",({path:t})=>De(function*(){let r=yield*Ks,n=yield*YA;return yield*r.get(t.id).pipe(Lr("ImposterNotFoundError",o=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:o.id})))),yield*n.getStats(t.id)})).handle("resetImposterStats",({path:t})=>De(function*(){let r=yield*Ks,n=yield*YA;return yield*r.get(t.id).pipe(Lr("ImposterNotFoundError",o=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:o.id})))),yield*n.resetStats(t.id),{message:`Statistics reset for imposter ${t.id}`}})));var rGe=Od.group(Wx,"system",e=>e.handle("healthCheck",()=>De(function*(){let t=yield*Om,n=yield*(yield*Ks).getAll,o=yield*ie(wa,c=>Hh(c)),s=process.memoryUsage(),i=n.filter(c=>c.config.status==="running").length,a=n.filter(c=>c.config.status==="stopped").length;return{status:"healthy",timestamp:o,version:zt.make("0.2.3"),uptime:bb(Uo(process.uptime()*1e3)),system:{memory:{used:zt.make(`${Math.round(s.heapUsed/1024/1024)}MB`),free:zt.make(`${Math.round((s.heapTotal-s.heapUsed)/1024/1024)}MB`)},imposters:{total:n.length,running:i,stopped:a},ports:{available:t.portRangeMax-t.portRangeMin+1-n.length,allocated:n.length}}}})).handle("serverInfo",()=>De(function*(){let t=yield*Om,r=yield*ie(wa,n=>Hh(n));return{server:{name:zt.make("imposters"),version:zt.make("0.2.3"),buildTime:r,platform:zt.make(process.platform),protocols:["HTTP"]},configuration:{maxImposters:t.maxImposters,portRange:{min:gc.make(t.portRangeMin),max:gc.make(t.portRangeMax)},defaultTimeout:3e4,logLevel:t.logLevel},features:{openApiGeneration:!0,clientGeneration:!1,authentication:!1,clustering:!1}}})));var ezt=yu(tGe,rGe),nGe=Od.api(Wx).pipe(is(ezt)),tzt=yu(Od.middlewareOpenApi(),_9.layer()).pipe(is(nGe)),oGe=yu(nGe,tzt,YI.layerContext);var Na=[];for(let e=0;e<256;++e)Na.push((e+256).toString(16).slice(1));function sGe(e,t=0){return(Na[e[t+0]]+Na[e[t+1]]+Na[e[t+2]]+Na[e[t+3]]+"-"+Na[e[t+4]]+Na[e[t+5]]+"-"+Na[e[t+6]]+Na[e[t+7]]+"-"+Na[e[t+8]]+Na[e[t+9]]+"-"+Na[e[t+10]]+Na[e[t+11]]+Na[e[t+12]]+Na[e[t+13]]+Na[e[t+14]]+Na[e[t+15]]).toLowerCase()}var iGe=require("crypto"),M9=new Uint8Array(256),D9=M9.length;function mpe(){return D9>M9.length-16&&((0,iGe.randomFillSync)(M9),D9=0),M9.slice(D9,D9+=16)}var aGe=require("crypto"),gpe={randomUUID:aGe.randomUUID};function rzt(e,t,r){if(gpe.randomUUID&&!t&&!e)return gpe.randomUUID();e=e||{};let n=e.random??e.rng?.()??mpe();if(n.length<16)throw new Error("Random bytes length must be >= 16");if(n[6]=n[6]&15|64,n[8]=n[8]&63|128,t){if(r=r||0,r<0||r+16>t.length)throw new RangeError(`UUID byte range ${r}:${r+15} is out of buffer bounds`);for(let o=0;o<16;++o)t[r+o]=n[o];return t}return sGe(n)}var N9=rzt;var Ape=Hs(Ud,{generate:Ie(()=>N9()),generateShort:Ie(()=>N9().substring(0,8))});var nzt=XYe.pipe(is(fpe)),ozt=LYe.pipe(is(Ape)),szt=ZYe.pipe(is(yu(lpe,Zle,T9,ipe,spe,ozt))),cGe=yu(Ape,fpe,nzt,Zle,lpe,ipe,spe,szt);var uGe=(e,t)=>ze`<!DOCTYPE html>
|
|
641
|
+
`)){let k=v.indexOf(":");k>0&&(d[v.slice(0,k).trim()]=v.slice(k+1).trim())}let g=Date.now(),y=await fetch(`http://localhost:${e.config.port}${u}`,{method:c,headers:d,...l&&c!=="GET"&&c!=="HEAD"?{body:l}:{}}),w=Date.now()-g,S=await y.text(),I={};return y.headers.forEach((v,k)=>{I[k]=v}),aa($Ye({status:y.status,headers:I,body:S,duration:w}).value)}catch(a){return aa(`<div class="bg-red-50 border border-red-200 text-red-700 rounded p-3">Request failed: ${String(a)}</div>`)}if(o==="DELETE"&&n==="/requests")return e.runPromise(q.gen(function*(){return yield*e.requestLogger.clear(e.id),aa(QS([]).value)}));if(o==="GET"&&n.startsWith("/requests/")){let a=n.slice(10);if(a&&!a.includes("/"))return e.runPromise(q.gen(function*(){let c=yield*e.requestLogger.getEntryById(e.id,a);if(c===null)return aa("<h1>Request not found</h1>",404);let u=null;if(c.response.matchedStubId)try{u=(yield*e.repo.getStubs(e.id).pipe(q.catchAll(()=>q.succeed([])))).find(p=>p.id===c.response.matchedStubId)??null}catch{}return aa(zYe({config:e.config,entry:c,matchedStub:u}).value)}))}return aa("<h1>Not Found</h1>",404)};var bM=class extends it.Tag("FiberManager")(){},lpe=Zt.scoped(bM,q.gen(function*(){let e=yield*aS.make();return{start:(o,s)=>aS.run(e,o,s),stop:o=>aS.remove(e,o),isRunning:o=>aS.has(e,o)}}));var JYe=Fa(require("node:http"),1),Kx=class extends it.Tag("ServerFactory")(){},T9=Zt.succeed(Kx,{create:e=>{let t=JYe.createServer(async(r,n)=>{try{let o=`http://localhost:${e.port}${r.url}`,s=new Headers;for(let[p,f]of Object.entries(r.headers))f&&s.set(p,Array.isArray(f)?f.join(", "):f);let i;r.method!=="GET"&&r.method!=="HEAD"&&(i=await new Promise(p=>{let f="";r.on("data",d=>{f+=d.toString()}),r.on("end",()=>p(f))}));let a=new Request(o,{method:r.method??"GET",headers:s,...i!==void 0&&i!==""?{body:i}:{}}),c=await e.fetch(a),u={};c.headers.forEach((p,f)=>{u[f]=p}),n.writeHead(c.status,u);let l=await c.text();n.end(l)}catch(o){n.writeHead(500),n.end(JSON.stringify({error:"Internal server error",details:String(o)}))}});return t.listen(e.port),{port:e.port,stop:r=>{r&&typeof t.closeAllConnections=="function"&&t.closeAllConnections(),t.close()}}}}),KYe=Zt.succeed(Kx,{create:e=>globalThis.Bun.serve(e)});var ppe=class extends js.TaggedError("ImposterServerError"){},GA=class extends it.Tag("ImposterServer")(){},ZYe=Zt.effect(GA,q.gen(function*(){let e=yield*Ks,t=yield*bM,r=yield*Kx,n=yield*Gx,o=yield*YA,s=yield*yM,i=yield*Ct.make(Kt.empty());return{start:f=>q.gen(function*(){let d=yield*e.get(f),g=d.config,y=yield*Ct.make(d.stubs),w=yield*Ct.make(g.proxy),S=yield*FYe();yield*Ct.update(i,Kt.set(f,{stubsRef:y,proxyConfigRef:w}));let I=yield*q.runtime(),v=Kg.runPromise(I),k=GYe({id:f,config:g,stubsRef:y,repo:e,requestLogger:n,runPromise:v}),P=async Q=>{let ee=await k(Q);return ee!==null?ee:v(q.gen(function*(){let he=Date.now(),_e=yield*Ct.get(y),xe=yield*q.promise(()=>IYe(Q)),ct=kYe(xe,_e),Ke,Ut=!1;if(ct){let yr=ct.responses,ds=yield*S.getNextIndex(f,ct.id,yr.length,ct.responseMode),L=yr[ds],V=L.delay;V!==void 0&&V>0&&(yield*q.sleep(`${V} millis`)),Ke=yield*q.promise(()=>PYe(L,xe))}else{let yr=yield*Ct.get(w);if(yr){let ds=new URL(Q.url);if(Ke=yield*s.forward(xe,yr,ds).pipe(q.catchTag("ProxyError",L=>q.succeed(new Response(JSON.stringify({error:"Proxy failed",target:L.targetUrl,reason:L.reason}),{status:502,headers:{"content-type":"application/json"}})))),Ut=!0,yr.mode==="record"&&Ke.status<500){let L=Ke.clone(),V=yield*s.recordAsStub(xe,L);yield*e.addStub(f,V).pipe(q.catchAll(()=>q.void));let rt=yield*e.getStubs(f).pipe(q.catchAll(()=>q.succeed([])));yield*Ct.set(y,rt)}}else Ke=new Response(JSON.stringify({error:"No matching stub found",method:xe.method,path:xe.path}),{status:404,headers:{"content-type":"application/json"}})}let ur=yield*q.promise(()=>Ke.text()),St={};Ke.headers.forEach((yr,ds)=>{St[ds]=yr}),Ke=new Response(ur,{status:Ke.status,headers:Ke.headers});let _t=ur.length>10240?ur.slice(0,10240):ur||void 0,ho=Date.now()-he,Bt={id:zt.make(crypto.randomUUID()),imposterId:zt.make(f),timestamp:Hh(he),request:{method:xe.method,path:xe.path,headers:xe.headers,query:xe.query,body:xe.body},response:{status:Ke.status,headers:St,..._t!==void 0?{body:_t}:{},...ct?{matchedStubId:zt.make(ct.id)}:{},proxied:Ut},duration:ho};return yield*n.log(Bt).pipe(q.catchAll(()=>q.void)),yield*o.recordRequest(Bt).pipe(q.catchAll(()=>q.void)),Ke}).pipe(q.catchAllCause(he=>q.succeed(new Response(JSON.stringify({error:"Internal server error",details:String(he)}),{status:500,headers:{"content-type":"application/json"}})))))},B=q.acquireRelease(q.try({try:()=>r.create({port:g.port,fetch:P}),catch:Q=>new ppe({imposterId:f,reason:`Failed to bind port ${g.port}: ${Q}`})}),Q=>q.sync(()=>Q.stop(!0))).pipe(q.andThen(q.never),q.scoped).pipe(q.onError(()=>q.gen(function*(){yield*Ct.update(i,Kt.remove(f)),yield*e.update(f,Q=>({...Q,config:NS({...Q.config,status:"stopped"})})).pipe(q.catchAll(()=>q.void)),yield*S.reset(f)})));yield*t.start(f,B),yield*e.update(f,Q=>({...Q,config:NS({...Q.config,status:"running"})})).pipe(q.catchTag("ImposterNotFoundError",()=>q.void))}),stop:f=>q.gen(function*(){yield*t.stop(f),yield*Ct.update(i,Kt.remove(f)),yield*e.update(f,d=>({...d,config:NS({...d.config,status:"stopped"})})).pipe(q.catchAll(()=>q.void)),yield*n.removeImposter(f)}),updateStubs:f=>q.gen(function*(){let d=yield*e.getStubs(f).pipe(q.catchAll(()=>q.succeed([]))),g=yield*Ct.get(i),y=Kt.get(g,f);y._tag==="Some"&&(yield*Ct.set(y.value.stubsRef,d))}),updateProxyConfig:f=>q.gen(function*(){let d=yield*e.get(f).pipe(q.catchAll(()=>q.succeed(null)));if(d===null)return;let g=yield*Ct.get(i),y=Kt.get(g,f);y._tag==="Some"&&(yield*Ct.set(y.value.proxyConfigRef,d.config.proxy))}),isRunning:f=>t.isRunning(f)}}));var Om=class extends it.Tag("AppConfig")(){},XHt=cc.all({adminPort:cc.number("ADMIN_PORT").pipe(cc.withDefault(2525)),portRangeMin:cc.number("PORT_RANGE_MIN").pipe(cc.withDefault(3e3)),portRangeMax:cc.number("PORT_RANGE_MAX").pipe(cc.withDefault(4e3)),maxImposters:cc.number("MAX_IMPOSTERS").pipe(cc.withDefault(100)),logLevel:cc.literal("debug","info","warn","error")("LOG_LEVEL").pipe(cc.withDefault("info"))}),fpe=Zt.effect(Om,XHt);var dpe=class extends js.TaggedError("PortAllocatorError"){},hpe=class extends js.TaggedError("PortExhaustedError"){},FS=class extends it.Tag("PortAllocator")(){},XYe=Zt.effect(FS,q.gen(function*(){let e=yield*Om,t=yield*Ct.make(vo.empty());return{allocate:s=>s!==void 0?Ct.modify(t,i=>vo.has(i,s)?[q.fail(new dpe({reason:`Port ${s} is already allocated`,port:s})),i]:[q.succeed(s),vo.add(i,s)]).pipe(q.flatten):Ct.modify(t,i=>{for(let a=e.portRangeMin;a<=e.portRangeMax;a++)if(!vo.has(i,a))return[q.succeed(a),vo.add(i,a)];return[q.fail(new hpe({rangeMin:e.portRangeMin,rangeMax:e.portRangeMax})),i]}).pipe(q.flatten),release:s=>Ct.update(t,vo.remove(s)),isAvailable:s=>Ct.get(t).pipe(q.map(i=>!vo.has(i,s)))}}));var EM=e=>De(function*(){let t=e.config,r=yield*wa,n=Uo(r-id(t.createdAt));return{id:zt.make(t.id),name:zt.make(t.name),port:gc.make(t.port),protocol:"HTTP",status:t.status,endpointCount:e.stubs.length,createdAt:t.createdAt,adminUrl:zt.make(`http://localhost:${t.port}`),adminPath:zt.make("/_admin"),uptime:bb(n),...t.proxy!==void 0?{proxy:t.proxy}:{}}}),eGe=(e,t,r)=>({total:e,limit:hM.make(t),offset:r,hasMore:r+t<e});var tGe=Od.group(Wx,"imposters",e=>e.handle("createImposter",({payload:t})=>De(function*(){let r=yield*Ks,n=yield*Ud,o=yield*FS,s=yield*Om;if((yield*r.getAll).length>=s.maxImposters)return yield*Z(new Ld({message:`Maximum number of imposters (${s.maxImposters}) reached`}));let a=yield*n.generateShort,c=t.name??zt.make(a),u=yield*o.allocate(t.port).pipe(zf({PortAllocatorError:f=>Z(new Rm({message:f.reason})),PortExhaustedError:f=>Z(new Ld({message:`No available ports in range ${f.rangeMin}-${f.rangeMax}`}))})),l=NS({id:a,name:c,port:u,status:"stopped",createdAt:UK(),...t.proxy!==void 0?{proxy:t.proxy}:{}}),p=yield*r.create(l);return yield*EM(p)})).handle("listImposters",({urlParams:t})=>De(function*(){let o=(yield*(yield*Ks).getAll).filter(c=>t.status===void 0||c.config.status===t.status).filter(()=>t.protocol===void 0||t.protocol==="HTTP");o.sort((c,u)=>id(c.config.createdAt)-id(u.config.createdAt));let s=o.length,i=o.slice(t.offset,t.offset+t.limit);return{imposters:yield*Ng(i.map(EM)),pagination:eGe(s,t.limit,t.offset)}})).handle("getImposter",({path:t})=>De(function*(){let n=yield*(yield*Ks).get(t.id).pipe(Lr("ImposterNotFoundError",o=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:o.id}))));return yield*EM(n)})).handle("updateImposter",({path:t,payload:r})=>De(function*(){let n=yield*Ks,o=yield*FS,s=yield*GA,i=yield*n.get(t.id).pipe(Lr("ImposterNotFoundError",g=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:g.id})))),a=yield*s.isRunning(t.id),c=r.status==="running",u=r.status==="stopped",l=r.port!==void 0&&r.port!==i.config.port;l&&a&&(yield*s.stop(t.id));let p;l&&(p=yield*o.allocate(r.port).pipe(zf({PortAllocatorError:g=>Z(new Rm({message:g.reason})),PortExhaustedError:g=>Z(new Ld({message:`No available ports in range ${g.rangeMin}-${g.rangeMax}`}))})));let f=r.proxy===void 0?{}:r.proxy===null?{proxy:void 0}:{proxy:r.proxy};yield*n.update(t.id,g=>({...g,config:NS({...g.config,...r.name!==void 0?{name:r.name}:{},...r.status!==void 0?{status:r.status}:{},...p!==void 0?{port:p}:{},...f})})).pipe(Lr("ImposterNotFoundError",g=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:g.id}))),F2(()=>p!==void 0?o.release(p):ke)),p!==void 0&&(yield*o.release(i.config.port)),r.proxy!==void 0&&(yield*s.updateProxyConfig(t.id)),c&&!a?yield*s.start(t.id).pipe(Lr("ImposterServerError",g=>Z(new Ld({message:g.reason}))),Lr("ImposterNotFoundError",g=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:g.id})))):u&&a&&!l?yield*s.stop(t.id):l&&a&&(yield*s.start(t.id).pipe(Lr("ImposterServerError",g=>Z(new Ld({message:g.reason}))),Lr("ImposterNotFoundError",g=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:g.id})))));let d=yield*n.get(t.id).pipe(Lr("ImposterNotFoundError",g=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:g.id}))));return yield*EM(d)})).handle("deleteImposter",({path:t,urlParams:r})=>De(function*(){let n=yield*Ks,o=yield*FS,s=yield*GA,i=yield*YA,a=yield*n.get(t.id).pipe(Lr("ImposterNotFoundError",l=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:l.id}))));if(!r.force&&a.config.status!=="stopped")return yield*Z(new Rm({message:`Imposter is ${a.config.status}, use force=true to delete`}));(yield*s.isRunning(t.id))&&(yield*s.stop(t.id)),yield*n.remove(t.id).pipe(Lr("ImposterNotFoundError",l=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:l.id})))),yield*o.release(a.config.port),yield*i.resetStats(t.id);let u=yield*ie(wa,l=>Hh(l));return{message:zt.make(`Imposter ${t.id} deleted`),id:zt.make(t.id),deletedAt:u}})).handle("addStub",({path:t,payload:r})=>De(function*(){let n=yield*Ks,o=yield*Ud,s=yield*GA,i=yield*o.generateShort,a={id:zt.make(i),predicates:r.predicates,responses:r.responses,responseMode:r.responseMode},c=yield*n.addStub(t.imposterId,a).pipe(Lr("ImposterNotFoundError",l=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:l.id}))));return(yield*s.isRunning(t.imposterId))&&(yield*s.updateStubs(t.imposterId)),c})).handle("listStubs",({path:t})=>De(function*(){return yield*(yield*Ks).getStubs(t.imposterId).pipe(Lr("ImposterNotFoundError",n=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:n.id}))))})).handle("updateStub",({path:t,payload:r})=>De(function*(){let n=yield*Ks,o=yield*GA,s=yield*n.updateStub(t.imposterId,t.stubId,a=>({...a,...r.predicates!==void 0?{predicates:r.predicates}:{},...r.responses!==void 0?{responses:r.responses}:{},...r.responseMode!==void 0?{responseMode:r.responseMode}:{}})).pipe(Lr("ImposterNotFoundError",a=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:a.id}))),Lr("StubNotFoundError",a=>Z(new cn({message:"Stub not found",resourceType:"stub",resourceId:a.stubId}))));return(yield*o.isRunning(t.imposterId))&&(yield*o.updateStubs(t.imposterId)),s})).handle("deleteStub",({path:t})=>De(function*(){let r=yield*Ks,n=yield*GA,o=yield*r.removeStub(t.imposterId,t.stubId).pipe(Lr("ImposterNotFoundError",i=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:i.id}))),Lr("StubNotFoundError",i=>Z(new cn({message:"Stub not found",resourceType:"stub",resourceId:i.stubId}))));return(yield*n.isRunning(t.imposterId))&&(yield*n.updateStubs(t.imposterId)),o})).handle("listRequests",({path:t,urlParams:r})=>De(function*(){let n=yield*Ks,o=yield*Gx;return yield*n.get(t.id).pipe(Lr("ImposterNotFoundError",s=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:s.id})))),yield*o.getEntries(t.id,{limit:r.limit,...r.method!==void 0?{method:r.method}:{},...r.path!==void 0?{path:r.path}:{},...r.status!==void 0?{status:r.status}:{}})})).handle("clearRequests",({path:t})=>De(function*(){let r=yield*Ks,n=yield*Gx;return yield*r.get(t.id).pipe(Lr("ImposterNotFoundError",o=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:o.id})))),yield*n.clear(t.id),{message:`Request log cleared for imposter ${t.id}`}})).handle("getImposterStats",({path:t})=>De(function*(){let r=yield*Ks,n=yield*YA;return yield*r.get(t.id).pipe(Lr("ImposterNotFoundError",o=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:o.id})))),yield*n.getStats(t.id)})).handle("resetImposterStats",({path:t})=>De(function*(){let r=yield*Ks,n=yield*YA;return yield*r.get(t.id).pipe(Lr("ImposterNotFoundError",o=>Z(new cn({message:"Imposter not found",resourceType:"imposter",resourceId:o.id})))),yield*n.resetStats(t.id),{message:`Statistics reset for imposter ${t.id}`}})));var rGe=Od.group(Wx,"system",e=>e.handle("healthCheck",()=>De(function*(){let t=yield*Om,n=yield*(yield*Ks).getAll,o=yield*ie(wa,c=>Hh(c)),s=process.memoryUsage(),i=n.filter(c=>c.config.status==="running").length,a=n.filter(c=>c.config.status==="stopped").length;return{status:"healthy",timestamp:o,version:zt.make("0.2.4"),uptime:bb(Uo(process.uptime()*1e3)),system:{memory:{used:zt.make(`${Math.round(s.heapUsed/1024/1024)}MB`),free:zt.make(`${Math.round((s.heapTotal-s.heapUsed)/1024/1024)}MB`)},imposters:{total:n.length,running:i,stopped:a},ports:{available:t.portRangeMax-t.portRangeMin+1-n.length,allocated:n.length}}}})).handle("serverInfo",()=>De(function*(){let t=yield*Om,r=yield*ie(wa,n=>Hh(n));return{server:{name:zt.make("imposters"),version:zt.make("0.2.4"),buildTime:r,platform:zt.make(process.platform),protocols:["HTTP"]},configuration:{maxImposters:t.maxImposters,portRange:{min:gc.make(t.portRangeMin),max:gc.make(t.portRangeMax)},defaultTimeout:3e4,logLevel:t.logLevel},features:{openApiGeneration:!0,clientGeneration:!1,authentication:!1,clustering:!1}}})));var ezt=yu(tGe,rGe),nGe=Od.api(Wx).pipe(is(ezt)),tzt=yu(Od.middlewareOpenApi(),_9.layer()).pipe(is(nGe)),oGe=yu(nGe,tzt,YI.layerContext);var Na=[];for(let e=0;e<256;++e)Na.push((e+256).toString(16).slice(1));function sGe(e,t=0){return(Na[e[t+0]]+Na[e[t+1]]+Na[e[t+2]]+Na[e[t+3]]+"-"+Na[e[t+4]]+Na[e[t+5]]+"-"+Na[e[t+6]]+Na[e[t+7]]+"-"+Na[e[t+8]]+Na[e[t+9]]+"-"+Na[e[t+10]]+Na[e[t+11]]+Na[e[t+12]]+Na[e[t+13]]+Na[e[t+14]]+Na[e[t+15]]).toLowerCase()}var iGe=require("crypto"),M9=new Uint8Array(256),D9=M9.length;function mpe(){return D9>M9.length-16&&((0,iGe.randomFillSync)(M9),D9=0),M9.slice(D9,D9+=16)}var aGe=require("crypto"),gpe={randomUUID:aGe.randomUUID};function rzt(e,t,r){if(gpe.randomUUID&&!t&&!e)return gpe.randomUUID();e=e||{};let n=e.random??e.rng?.()??mpe();if(n.length<16)throw new Error("Random bytes length must be >= 16");if(n[6]=n[6]&15|64,n[8]=n[8]&63|128,t){if(r=r||0,r<0||r+16>t.length)throw new RangeError(`UUID byte range ${r}:${r+15} is out of buffer bounds`);for(let o=0;o<16;++o)t[r+o]=n[o];return t}return sGe(n)}var N9=rzt;var Ape=Hs(Ud,{generate:Ie(()=>N9()),generateShort:Ie(()=>N9().substring(0,8))});var nzt=XYe.pipe(is(fpe)),ozt=LYe.pipe(is(Ape)),szt=ZYe.pipe(is(yu(lpe,Zle,T9,ipe,spe,ozt))),cGe=yu(Ape,fpe,nzt,Zle,lpe,ipe,spe,szt);var uGe=(e,t)=>ze`<!DOCTYPE html>
|
|
642
642
|
<html lang="en">
|
|
643
643
|
<head>
|
|
644
644
|
<meta charset="utf-8">
|
|
@@ -727,7 +727,7 @@ Quitting wizard mode...`));return ko(an(y))}return Z(g)}))}case"ShowVersion":{le
|
|
|
727
727
|
${ju(Zx(e.imposters).value)}
|
|
728
728
|
</tbody>
|
|
729
729
|
</table>
|
|
730
|
-
</div>`;return uGe({title:"Imposters \u2014 Admin Dashboard"},t)};var Tm=(e,t=200)=>new Response(e,{status:t,headers:{"content-type":"text/html; charset=utf-8"}}),dGe=e=>({id:e.id,name:e.name??`imposter-${e.id}`,port:e.port,status:e.status,protocol:e.protocol??"HTTP",stubCount:e.stubs?.length??e.endpointCount??e.stubCount??0}),Z1=async e=>{let t=await e(new Request("http://localhost/imposters?limit=50",{method:"GET"}));if(!t.ok)return[];let r=await t.json();return(Array.isArray(r)?r:r.imposters??r.items??[]).map(dGe)},fGe=async(e,t)=>{let r=await e(new Request(`http://localhost/imposters/${t}`,{method:"GET"}));if(!r.ok)return null;let n=await r.json();return dGe(n)},hGe=e=>async t=>{let r=new URL(t.url);if(!r.pathname.startsWith("/_ui"))return null;let n=r.pathname.slice(4)||"/",o=t.method.toUpperCase();if(o==="GET"&&(n==="/"||n==="")){let c=await Z1(e.apiHandler);return Tm(pGe({imposters:c}).value)}if(o==="GET"&&n==="/imposters"){let c=await Z1(e.apiHandler);return Tm(Zx(c).value)}if(o==="POST"&&n==="/imposters")try{let c=await t.formData(),u=c.get("name"),l=c.get("port"),p=c.get("autoStart")==="on",f={protocol:"HTTP"};u&&u.trim()&&(f.name=u.trim()),l&&l.trim()&&(f.port=Number(l.trim()));let d=await e.apiHandler(new Request("http://localhost/imposters",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(f)}));if(!d.ok){let w=await d.text(),S=await Z1(e.apiHandler);return Tm(wM(`Failed to create imposter: ${w}`).value+Zx(S).value)}let g=await d.json();p&&await e.apiHandler(new Request(`http://localhost/imposters/${g.id}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({status:"running"})}));let y=await Z1(e.apiHandler);return Tm(Zx(y).value)}catch(c){let u=await Z1(e.apiHandler);return Tm(wM(`Error: ${String(c)}`).value+Zx(u).value)}let s=n.match(/^\/imposters\/([^/]+)\/start$/);if(o==="POST"&&s){let c=s[1];await e.apiHandler(new Request(`http://localhost/imposters/${c}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({status:"running"})})),await new Promise(l=>setTimeout(l,100));let u=await fGe(e.apiHandler,c);return u?Tm(Q9(u).value):Tm(wM("Imposter not found").value,404)}let i=n.match(/^\/imposters\/([^/]+)\/stop$/);if(o==="POST"&&i){let c=i[1];await e.apiHandler(new Request(`http://localhost/imposters/${c}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({status:"stopped"})})),await new Promise(l=>setTimeout(l,100));let u=await fGe(e.apiHandler,c);return u?Tm(Q9(u).value):Tm(wM("Imposter not found").value,404)}let a=n.match(/^\/imposters\/([^/]+)$/);if(o==="DELETE"&&a){let c=a[1];await e.apiHandler(new Request(`http://localhost/imposters/${c}?force=true`,{method:"DELETE"}));let u=await Z1(e.apiHandler);return Tm(Zx(u).value)}return null};var czt=oGe.pipe(is(cGe));var mGe=e=>{let{dispose:t,handler:r}=Od.toWebHandler(czt),n=hGe({apiHandler:r,adminPort:e});return{handler:async s=>{let i=await n(s);return i!==null?i:r(s)},dispose:t}};var yGe=Fa(require("node:fs"),1);var uzt=Qe({name:ot(zt),port:gc,stubs:br(Xt(v9),{default:()=>[]}),proxy:ot(W1)}),gGe=Qe({port:br(gc,{default:()=>2525}),portRangeMin:br(gc,{default:()=>3e3}),portRangeMax:br(gc,{default:()=>4e3}),maxImposters:br(ft.pipe(gr(),Su()),{default:()=>100}),logLevel:br(Et("debug","info","warn","error"),{default:()=>"info"})}),AGe=Qe({admin:br(gGe,{default:()=>K_(gGe)({})}),imposters:br(Xt(uzt),{default:()=>[]})});var SM=class extends js.TaggedError("ConfigLoadError"){},xGe=e=>q.gen(function*(){let t=yield*q.try({try:()=>yGe.readFileSync(e,"utf-8"),catch:n=>new SM({message:`Failed to read config file: ${e}`,cause:n})}),r=yield*q.try({try:()=>JSON.parse(t),catch:n=>new SM({message:`Invalid JSON in config file: ${e}`,cause:n})});return yield*zn.decodeUnknown(AGe)(r).pipe(q.mapError(n=>new SM({message:`Config validation failed: ${String(n)}`,cause:n})))});var bGe="0.2.
|
|
730
|
+
</div>`;return uGe({title:"Imposters \u2014 Admin Dashboard"},t)};var Tm=(e,t=200)=>new Response(e,{status:t,headers:{"content-type":"text/html; charset=utf-8"}}),dGe=e=>({id:e.id,name:e.name??`imposter-${e.id}`,port:e.port,status:e.status,protocol:e.protocol??"HTTP",stubCount:e.stubs?.length??e.endpointCount??e.stubCount??0}),Z1=async e=>{let t=await e(new Request("http://localhost/imposters?limit=50",{method:"GET"}));if(!t.ok)return[];let r=await t.json();return(Array.isArray(r)?r:r.imposters??r.items??[]).map(dGe)},fGe=async(e,t)=>{let r=await e(new Request(`http://localhost/imposters/${t}`,{method:"GET"}));if(!r.ok)return null;let n=await r.json();return dGe(n)},hGe=e=>async t=>{let r=new URL(t.url);if(!r.pathname.startsWith("/_ui"))return null;let n=r.pathname.slice(4)||"/",o=t.method.toUpperCase();if(o==="GET"&&(n==="/"||n==="")){let c=await Z1(e.apiHandler);return Tm(pGe({imposters:c}).value)}if(o==="GET"&&n==="/imposters"){let c=await Z1(e.apiHandler);return Tm(Zx(c).value)}if(o==="POST"&&n==="/imposters")try{let c=await t.formData(),u=c.get("name"),l=c.get("port"),p=c.get("autoStart")==="on",f={protocol:"HTTP"};u&&u.trim()&&(f.name=u.trim()),l&&l.trim()&&(f.port=Number(l.trim()));let d=await e.apiHandler(new Request("http://localhost/imposters",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(f)}));if(!d.ok){let w=await d.text(),S=await Z1(e.apiHandler);return Tm(wM(`Failed to create imposter: ${w}`).value+Zx(S).value)}let g=await d.json();p&&await e.apiHandler(new Request(`http://localhost/imposters/${g.id}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({status:"running"})}));let y=await Z1(e.apiHandler);return Tm(Zx(y).value)}catch(c){let u=await Z1(e.apiHandler);return Tm(wM(`Error: ${String(c)}`).value+Zx(u).value)}let s=n.match(/^\/imposters\/([^/]+)\/start$/);if(o==="POST"&&s){let c=s[1];await e.apiHandler(new Request(`http://localhost/imposters/${c}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({status:"running"})})),await new Promise(l=>setTimeout(l,100));let u=await fGe(e.apiHandler,c);return u?Tm(Q9(u).value):Tm(wM("Imposter not found").value,404)}let i=n.match(/^\/imposters\/([^/]+)\/stop$/);if(o==="POST"&&i){let c=i[1];await e.apiHandler(new Request(`http://localhost/imposters/${c}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({status:"stopped"})})),await new Promise(l=>setTimeout(l,100));let u=await fGe(e.apiHandler,c);return u?Tm(Q9(u).value):Tm(wM("Imposter not found").value,404)}let a=n.match(/^\/imposters\/([^/]+)$/);if(o==="DELETE"&&a){let c=a[1];await e.apiHandler(new Request(`http://localhost/imposters/${c}?force=true`,{method:"DELETE"}));let u=await Z1(e.apiHandler);return Tm(Zx(u).value)}return null};var czt=oGe.pipe(is(cGe));var mGe=e=>{let{dispose:t,handler:r}=Od.toWebHandler(czt),n=hGe({apiHandler:r,adminPort:e});return{handler:async s=>{let i=await n(s);return i!==null?i:r(s)},dispose:t}};var yGe=Fa(require("node:fs"),1);var uzt=Qe({name:ot(zt),port:gc,stubs:br(Xt(v9),{default:()=>[]}),proxy:ot(W1)}),gGe=Qe({port:br(gc,{default:()=>2525}),portRangeMin:br(gc,{default:()=>3e3}),portRangeMax:br(gc,{default:()=>4e3}),maxImposters:br(ft.pipe(gr(),Su()),{default:()=>100}),logLevel:br(Et("debug","info","warn","error"),{default:()=>"info"})}),AGe=Qe({admin:br(gGe,{default:()=>K_(gGe)({})}),imposters:br(Xt(uzt),{default:()=>[]})});var SM=class extends js.TaggedError("ConfigLoadError"){},xGe=e=>q.gen(function*(){let t=yield*q.try({try:()=>yGe.readFileSync(e,"utf-8"),catch:n=>new SM({message:`Failed to read config file: ${e}`,cause:n})}),r=yield*q.try({try:()=>JSON.parse(t),catch:n=>new SM({message:`Invalid JSON in config file: ${e}`,cause:n})});return yield*zn.decodeUnknown(AGe)(r).pipe(q.mapError(n=>new SM({message:`Config validation failed: ${String(n)}`,cause:n})))});var bGe="0.2.4";var lzt=jc.file("config").pipe(jc.withAlias("c"),jc.withDescription("Path to JSON config file"),jc.optional),pzt=jc.integer("port").pipe(jc.withAlias("p"),jc.withDescription("Admin server port (default: 2525)"),jc.optional),fzt=jc.choice("runtime",["node","bun"]).pipe(jc.withDescription("Server runtime: node (default) or bun"),jc.withDefault("node")),dzt=Gw.make("start",{config:lzt,port:pzt,runtime:fzt},({config:e,port:t,runtime:r})=>q.gen(function*(){let n=Le.isSome(t)?t.value:Number(process.env.ADMIN_PORT??2525),{dispose:o,handler:s}=mGe(n),a=(yield*Kx).create({port:n,fetch:s});if(console.log(`Imposters admin server running on http://localhost:${a.port} (runtime: ${r})`),console.log(`Admin UI: http://localhost:${a.port}/_ui`),Le.isSome(e)){let c=yield*xGe(e.value).pipe(q.catchTag("ConfigLoadError",u=>q.sync(()=>(console.error(`Warning: ${u.message}`),null))));if(c!==null&&c.imposters.length>0){let u=SYe(`http://localhost:${a.port}`).pipe(Zt.provide(iYe(s)));yield*q.provide(q.gen(function*(){let l=yield*AM;for(let p of c.imposters){let f=yield*l.imposters.createImposter({payload:{port:p.port,...p.name!==void 0?{name:p.name}:{},protocol:"HTTP",adminPath:"/_admin"}}).pipe(q.catchAll(d=>(console.error(`Failed to create imposter on port ${p.port}: ${d}`),q.succeed(null))));if(f!==null){for(let d of p.stubs)yield*l.imposters.addStub({path:{imposterId:f.id},payload:d}).pipe(q.catchAll(g=>(console.error(`Failed to add stub: ${g}`),q.void)));yield*l.imposters.updateImposter({path:{id:f.id},payload:{status:"running"}}).pipe(q.catchAll(d=>(console.error(`Failed to start imposter ${f.id}: ${d}`),q.void))),console.log(`Created imposter "${p.name??f.id}" on port ${p.port}`)}}}),u)}}yield*q.async(()=>{let c=()=>{console.log("Shutting down..."),a.stop(!0),o(),process.exit(0)};process.on("SIGINT",c),process.on("SIGTERM",c)})}).pipe(q.provide(r==="bun"?KYe:T9))),hzt=Gw.make("imposters").pipe(Gw.withSubcommands([dzt])),mzt=Gw.run(hzt,{name:"imposters",version:bGe}),_qr=mzt(process.argv).pipe(q.provide(b9.layer),E9.runMain);
|
|
731
731
|
/*! Bundled license information:
|
|
732
732
|
|
|
733
733
|
undici/lib/web/fetch/body.js:
|
package/dist/cjs/cli/version.js
CHANGED
package/dist/esm/cli/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = "0.2.
|
|
1
|
+
export const version = "0.2.4";
|
|
2
2
|
//# sourceMappingURL=version.js.map
|