UNPKG

@vulppi/intrest

Version:
7 lines (6 loc) 9.75 kB
import L from"chalk";import Ne from"selfsigned";import{existsSync as Ce,mkdirSync as $e,rmSync as De}from"fs";import{createSecureServer as He,createServer as _e}from"http2";import{join as ze}from"path";var b=()=>process.env.NODE_ENV==="development",P={env:[".env",".env{.local,.development,.production}"],entryFolder:["routes","src/routes"],assetsFolder:["assets","src/assets"],staticFolder:["static","src/static","public","src/public"],configFile:"intrest.config.{mjs,cjs,js}",envFile:".env{.local,.development,.production}",bootstrapEntry:"bootstrap.ts",bootstrapCompiled:"bootstrap.mjs",entryPoints:"**/{route,middleware,validation}.ts",identityPoints:"**/__identity.mjs",middlewarePoints:"**/middleware.mjs",routeFile:"route.{mjs,cjs,js,ts}",middlewareFile:"middleware.{mjs,cjs,js,ts}"},N={env:/^\.env(?:\.[a-z-_]*)?$/,config:/^intrest\.config\.[mc]?js$/,bootstrap:/^bootstrap\.ts$/,entry:/(?:^|\/)(?:route|middleware|validation)\.ts$/,observable:/(?:route)\.ts$/,reservedChars:/(?:[.*+?^=!:${}()|\[\]\/\\])/g,startSlashesOrNot:/^[\\\/]*/,endSlashesOrNot:/[\\\/]*$/,multiSlashes:/[\\\/]+/g,isBusboyContentType:/^(?:x-www-form-urlencoded|multipart\/form-data.*)$/i,isJSONContentType:/^application\/json$/i,isXMLContentType:/^application\/xml$/i,isAcceptableContentType:/^(?:x-www-form-urlencoded|multipart\/form-data.*|application\/(?:json|xml))$/i},S={compiledFolder:".intrest",compiledRoutes:"routes",workerMultiWorker:"multi.mjs",workerSingleWorker:"single.mjs",workerRouter:"router.mjs",routeIdentity:"__identity.mjs"};import{randomUUID as Re}from"crypto";import{Worker as G}from"worker_threads";import{join as be}from"path";import{glob as ge}from"glob";import{join as we,normalize as ye}from"path";import{pathToFileURL as he}from"url";function w(r){return ye(r).replace(/[\/\\]+/g,"/")}async function k(r){if(!r)return{};let c=he(r);c.searchParams.set("update",Date.now().toString());try{return await import(c.toString()).then(t=>t)||{}}catch{return{}}}async function v(...r){let c=await ge(w(we(...r)),{ignore:["**/node_modules/**"],windowsPathsNoEscape:!0});return c[0]&&w(c[0])}function J(r){return new URL(w(be(".",r)),import.meta.url)}var C=new Map;async function q(r){for(let c=0;c<r;c++){let t=new G(J(S.workerRouter),{env:process.env});t.setMaxListeners(1/0),C.set(t.threadId,{weight:0,worker:t,workerId:t.threadId})}}async function M({basePath:r,data:c,config:t},e){return new Promise((f,h)=>{let s=Re(),g=Array.from(C.values()),i=g.find(o=>o.weight===0),p,O;if(!i&&g.length<(t.limits?.maxWorkerPoolSize||20)){let o=new G(J(S.workerRouter),{env:process.env});o.setMaxListeners(1/0),i={weight:0,worker:o,workerId:o.threadId},C.set(o.threadId,i)}else i||(i=g.reduce((o,I)=>o.weight<I.weight?o:I));i.weight++,p=i.worker,O=i.workerId;let u=o=>{C.delete(O),p.off("exit",u),h(new Error(`Worker stopped with exit code ${o}`))};p.once("exit",u);let T=o=>{h(o),i&&i.weight--,p.off("error",T),p.off("exit",u)};p.once("error",T);let R=o=>{o.requestId===s&&(e(o.state,o.data),o.state==="end"&&(i&&i.weight--,p.off("message",R),p.off("error",T),p.off("exit",u),f()))};p.on("message",R),p.postMessage({data:c,basePath:r,config:t,requestId:s})})}import Te from"busboy";import $ from"chalk";import Ee from"concat-stream";import U from"cookie";import{randomUUID as xe}from"crypto";import{XMLParser as ke,XMLValidator as ve}from"fast-xml-parser";import{createWriteStream as Ae,rmSync as Oe}from"fs";import{StatusCodes as y,getReasonPhrase as Ie}from"http-status-codes";import K from"lodash";import Z from"ms";import{join as ee}from"path";import{performance as te}from"perf_hooks";import{createDeflate as et,createGunzip as tt,createGzip as rt,createInflate as ot,deflate as nt,gunzip as Pe,gzip as st,inflate as Se}from"zlib";function Q(r){if(typeof r!="string")return r;let[,c,t]=r.match(/^(\d+)([kmgt]b?)$/i)||[];if(!c||!t)return 0;let e=parseInt(c);if(isNaN(e))return 0;switch(t.toLowerCase()){case"tb":return e*1024*1024*1024*1024;case"gb":return e*1024*1024*1024;case"mb":return e*1024*1024;case"kb":return e*1024;default:return e}}function X(r){switch(!0){case r==null:return;case/^(no|n|false|f|off)$/i.test(r):return!1;case/^(yes|y|true|t|on)$/i.test(r):return!0;case!isNaN(parseFloat(r)):return parseFloat(r);default:return r}}async function Y(r,c=["identity"]){let t=r;for(let e of c)/^gzip$/i.test(e)?t=await new Promise((f,h)=>{Pe(t,(s,g)=>{if(s)return h(s);f(g)})}):/^deflate$/i.test(e)&&(t=await new Promise((f,h)=>{Se(t,(s,g)=>{if(s)return h(s);f(g)})}));return t}function A(r,c,t,e=200){console.debug("%s(%s - %s) - %s %s",$.yellow(c),$.green(e),Ie(e),$.bold(t),$.cyan(`${(te.now()-r).toPrecision(5)}ms`))}function F(r){return async function(t,e){let f=process.cwd(),h=await v(f,P.configFile),s=(await k(h)).default||{},g=w(ee(f,s.paths?.uploadTemp||".tmp")),i=t.method?.toUpperCase()||"GET",[p,O]=(t.url||"/").split("?"),u=decodeURIComponent(p),T=O||"",R=t.headers["content-type"]||"application/json",o=t.headers.origin||t.headers.host||"",I=t.socket.remoteAddress,ne=o.replace(/^[a-z]+:\/\//,""),_=/^[a-z]+:\/\//.test(o)?o:o.includes("localhost")||b()?`http://${o||"localhost"}`:o?`https://${o}`:"*";if(s.limits?.allowOrigin&&!b()){let m=(Array.isArray(s.limits.allowOrigin)?s.limits.allowOrigin:[s.limits.allowOrigin]).map(n=>n.replace(/^[a-z]+:\/\//,"")).find(n=>ne.endsWith(n));m?e.setHeader("Access-Control-Allow-Origin",m):e.setHeader("Access-Control-Allow-Origin","*")}else e.setHeader("Access-Control-Allow-Origin",_);e.setHeader("Server","IntREST"),e.setHeader("Accept",["application/json","application/xml","x-www-form-urlencoded","multipart/form-data"]),e.setHeader("Accept-Encoding",["gzip","x-gzip","deflate","identity"]),e.setHeader("Access-Control-Allow-Methods",["GET","POST","PUT","PATCH","DELETE","OPTIONS"]),e.setHeader("Access-Control-Allow-Headers",["Content-Length","Content-Type","Authorization","Range","*",...s.limits?.allowHeaders||[]]),e.setHeader("Access-Control-Allow-Credentials","true"),e.setHeader("Access-Control-Max-Age","86400"),e.setHeader("Accept-Ranges","bytes"),e.setHeader("Connection","keep-alive"),e.setHeader("Keep-Alive",["timeout=5","max=30"]);let E=te.now();if(/^options$/i.test(i)){e.statusCode=y.NO_CONTENT,e.end();return}if(!N.isAcceptableContentType.test(R))return e.writeHead(y.UNSUPPORTED_MEDIA_TYPE,{"Content-Type":"application/json"}),A(E,i,u,y.UNSUPPORTED_MEDIA_TYPE),e.end(JSON.stringify({message:s.messages?.UNSUPPORTED_MEDIA_TYPE||"Unsupported media type"}));let x={},se=t.headers["content-length"]&&parseInt(t.headers["content-length"])||0,ie=Q(s.limits?.bodyMaxSize||"10mb");if(se>ie)return e.writeHead(y.REQUEST_TOO_LONG,{"Content-Type":"application/json"}),A(E,i,u,y.REQUEST_TOO_LONG),e.end(JSON.stringify({message:s.messages?.REQUEST_TOO_LONG||"Request entity too large"}));let z=[];if(!/^get$/i.test(i))try{if(N.isBusboyContentType.test(R))await new Promise((l,m)=>{let n=Te({headers:t.headers});n.on("file",(a,d,ce)=>{let{filename:le,encoding:pe,mimeType:me}=ce,ue=xe(),j=w(ee(g,ue)),de={absolutePath:j,filename:le,encoding:pe,mimetype:me};K.set(x,a,de),z.push(j);let fe=Ae(j,{flags:"w"});d.pipe(fe,{end:!0})}),n.on("field",(a,d)=>{K.set(x,a,X(d))}),n.on("close",l),n.on("error",m),t.pipe(n,{end:!0})});else{let l=await new Promise(a=>{let d=Ee(a);t.pipe(d)}),m=t.headers["content-encoding"]||"identity",n=(await Y(l,m.split(/, */))).toString()||"{}";if(N.isJSONContentType.test(R))x=JSON.parse(n);else{let a=new ke({ignoreAttributes:!1,allowBooleanAttributes:!0,attributeNamePrefix:"",attributesGroupName:"$attributes",commentPropName:"$comment",cdataPropName:"$cdata",textNodeName:"$text",alwaysCreateTextNode:!0,parseTagValue:!0,unpairedTags:["meta","link","img","br","hr","input"]});if(!ve.validate(n))throw new Error("Invalid XML");x=a.parse(n)}}}catch(l){return e.writeHead(y.BAD_REQUEST,{"Content-Type":"application/json"}),A(E,i,u,y.BAD_REQUEST),e.end(JSON.stringify({message:"Invalid body",error:l.message||l.toString()}))}let ae=U.parse(t.headers.cookie||"");try{await r({basePath:f,config:s,data:{method:i,path:u,custom:{},headers:t.headers,cookies:ae,body:x,query:T,origin:{url:_==="*"?void 0:new URL(_),ip:I}}},(l,m)=>{if(l==="cookie"){let{name:n,value:a,options:d}=m;d?.maxAge&&typeof d?.maxAge=="string"&&(d.maxAge=Z(d.maxAge)),e.setHeader("Set-Cookie",U.serialize(n,a,d))}else if(l==="clear-cookie"){let{name:n,options:a}=m;a?.maxAge&&typeof a?.maxAge=="string"&&(a.maxAge=Z(a.maxAge)),e.setHeader("Set-Cookie",U.serialize(n,"",a))}else if(l==="set"){let[n,a]=m;e.setHeader(n,a||"")}else if(l==="write"){let n=m;e.write(n)}else if(l==="status")e.statusCode=m;else if(l==="end"){if(z.length&&s.removeUploadFilesAfterResponse)for(let n of z)try{Oe(n)}catch(a){console.error(`Error removing file ${n}`,a.message)}A(E,i,u,e.statusCode),e.end()}})}catch(l){return console.error(l),e.writeHead(y.INTERNAL_SERVER_ERROR,{"Content-Type":"application/json"}),A(E,i,u,y.INTERNAL_SERVER_ERROR),e.end(JSON.stringify({message:s.messages?.INTERNAL_SERVER_ERROR||"Internal server error"}))}}}var V=process.cwd(),je=await v(V,P.configFile),H=(await k(je)).default||{},Me=await v(V,S.compiledFolder,S.compiledRoutes,P.bootstrapCompiled),re=await k(Me),B=re.bootstrap||re.default;B&&typeof B=="function"&&(console.log(` Bootstrapping... `),await B(H));var D=H.port||+(process.env.PORT||4e3),W=w(ze(V,H.paths?.uploadTemp||".tmp"));Ce(W)&&De(W,{recursive:!0});$e(W,{recursive:!0});q(H.limits?.minWorkerPoolSize||5);var oe=Ne.generate(),Ue=b()?He({cert:oe.cert,key:oe.private,keepAlive:!0,keepAliveInitialDelay:5e3},F(M)):_e(F(M));Ue.listen(D,()=>{console.log(` Server running on port %s`,L.yellow(D)),console.log(` You can access the server at %s or %s `,L.yellow(`https://localhost:${D}`),L.yellow(`https://127.0.0.1:${D}`))}); //# sourceMappingURL=v2-multi.mjs.map