UNPKG

@vulppi/intrest

Version:
7 lines (6 loc) 14.8 kB
import Y from"chalk";import{certificateFor as Ze}from"devcert";import{existsSync as qe,mkdirSync as et,rmSync as tt}from"fs";import{createSecureServer as ot,createServer as rt}from"http2";import{join as nt}from"path";var v=()=>process.env.NODE_ENV==="development",E={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}"},L={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},b={compiledFolder:".intrest",compiledRoutes:"routes",workerMultiWorker:"multi.mjs",workerSingleWorker:"single.mjs",workerRouter:"router.mjs",routeIdentity:"__identity.mjs"};import{glob as V}from"glob";import{join as G,normalize as Ce}from"path";import{pathToFileURL as Oe}from"url";function f(e){return Ce(e).replace(/[\/\\]+/g,"/")}async function _(e){if(!e)return{};let n=Oe(e);n.searchParams.set("update",Date.now().toString());try{return await import(n.toString()).then(o=>o)||{}}catch{return{}}}async function N(...e){let n=await V(f(G(...e)),{ignore:["**/node_modules/**"],windowsPathsNoEscape:!0});return n[0]&&f(n[0])}async function k(...e){return(await V(f(G(...e)),{ignore:["**/node_modules/**"],windowsPathsNoEscape:!0})).map(f)}async function ve(...e){let n=e.map(t=>f(G(...t)));return(await V(n.reverse(),{ignore:["**/node_modules/**"],windowsPathsNoEscape:!0})).map(f)}async function oe(e,n){return(await ve(...n.map(o=>[e,o])))[0]||n[1]}function H(e){return v()?`${e}?update=${Date.now()}`:e}import _e from"busboy";import I from"chalk";import je from"concat-stream";import W from"cookie";import{randomUUID as Fe}from"crypto";import{XMLParser as De,XMLValidator as Le}from"fast-xml-parser";import{createWriteStream as ke,rmSync as He}from"fs";import{StatusCodes as A,getReasonPhrase as Ie}from"http-status-codes";import se from"lodash";import ie from"ms";import{join as ce}from"path";import{performance as le}from"perf_hooks";import{createDeflate as gt,createGunzip as ht,createGzip as yt,createInflate as wt,deflate as Rt,gunzip as Ne,gzip as Tt,inflate as $e}from"zlib";function re(e){if(typeof e!="string")return e;let[,n,o]=e.match(/^(\d+)([kmgt]b?)$/i)||[];if(!n||!o)return 0;let t=parseInt(n);if(isNaN(t))return 0;switch(o.toLowerCase()){case"tb":return t*1024*1024*1024*1024;case"gb":return t*1024*1024*1024;case"mb":return t*1024*1024;case"kb":return t*1024;default:return t}}function ne(e){switch(!0){case e==null:return;case/^(no|n|false|f|off)$/i.test(e):return!1;case/^(yes|y|true|t|on)$/i.test(e):return!0;case!isNaN(parseFloat(e)):return parseFloat(e);default:return e}}async function ae(e,n=["identity"]){let o=e;for(let t of n)/^gzip$/i.test(t)?o=await new Promise((a,d)=>{Ne(o,(r,c)=>{if(r)return d(r);a(c)})}):/^deflate$/i.test(t)&&(o=await new Promise((a,d)=>{$e(o,(r,c)=>{if(r)return d(r);a(c)})}));return o}function j(e,n,o,t=200){console.debug("%s(%s - %s) - %s %s",I.yellow(n),I.green(t),Ie(t),I.bold(o),I.cyan(`${(le.now()-e).toPrecision(5)}ms`))}function J(e){return async function(o,t){let a=process.cwd(),d=await N(a,E.configFile),r=(await _(d)).default||{},c=f(ce(a,r.paths?.uploadTemp||".tmp")),i=o.method?.toUpperCase()||"GET",[s,l]=(o.url||"/").split("?"),u=decodeURIComponent(s),h=l||"",x=o.headers["content-type"]||"application/json",R=o.headers.origin||o.headers.host||"",C=o.socket.remoteAddress,S=R.replace(/^[a-z]+:\/\//,""),T=/^[a-z]+:\/\//.test(R)?R:R.includes("localhost")||v()?`http://${R||"localhost"}`:R?`https://${R}`:"*";if(r.limits?.allowOrigin&&!v()){let w=(Array.isArray(r.limits.allowOrigin)?r.limits.allowOrigin:[r.limits.allowOrigin]).map(p=>p.replace(/^[a-z]+:\/\//,"")).find(p=>S.endsWith(p));w?t.setHeader("Access-Control-Allow-Origin",w):t.setHeader("Access-Control-Allow-Origin","*")}else t.setHeader("Access-Control-Allow-Origin",T);t.setHeader("Server","IntREST"),t.setHeader("Accept",["application/json","application/xml","x-www-form-urlencoded","multipart/form-data"]),t.setHeader("Accept-Encoding",["gzip","x-gzip","deflate","identity"]),t.setHeader("Access-Control-Allow-Methods",["GET","POST","PUT","PATCH","DELETE","OPTIONS"]),t.setHeader("Access-Control-Allow-Headers",["Content-Length","Content-Type","Authorization","Range","*",...r.limits?.allowHeaders||[]]),t.setHeader("Access-Control-Allow-Credentials","true"),t.setHeader("Access-Control-Max-Age","86400"),t.setHeader("Accept-Ranges","bytes"),t.setHeader("Connection","keep-alive"),t.setHeader("Keep-Alive",["timeout=5","max=30"]);let y=le.now();if(/^options$/i.test(i)){t.statusCode=A.NO_CONTENT,t.end();return}if(!L.isAcceptableContentType.test(x))return t.writeHead(A.UNSUPPORTED_MEDIA_TYPE,{"Content-Type":"application/json"}),j(y,i,u,A.UNSUPPORTED_MEDIA_TYPE),t.end(JSON.stringify({message:r.messages?.UNSUPPORTED_MEDIA_TYPE||"Unsupported media type"}));let O={},ye=o.headers["content-length"]&&parseInt(o.headers["content-length"])||0,we=re(r.limits?.bodyMaxSize||"10mb");if(ye>we)return t.writeHead(A.REQUEST_TOO_LONG,{"Content-Type":"application/json"}),j(y,i,u,A.REQUEST_TOO_LONG),t.end(JSON.stringify({message:r.messages?.REQUEST_TOO_LONG||"Request entity too large"}));let U=[];if(!/^get$/i.test(i))try{if(L.isBusboyContentType.test(x))await new Promise((g,w)=>{let p=_e({headers:o.headers});p.on("file",(m,P,Te)=>{let{filename:Pe,encoding:be,mimeType:Ee}=Te,Se=Fe(),B=f(ce(c,Se)),Ae={absolutePath:B,filename:Pe,encoding:be,mimetype:Ee};se.set(O,m,Ae),U.push(B);let xe=ke(B,{flags:"w"});P.pipe(xe,{end:!0})}),p.on("field",(m,P)=>{se.set(O,m,ne(P))}),p.on("close",g),p.on("error",w),o.pipe(p,{end:!0})});else{let g=await new Promise(m=>{let P=je(m);o.pipe(P)}),w=o.headers["content-encoding"]||"identity",p=(await ae(g,w.split(/, */))).toString()||"{}";if(L.isJSONContentType.test(x))O=JSON.parse(p);else{let m=new De({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(!Le.validate(p))throw new Error("Invalid XML");O=m.parse(p)}}}catch(g){return t.writeHead(A.BAD_REQUEST,{"Content-Type":"application/json"}),j(y,i,u,A.BAD_REQUEST),t.end(JSON.stringify({message:"Invalid body",error:g.message||g.toString()}))}let Re=W.parse(o.headers.cookie||"");try{await e({basePath:a,config:r,data:{method:i,path:u,custom:{},headers:o.headers,cookies:Re,body:O,query:h,origin:{url:T==="*"?void 0:new URL(T),ip:C}}},(g,w)=>{if(g==="cookie"){let{name:p,value:m,options:P}=w;P?.maxAge&&typeof P?.maxAge=="string"&&(P.maxAge=ie(P.maxAge)),t.setHeader("Set-Cookie",W.serialize(p,m,P))}else if(g==="clear-cookie"){let{name:p,options:m}=w;m?.maxAge&&typeof m?.maxAge=="string"&&(m.maxAge=ie(m.maxAge)),t.setHeader("Set-Cookie",W.serialize(p,"",m))}else if(g==="set"){let[p,m]=w;t.setHeader(p,m||"")}else if(g==="write"){let p=w;t.write(p)}else if(g==="status")t.statusCode=w;else if(g==="end"){if(U.length&&r.removeUploadFilesAfterResponse)for(let p of U)try{He(p)}catch(m){console.error(`Error removing file ${p}`,m.message)}j(y,i,u,t.statusCode),t.end()}})}catch(g){return console.error(g),t.writeHead(A.INTERNAL_SERVER_ERROR,{"Content-Type":"application/json"}),j(y,i,u,A.INTERNAL_SERVER_ERROR),t.end(JSON.stringify({message:r.messages?.INTERNAL_SERVER_ERROR||"Internal server error"}))}}}import{createReadStream as We}from"fs";import{StatusCodes as F}from"http-status-codes";import ue from"lodash";import{lookup as Je}from"mime-types";import{join as D}from"path";import{unescape as Ke}from"querystring";import{pathToFileURL as Q}from"url";import{StatusCodes as K}from"http-status-codes";import de from"lodash";import Ve from"range-parser";import{Readable as Ge}from"stream";import{isAnyArrayBuffer as ze,isUint16Array as Me,isUint32Array as Ue,isUint8Array as Be}from"util/types";function pe(e){return!!(ze(e)||Be(e)||Me(e)||Ue(e))}function z(e){return!!(e&&Array.isArray(e)&&e.length&&e.type==="bytes")}async function me(e,n,o,t){let a=Object.keys(e.headers||{}).find(s=>/^content-length$/i.test(s)),d=Object.keys(e.headers||{}).find(s=>/^content-type$/i.test(s)),r=de.get(e.headers||{},a||"Content-Length",1/0),c=de.get(e.headers||{},d||"Content-Type"),i=n.range?Ve(+r,n.range,{combine:!0}):void 0;z(i)&&(e.status=!e.status||e.status===K.OK?K.PARTIAL_CONTENT:e.status,e.headers={...e.headers,"Content-Range":`bytes ${i[0].start}-${i[0].end}`+(r&&isFinite(+r)?`/${r}`:"")},delete e.headers[a||"Content-Length"]);for(let s of Object.entries(e.headers||{}))t({requestId:o,state:"set",data:s});for(let[s,l]of Object.entries(e.cookies||{}))if(Array.isArray(l))for(let u of l)t({requestId:o,state:"cookie",data:{name:s,value:u.value,options:u.options}});else t({requestId:o,state:"cookie",data:{name:s,value:l.value,options:l.options}});for(let[s,l]of Object.entries(e.clearCookies||{}))if(Array.isArray(l))for(let u of l)t({requestId:o,state:"clear-cookie",data:{name:s,options:u}});else t({requestId:o,state:"clear-cookie",data:{name:s,options:l}});if(t({requestId:o,state:"status",data:e.status||K.OK}),e.body)if(typeof e.body=="string"||pe(e.body)){c||t({requestId:o,state:"set",data:["Content-Type","text/plain"]});let s=Buffer.from(e.body);z(i)?t({requestId:o,state:"write",data:s.subarray(i[0].start,i[0].end+1)}):t({requestId:o,state:"write",data:s})}else if(e.body instanceof Ge){c||t({requestId:o,state:"set",data:["Content-Type","application/octet-stream"]});let s=e.body;if(z(i)){let l=i[0].start,u=i[0].end,h=0;await new Promise((x,R)=>{s.on("data",C=>{let S=Buffer.from(C);if(S.length+h<l){h+=S.length;return}if(h>u)return s.destroy(),x();let T=Math.max(l-h,0),y=Math.min(u+1-h,S.length);h+=y;let O=S.subarray(T,T+y);t({requestId:o,state:"write",data:O})}),s.on("end",()=>{x()}),s.on("error",C=>{R(C)})})}else await new Promise((l,u)=>{s.on("data",h=>{t({requestId:o,state:"write",data:h})}),s.on("end",()=>{l()}),s.on("error",h=>{u(h)})})}else{c||t({requestId:o,state:"set",data:["Content-Type","application/json"]});let s=JSON.stringify(e.body),l=Buffer.from(s);z(i)?t({requestId:o,state:"write",data:l.subarray(i[0].start,i[0].end+1)}):t({requestId:o,state:"write",data:l})}t({requestId:o,state:"end",data:void 0})}async function X({data:e,config:n,basePath:o},t){let a={...e,params:{},query:new URLSearchParams(e.query||"")},d=await oe(o,E.staticFolder);if(d){let r=await N(d,a.path);if(r){let c=Je(r);if(c)return await $({status:F.OK,body:We(r),headers:{"Content-Type":c}},a.headers,t)}}try{let r=await Qe(a.path);if(!r.length)return await $({status:F.NOT_FOUND,body:{message:n.messages?.NOT_FOUND||"Not found"},headers:{"Content-Type":"application/json"}},a.headers,t);let c=a.method,i=f(D(b.compiledFolder,b.compiledRoutes)),l=(await Promise.all(r.map(async T=>{let y=await import(H(Q(f(D(i,T.pathname,"route.mjs"))).toString()));return{handler:y[c]||y.ALL||y.default,identity:T}}))).find(T=>typeof T.handler=="function");if(!l?.handler)return await $({status:F.METHOD_NOT_ALLOWED,body:{message:n.messages?.METHOD_NOT_ALLOWED||"Method not allowed"},headers:{"Content-Type":"application/json"}},a.headers,t);let u=l.identity.paramExtract,h=l.identity.pathname,x=l.identity.paramKeys,R=Array.from(e.path.match(u)||[]).slice(1);a.params=ue.zipObject(x,R.map(Ke));let C=await Xe(h),S=await fe({middlewares:C,context:a,config:n,requestHandler:l.handler});if(!S)throw new Error("Response not found");return await $(S,a.headers,t)}catch(r){if(console.error(r),r instanceof Error)return await $({status:F.INTERNAL_SERVER_ERROR,body:{message:r.message},headers:{"Content-Type":"application/json"}},a.headers,t);if(typeof r=="object"&&r!=null)return await $(r,a.headers,t);throw r}}async function $(e,n,o){return await me(e,n,"void",t=>{let{state:a,data:d}=t;o(a,d)})}async function Qe(e){let n=f(D(process.cwd(),b.compiledFolder,b.compiledRoutes)),o=await k(n,E.identityPoints);return(await Promise.all(o.map(a=>import(H(Q(a).toString())).then(d=>d)))).filter(a=>a.paramExtract.test(e)).sort((a,d)=>a.pathname>d.pathname?1:-1).sort(Ye)}async function Xe(e){let n=f(D(process.cwd(),b.compiledFolder,b.compiledRoutes)),o=e.split("/").map((r,c,i)=>c>0?i.slice(0,c+1).join("/"):"/").map(r=>f(D(n,r,"middleware.mjs"))),a=(await k(n,E.middlewarePoints)).filter(r=>o.some(c=>r===c));return(await Promise.all(a.map(async r=>({handler:await import(H(Q(r).toString())).then(c=>c.middleware||c.default),pathname:r.replace(n,"")})))).filter(r=>typeof r.handler=="function")}function Ye(e,n){let o=e.pathname.split("/"),t=n.pathname.split("/");for(let a=0;a<o.length;a++)if(!(o[a][0]==="["&&t[a]?.[0]==="[")){if(o[a][0]==="[")return 1;if(t[a]?.[0]==="[")return-1}return n.route.toLowerCase()>e.route.toLowerCase()?-1:n.route.toLowerCase()<e.route.toLowerCase()?1:0}async function fe({middlewares:e,context:n,config:o,requestHandler:t}){if(!e.length)return await t(n)||{status:F.NOT_FOUND};let a=e[0],d=setTimeout(()=>{throw new Error(`Middleware handler timeout: ${a.pathname}`)},o.limits?.middleware?.timeout||5e3),r=await a.handler(n,async c=>(clearTimeout(d),n.custom=ue.merge(n.custom,c),fe({middlewares:e.slice(1),context:n,config:o,requestHandler:t})));return clearTimeout(d),r}var ee=process.cwd(),at=await N(ee,E.configFile),te=(await _(at)).default||{},st=await N(ee,b.compiledFolder,b.compiledRoutes,E.bootstrapCompiled),ge=await _(st),Z=ge.bootstrap||ge.default;Z&&typeof Z=="function"&&(console.log(` Bootstrapping... `),await Z(te));var M=te.port||+(process.env.PORT||4e3),q=f(nt(ee,te.paths?.uploadTemp||".tmp"));qe(q)&&tt(q,{recursive:!0});et(q,{recursive:!0});var he=await Ze(["localhost"]),it=v()?ot({cert:he.cert,key:he.key,keepAlive:!0,keepAliveInitialDelay:5e3},J(X)):rt(J(X));it.listen(M,()=>{console.log(` Server running on port %s`,Y.yellow(M)),console.log(` You can access the server at %s or %s `,Y.yellow(`https://localhost:${M}`),Y.yellow(`https://127.0.0.1:${M}`))}); //# sourceMappingURL=v2-single.mjs.map