rtjscomp 0.9.7 → 0.9.8

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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/package.json +1 -1
  3. package/rtjscomp.js +41 -41
package/README.md CHANGED
@@ -44,6 +44,7 @@ it is only needed if you want to change default settings. it has the following p
44
44
  - `type_dynamics`: dynamic file types, see [api](#api)
45
45
  - `type_mimes`: file type to mime type map (most common are already set, only overrides)
46
46
  - `type_raws`: array of file types that are sent uncompressed
47
+ - `upload_limit`: max upload size in mebibytes, default is 10
47
48
  - `zstd_level`: compression level for zstd, 0-19, default is 3
48
49
 
49
50
  here is an example for a customized setup:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rtjscomp",
3
- "version": "0.9.7",
3
+ "version": "0.9.8",
4
4
  "description": "php-like server but with javascript",
5
5
  "repository": {
6
6
  "type": "git",
package/rtjscomp.js CHANGED
@@ -2,44 +2,44 @@
2
2
  "use strict";/*
3
3
  RTJSCOMP by L3P3, 2017-2025
4
4
  */
5
- (async()=>{const E=require("fs"),H=require("fs/promises"),ya=require("http"),Ta=require("url"),N=require("zlib"),ia={level:9},za=null!=N.createBrotliCompress,Aa=null!=N.createZstdCompress,Ba=/,\s*/,ja=/\bimport\(/g;var F="undefined"!==typeof Bun;const Ua=/:([0-9]+)[\):]/,Ca={paths:[require("path").resolve()]},Va=/\bservice_require\(([^)]*)\)/g,ka={persistent:!0,interval:1E3},Da={params:{[100]:3}},Ea=process.argv.includes("-v");let t=Ea,O=0,P=0,X=!0,Q=!1;const Y=new Map([["","index.html"]]),R=new Map([["index.html",
6
- "/"]]),S=new Map,la=new Set,ma=new Set,na=new Set,oa=new Set(["events","html","json","txt"]),pa=new Map([["apk","application/zip"],["bpg","image/bpg"],["css","text/css; charset=utf-8"],["events","text/event-stream"],["flac","audio/flac"],["gz","application/gzip"],["hta","application/hta"],["html","text/html; charset=utf-8"],["ico","image/x-icon"],["jpg","image/jpeg"],["js","text/javascript; charset=utf-8"],["json","application/json; charset=utf-8"],["mid","audio/midi"],["mp3","audio/mpeg3"],["pdf",
7
- "application/pdf"],["png","image/png"],["rss","application/rss+xml; charset=utf-8"],["txt","text/plain; charset=utf-8"],["xml","application/xml; charset=utf-8"],["xz","application/x-xz"],["zip","application/zip"]]),Z=new Set("apk bpg flac gz jpg mp3 pdf png xz zip".split(" ")),aa=new Map,q={},G=global.rtjscomp={actions:q,version:"0.9.7"};Object.fromEntries||(Object.fromEntries=a=>{const b={};for(const c of a)b[c[0]]=c[1];return b});let T=E.watch;if(F){const a=T,b=new Map;T=(c,f,k)=>{b.has(c)||a(c,
8
- f,()=>{const m=b.get(c);m&&m()});b.set(c,k);return{close:()=>b.set(c,null)}}}global.globals=G;global.actions=G.actions;global.data_load=a=>{d("[deprecated] synchronous load file: data/"+a);try{return E.readFileSync("data/"+a,"utf8")}catch(b){return null}};global.data_save=(a,b)=>(d("[deprecated] synchronous save file: data/"+a),E.writeFileSync("data/"+a,b,"utf8"));global.number_check_int=a=>Math.floor(a)===a;global.number_check_uint=a=>0<=a&&number_check_int(a);G.data_load=async a=>{t&&d("load file: data/"+
9
- a);const b=await H.readFile("data/"+a,"utf8").catch(()=>null);return a.endsWith(".json")?JSON.parse(b||null):b};G.data_load_watch=(a,b)=>qa("data/"+a,c=>b(a.endsWith(".json")?JSON.parse(c||null):c));G.data_save=(a,b)=>(t&&d("save file: data/"+a),H.writeFile("data/"+a,a.endsWith(".json")?JSON.stringify(b):b,"utf8"));const Fa=a=>{try{return`:${a.stack.split("\n",2)[1].split(",").pop().match(Ua)[1]-2}`}catch(b){return""}},Ga=new Set,ra=new Map,sa=new Map,ta=a=>{var b=ra.get(a);if(null!=b)return b;t&&
10
- d("require module: "+a);b=require.resolve(a,Ca);Ga.add(b);ra.set(a,b=require(b));return b},ua=async a=>{let b=sa.get(a);if(null!=b)return b;t&&d("import module: "+a);sa.set(a,b=await import("file://"+require.resolve(a,Ca)));return b};q.module_cache_clear=()=>{for(const a of Ga)delete require.cache[a];ra.clear();sa.clear()};const va=ua.constructor,I=new Map;let U=null,wa=null;const Wa=async a=>{await Promise.all([...I.values()].filter(c=>4>c.status&&!a.includes(c.path)).map(c=>(c.dependencies=
11
- null,c)).map(Ha));const b=[];for(const c of a){let f=I.get(c);if(null==f)I.set(c,f={content:null,dependencies:null,x0:null,x1:null,x2:null,path:c,x5:null,x4:null,x7:null,x6:null,status:0,x8:null});else if(4>f.status)continue;b.push(f)}await Promise.all(b.map(ba))},Xa=()=>Promise.all([...I.values()].map(a=>(a.dependencies=null,a)).map(Ha)),ba=async a=>{U||(U=new Promise(m=>{wa=m}));const {path:b}=a;t&&d(b+": prepare for (re)start");let c=0;try{if(1===a.status||2===a.status)t&&d(b+": abort previous start"),
12
- a.status=0,a.x4&&a.x4();else if(3===a.status){a.status=0;for(var f of I.values())(2===f.status||3===f.status)&&f.dependencies&&f.dependencies.includes(a)&&(f.dependencies=null,ba(f));Ia(a)}await a.x7;3<a.status&&(a.status=0);a.x7=new Promise(l=>{a.x6=l});if(!a.x1){f="public/"+b+".service.js";var k=await H.readFile(f,"utf8");if(0!==a.status)return;if(!a.x8){let l=0;a.x8=T(f,ka,()=>(clearTimeout(l),l=setTimeout(()=>(t&&d("file updated: "+b),a.x1=null,ba(a)),50)))}k.includes("globals.")&&d(`[deprecated] ${b}: uses globals object`);
13
- a.x0=[];for(let [,l]of k.matchAll(Va)){const u=l.charCodeAt(0),v=l.charCodeAt(l.length-1);if(3>l.length||!(34===u&&34===v||39===u&&39===v))throw Error("service_require() needs inline string");a.x0.includes(l=l.slice(1,-1))||a.x0.push(l)}a.x1=new va("require","custom_import","service_require","service_require_try",`const log=a=>rtjscomp.log(${JSON.stringify(b+": ")}+a);${k.replace(ja,"custom_import(")}`)}a.dependencies=[];k=!1;for(const l of a.x0){const u=I.get(l);if(null==u)throw Error("unknown required service: "+
14
- l);a.dependencies.push(u);k=k||3!==u.status}if(k&&(t&&d(b+": wait for dependencies"),a.status=1,a.x5=new Promise(l=>{a.x4=l}),await a.x5,1!==a.status))return;d("start service: "+b);a.status=2;c=setInterval(()=>{d(`[warning] ${b}: still starting`)},5E3);const m=a.content={},g=await a.x1.call(m,ta,ua,Ja,Ka);if(2!==a.status)return;"function"===typeof g&&(a.x2=g);const p=m.start;if(p&&(d(`[deprecated] ${b}: has start method`),delete m.start,await p(),2!==a.status))return;m.stop&&(d(`[deprecated] ${b}: has stop method`),
15
- a.x2=m.stop,delete m.stop);t&&d("started service: "+b);a.status=3}catch(m){m instanceof Error||(m=Error(m+"?! wtf"));d(`[error] ${b}${Fa(m)}: ${m.message}`);a.status=5;a.dependencies=null;return}finally{clearInterval(c),a.x5=a.x4=null,3!==a.status&&(a.x6(),La())}a:for(const m of I.values())if(1===m.status){for(const g of m.dependencies)if(3!==g.status)continue a;m.x4()}La()},La=()=>{if(U){for(const a of I.values())if(3>a.status)return;wa();U=wa=null}},Ha=async a=>{d("stop service: "+a.path);a.status=
16
- 4;a.x1=null;a.x8&&a.x8.close();for(const b of I.values())b.dependencies&&b.dependencies.includes(a)&&(b.dependencies=null,4!==b.status&&ba(b));a.x4?a.x4():await Ia(a);I.delete(a.path);t&&d("stopped service: "+a.path)},Ia=async a=>{const {x2:b,path:c}=a;if(b){a.x2=null;const f=setInterval(()=>{d(`[warning] ${c}: still stopping`)},1E3);try{await b()}catch(k){d(`[error] ${c}${Fa(k)} stop handler: ${k.message}`),a.status=5}clearInterval(f)}a.x6()},Ja=a=>{const b=I.get(a);if(null!=b&&3===b.status)return b.content;
17
- throw Error("service required: "+a);},Ka=a=>{a=I.get(a);return null!=a&&3===a.status?a.content:null},Ya=(a,b)=>{const c=T(a,ka,()=>(c.close(),t&&d("file updated: "+a),b()))},qa=async(a,b)=>{try{const f=await H.readFile(a,"utf8");t&&d("load file: "+a);await b(f)}catch(f){return await b(null),null}let c=0;return T(a,ka,()=>(clearTimeout(c),c=setTimeout(()=>Q||(t&&d("file updated: "+a),H.readFile(a,"utf8").catch(()=>null).then(b)),50)))},Ma=(a,b,c)=>{if(null===a||!(b in a))return c;c=a[b];if("boolean"!==
18
- typeof c)throw b+" must be boolean";delete a[b];return c},ca=(a,b,c)=>{if(null===a||!(b in a))return c;c=a[b];if("number"!==typeof c||0>c||0<c%1)throw b+" must be positive integer";delete a[b];return c},L=(a,b)=>{if(null===a||!(b in a))return null;const c=a[b];if("object"!==typeof c||!c||null==c.length||c.some(f=>"string"!==typeof f))throw b+" must be array of strings";delete a[b];return c},Na=(a,b)=>{if(null===a||!(b in a))return null;let c=a[b];if("object"!==typeof c||!c||(c=Object.entries(c)).some(([,
19
- f])=>"string"!==typeof f))throw b+" must be object of strings";delete a[b];return c};var K=a=>a.split("\n").filter(b=>0<b.length&&35!==b.charCodeAt(0));const Oa=a=>Object.fromEntries(a.split("\n").filter(b=>0<b.length&&35!==b.charCodeAt(0)).map(b=>b.split(":",2))),M=(a,b=!1)=>{if(!b&&!a)throw"path is empty";if(47===a.charCodeAt(0))throw"path must not start with /";if(47===a.charCodeAt(a.length-1))throw"path must not end with /";if(a.includes(".."))throw"path must not contain ..";if(a.includes("~"))throw"path must not contain ~";
20
- if(a.includes("//"))throw"path must not contain //";};let Pa=G.log_history=[];q.log_clear=()=>{Pa=G.log_history=[]};const d=G.log=a=>(console.log(a),Pa.push(a),V?da("log",[a]):void 0),V=E.existsSync("spam.csv");G.spam_history="";q.spam_save=async(a=!1)=>{if(V)try{const b=G.spam_history;G.spam_history="";await H.appendFile("spam.csv",b,"utf8");t&&!a&&d("spam.csv saved")}catch(b){d("[error] cannot save spam.csv: "+b.message)}};const da=(a,b)=>{G.spam_history+=Date.now()+","+a+","+JSON.stringify(b)+
21
- "\n";1E5<=G.spam_history.length&&q.spam_save()},Za=(a,b,c)=>{b=Buffer.from(b);34===b[0]&&(b=b.subarray(1,-1));const f=b.length,k=f+4,m=a.length-k;var g=0;let p=0;for(;0<=(p=a.indexOf(45,p))&&p<=m;)if(45!==a[p+1]||0<p&&13!==a[p-2]||0<p&&10!==a[p-1]||0!==a.compare(b,0,f,p+2,p+2+f))++p;else{if(0<g){if(20>p-g)throw"part too short";for(var l=g;0<=(l=a.indexOf(13,l))&&10!==a[l+1]||13!==a[l+2]||10!==a[l+3];)++l;if(0>l)throw"part header end not found";let u="",v="";for(const y of a.toString("utf8",g,l).split("\r\n",
22
- 2)){if(!y.startsWith("Content-"))throw"illegal part header";const [C,r]=y.slice(8).split(": ",2);if("Disposition"===C){if(!r.startsWith("form-data; "))throw"illegal disposition part header";u=r.slice(11)}else if("Type"===C)v=r;else throw"illegal part header";}if(!u)throw"part disposition header missing";let J=g="";for(const y of u.split("; ")){let [C,r]=y.split("=",2);34===r.charCodeAt(0)&&(r=r.slice(1,-1));if("name"===C)g=r;else if("filename"===C)J=r;else throw"illegal disposition part header";}if(!g)throw"part name header missing";
23
- l=v?{filename:J,data:a.subarray(l+4,p-2),type:v}:a.toString("utf8",l+4,p-2);if(g.endsWith("[]"))if(g=g.slice(0,-2),g in c){if(!(c[g]instanceof Array))throw"duplicate part name";c[g].push(l)}else c[g]=[l];else{if(g in c)throw"duplicate part name";c[g]=l}}g=p+k;p=g+1}},xa=(a,b)=>{for(const c of a.split("&")){let [f,k]=c.split("=",2);(a=f.endsWith("[]"))&&(f=f.slice(0,-2));if(!f)throw"key is empty";k=decodeURIComponent(k||"");if(f in b){if(b[f]instanceof Array!==a)throw"type mismatch";a?b[f].push(k):
24
- b[f]=k}else b[f]=a?[k]:k}},Qa=async(a,b,c)=>{const f=a.method,k=a.headers,m=k["x-forwarded-for"]||a.socket.remoteAddress,g="HEAD"===f;"x-forwarded-proto"in k&&(c="https"===k["x-forwarded-proto"]);V&&da("request",[c,a.url,m]);try{const A=Ta.parse(a.url,!1);let h=A.pathname||"/";if(47!==h.charCodeAt(0)||h.includes("//"))throw 404;if(1<h.length&&h.endsWith("/")&&(h=h.slice(0,-1),h.lastIndexOf("/")<h.lastIndexOf(".")))throw b.setHeader("Location",h),301;h=h.slice(1);if(!(h.includes("php")||h.includes("sql")||
25
- h.includes(".git/")||la.has(h))){b.setHeader("Server","l3p3 rtjscomp v0.9.7");b.setHeader("Access-Control-Allow-Origin","*");var p=null,l=null;if(R.has(h))throw b.setHeader("Location",R.get(h)),301;if(Y.has(h))h=Y.get(h);else{var u=h.split("/"),v=S.get(u.shift());if(null!=v)a:for(var J of v){var y=J.x3,C=y.length;if(C===u.length){v={};for(var r=0;r<C;++r)if(42===y[r].charCodeAt(0))1<y[r].length&&(v[y[r].slice(1)]=u[r]);else if(y[r]!==u[r])continue a;h=J.value;p=v;break}}}var B=h.lastIndexOf(".");
26
- if(h.includes("..")||h.includes("~")||B<=h.lastIndexOf("/"))throw 404;var n=h.slice(B+1).toLowerCase();B=0;var D=oa.has(n)&&!na.has(h);if(!g&&"GET"!==f){if(!D)throw 405;"content-length"in k&&(l=new Promise(w=>{const e=[];a.on("data",z=>{e.push(z)});a.on("end",z=>{z&&e.push(z);w(Buffer.concat(e))})}))}J=u=null;y="public/"+h;if(D&&aa.has(h))u=aa.get(h);else{t&&d(`load ${D?"dynam":"stat"}ic file: ${h}`);if(ma.has(h)||h.endsWith(".service.js"))throw 403;if(!E.existsSync(y))throw 404;J=E.statSync(y);if(J.isDirectory())throw 403;
27
- if(D){const w=await H.readFile(y,"utf8");try{if(w.includes("\r"))throw"illegal line break, must be unix";if(w.includes("response.write(")||w.includes("response.end("))throw"response.write() not allowed, use output.write()";w.includes("globals.")&&d(`[deprecated] ${h}: uses globals object`);const e=w.length;let z=`const log=a=>rtjscomp.log(${JSON.stringify(h+": ")}+a);`;C=!1;for(r=v=0;r<e;)if(C){if(0>(r=w.indexOf("?>",v=r+2)))throw'"?>" missing';C=!1;v<r&&(z=61!==w.charCodeAt(v)?z+(w.slice(v,r).replace(ja,
28
- "custom_import(")+";"):z+`output.write(''+(${w.slice(++v,r).replace(ja,"custom_import(")}));`);r+=2}else-1<(r=w.indexOf("<?",v=r))?C=!0:r=e,v<r&&(z+=`output.write(${JSON.stringify(w.slice(v,r))});`);try{u=new va("input","output","request","response","require","custom_import","service_require","service_require_try",z)}catch($a){throw $a.message;}}catch(e){throw d(`[error] ${h} compile: ${e}`),500;}aa.set(h,u);Ya(y,()=>aa.delete(h))}}b.statusCode=200;b.setHeader("Content-Type",pa.get(n)||pa.get("txt"));
29
- if(D){var x=p||{};if(k.cookie)for(let e of k.cookie.split(";")){e=e.trim();const z=e.indexOf("=");0<z?x[e.slice(0,z).trimRight()]=decodeURI(e.slice(z+1).trimLeft()):0>z&&(x[e]=void 0)}if(k["x-input"])try{xa(k["x-input"],x)}catch(e){throw d(`[error] ${h} request x-input: ${e}`),400;}if(A.query)try{xa(A.query,x)}catch(e){throw d(`[error] ${h} request query: ${e}`),400;}if(l)try{const e=a.headers["content-type"]||"",z=x.body=await l;switch(e.split(";",1)[0]){case "application/json":Object.assign(x,JSON.parse(z.toString()));
30
- break;case "application/x-www-form-urlencoded":xa(z.toString(),x);break;case "multipart/form-data":Za(z,e.split("boundary=",2)[1].split(";",1)[0],x)}}catch(e){throw d(`[error] ${h} request body: ${e.message||e}`),400;}x.https=c;x.ip=m;x.method=g?"get":f.toLowerCase();x.path=A.pathname;x.user_agent=k["user-agent"];c=b;b.setHeader("Cache-Control","no-cache, no-store");if(X&&"accept-encoding"in k&&!Z.has(n)){const e=k["accept-encoding"].split(Ba);Aa&&e.includes("zstd")?(B=3,b.setHeader("Content-Encoding",
31
- "zstd"),g||(c=N.createZstdCompress(Da)).pipe(b)):za&&e.includes("br")?(B=2,b.setHeader("Content-Encoding","br"),g||(c=N.createBrotliCompress()).pipe(b)):0<ia.level&&e.includes("gzip")&&(B=1,b.setHeader("Content-Encoding","gzip"),g||(c=N.createGzip(ia)).pipe(b))}V&&da("execute",[h,Object.fromEntries(Object.entries(x).filter(e=>"body"!==e[0]).map(e=>"password"===e[0]?[e[0],"***"]:e).map(e=>"file"===e[0]?[e[0],"..."]:e).map(e=>"object"!==typeof e[1]||e[1].length?e:[e[0],Object.keys(e[1]).slice(0,20)]).map(e=>
32
- "user_agent"!==e[0]&&"string"===typeof e[1]&&20<e[1].length?[e[0],e[1].slice(0,20)+"..."]:e))]);g&&(c.write=c.end=()=>{throw null;});await U;let w;try{w=await u(x,c,a,b,ta,ua,Ja,Ka)}catch(e){e instanceof Error?(d(`[error] ${h}: ${e.message}`),w=e.message.startsWith("service required: ")?503:500):"number"===typeof e?(d(`[deprecated] ${h}: status code thrown, use return instead`),w=e):null!==e&&(d(`[error] ${h}: invalid throw type: ${typeof e}`),w=500)}g&&(delete c.write,delete c.end);if(null!=w){b.headersSent?
33
- (null!=b.writableEnded?b.writableEnded:b.finished)||c.end(`${"html"===n?"<hr>":"\n\n---\n"}ERROR!`):0!==B&&b.removeHeader("Content-Encoding");if("number"!==typeof w)throw d(`[error] ${h}: invalid return type: ${typeof w}`),500;if(b.headersSent&&500>w)throw d(`[error] ${h}: status code after content`),500;throw w;}c.end()}else{x=X&&!Z.has(n);n=y;if(x&&"accept-encoding"in k){const w=k["accept-encoding"].split(Ba);w.includes("zstd")&&E.existsSync(y+".zst")?(B=3,n+=".zst"):w.includes("br")&&E.existsSync(y+
34
- ".br")?(B=2,n+=".br"):w.includes("gzip")&&E.existsSync(y+".gz")&&(B=1,n+=".gz")}V&&da("static_send",[h,B]);b.setHeader("Cache-Control","public, max-age=600");x&&b.setHeader("Vary","Accept-Encoding");switch(B){case 0:b.setHeader("Content-Length",J.size);break;case 1:b.setHeader("Content-Encoding","gzip");break;case 2:b.setHeader("Content-Encoding","br");break;case 3:b.setHeader("Content-Encoding","zstd")}g?b.end():E.createReadStream(n).pipe(b)}}}catch(A){"number"!==typeof A&&(console.error(A),A=500),
35
- (500<=A||t&&400<=A)&&d(`[error] request failed: ${A}; ${m}; ${a.url}`),b.headersSent||(b.writeHead(A,{"Content-Type":"text/html","Cache-Control":"no-cache, no-store"}),b.end(`<!DOCTYPE html><html><body><h1>HTTP ${A}: ${ya.STATUS_CODES[A]||"Error"}</h1></body></html>`))}};q.halt=async()=>{Q=!0;t&&d("stop all");await Promise.all([q.http_stop&&q.http_stop(),q.https_stop&&q.https_stop(),Xa()]);await q.spam_save();d("stopped all")};q.exit=async a=>{Q||("number"!==typeof a&&(a=0),await q.halt(),t&&d("exit"),
36
- process.exit(a))};process.on("uncaughtException",a=>{"symbol"===typeof a&&(a=a.toString());d("[error] uncaughtException: "+(a.message||a));console.error(a);Q&&process.exit(1);q.exit(1)});process.on("unhandledRejection",a=>{d("[error] unhandledRejection: "+(a.message||a));console.error(a);Q&&process.exit(1);q.exit(1)});process.on("exit",q.exit);process.on("SIGINT",q.exit);process.on("SIGUSR2",q.exit);process.on("SIGTERM",q.exit);d(`rtjscomp v${"0.9.7"} in ${F?"bun":"node"} on ${process.platform.replace("win32",
37
- "windows")}`);t&&!za&&d("[hint] brotli not available");t&&!Aa&&d("[hint] zstd not available");await qa("config/init.js",async a=>{if(a){d("[deprecated] run global init script");try{await (new va("require",a))(ta)}catch(b){d("[error] init.js: "+b.message)}}});const [ab,bb,...Ra]=await Promise.all([H.stat("data/").catch(a=>null),H.stat("public/").catch(a=>null),..."file_blocks file_privates file_raws file_type_dyns file_type_mimes file_type_nocompress path_aliases port_http port_https services".split(" ").map(a=>
38
- H.readFile("config/"+a+".txt","utf8").catch(b=>null))]);ab||E.mkdirSync("data/");bb||E.cpSync(__dirname+"/public/","public/",{recursive:!0});if(Ra.some(a=>null!==a)){F=JSON.parse(await H.readFile("rtjscomp.json","utf8").catch(v=>null))||{};const [a,b,c,f,k,m,g,p,l,u]=Ra;a&&(F.path_ghosts=K(a));b&&(F.path_hiddens=K(b));c&&(F.path_statics=K(c));f&&(F.type_dynamics=K(f));k&&(F.type_mimes=Oa(k));m&&(F.type_raws=K(m));g&&(F.path_aliases=Oa(g));p&&(K=Number(p),isNaN(K)||(F.port_http=K));l&&(K=Number(l),
39
- isNaN(K)||(F.port_https=K));u&&(F.services=u.split("\n").filter(v=>0<v.length));await H.writeFile("rtjscomp.json",JSON.stringify(F,null,"\t")+"\n","utf8");d("[deprecated] config files found, rtjscomp.json written, please delete config files")}let Sa=0,ea=!1,W=null;const fa=new Map,ha=ya.createServer((a,b)=>Qa(a,b,!1));ha.on("error",a=>{d("[error] http: "+a.message);W&&W()});ha.on("connection",a=>{const b=++Sa;fa.set(b,a);a.on("close",()=>{fa.delete(b)})});q.http_start=async()=>{await q.http_stop();
40
- O&&(ea=!0,d("start http: http://localhost:"+O),await new Promise(a=>ha.listen(O,W=a)),W?W=null:t&&d("started http"))};q.http_stop=async()=>{if(ea){ea=!1;d("stop http");var a=setTimeout(q.http_kill,5E3);await new Promise(b=>ha.close(b));clearTimeout(a);t&&d("stopped http")}};q.http_kill=async()=>{ea||(d("kill http"),await Promise.all([...fa.values()].map(a=>a.destroy())),t&&d("killed http"),fa.clear())};try{const a=E.readFileSync("config/ssl/domain.key"),b=E.readFileSync("config/ssl/chained.pem");
41
- let c=!1,f=null;const k=new Map,m=require("https").createServer({key:a,cert:b},(g,p)=>Qa(g,p,!0));m.on("error",g=>{d("[error] https: "+g.message);f&&f()});m.on("connection",g=>{const p=++Sa;k.set(p,g);g.on("close",()=>{k.delete(p)})});q.https_start=async()=>{await q.https_stop();P&&(c=!0,d("start https: https://localhost:"+P),await new Promise(g=>m.listen(P,f=g)),f?f=null:t&&d("started https"))};q.https_stop=async()=>{if(c){c=!1;d("stop https");var g=setTimeout(q.https_kill,5E3);await new Promise(p=>
42
- m.close(p));clearTimeout(g);t&&d("stopped https")}};q.https_kill=async()=>{c||(d("kill https"),await Promise.all([...k.values()].map(g=>g.destroy())),t&&d("killed https"),k.clear())}}catch(a){t&&d("[hint] https: no cert, disabled")}await qa("rtjscomp.json",a=>{try{a=JSON.parse(a);if("object"!==typeof a)throw"must contain {}";const b=Ma(a,"compress",!0),c=ca(a,"gzip_level",3),f=Ma(a,"log_verbose",Ea),k=Na(a,"path_aliases"),m=L(a,"path_ghosts"),g=L(a,"path_hiddens"),p=L(a,"path_statics"),l=ca(a,"port_http",
43
- 8080),u=ca(a,"port_https",0),v=L(a,"services")||[],J=L(a,"type_dynamics"),y=Na(a,"type_mimes"),C=L(a,"type_raws"),r=ca(a,"zstd_level",3);if(a){const n=Object.keys(a);if(0<n.length)throw"unknown: "+n.join(", ");}if(9<c)throw"gzip_level > 9";if(19<r)throw"zstd_level > 19";if(65535<l||65535<u)throw"port > 65535";X=b;ia.level=X?c:0;Da.params[100]=r;t=f;if(m){la.clear();for(const n of m)M(n),la.add(n)}if(g){ma.clear();for(const n of g)M(n),ma.add(n)}if(p){na.clear();for(const n of p)M(n),na.add(n)}if(k){Y.clear();
44
- R.clear();S.clear();for(const [n,D]of k)if(M(n,!0),M(D),n.includes("*")){const x=n.split("/"),A=x.shift();S.has(A)?S.get(A).push({x3:x,value:D}):S.set(A,[{x3:x,value:D}])}else{Y.set(n,D);const x=R.get(D);(null==x||x.length-1>D.length)&&R.set(D,"/"+n)}}if(J){oa.clear();for(const n of J)oa.add(n)}if(y)for(const [n,D]of y)pa.set(n,D);if(C){Z.clear();for(const n of C)Z.add(n)}for(const n of v)M(n);const B=[Wa(v.filter(n=>35!==n.charCodeAt(0)))];l!==O&&(O=l,B.push(0<l?q.http_start():q.http_stop()));null!=
45
- q.https_stop&&u!==P&&(P=u,B.push(0<u?q.https_start():q.https_stop()));return Promise.all(B)}catch(b){d("[error] rtjscomp.json: "+(b.message||b))}});t&&d("started all")})();
5
+ (async()=>{const D=require("fs"),G=require("fs/promises"),xa=require("http"),Ua=require("url"),L=require("zlib"),ha={level:9},ya=null!=L.createBrotliCompress,za=null!=L.createZstdCompress,Aa=/,\s*/,ia=/\bimport\(/g,Ba="undefined"!==typeof Bun,Va=/:([0-9]+)[\):]/,Ca={paths:[require("path").resolve()]},Wa=/\bservice_require\(([^)]*)\)/g,ja={persistent:!0,interval:1E3},Da={params:{[100]:3}},Ea=process.argv.includes("-v");let u=Ea,M=0,N=0,Fa=10485760,X=!0,O=!1;const Y=new Map([["","index.html"]]),P=new Map([["index.html",
6
+ "/"]]),Q=new Map,ka=new Set,la=new Set,ma=new Set,na=new Set(["events","html","json","txt"]),oa=new Map([["apk","application/zip"],["bpg","image/bpg"],["css","text/css; charset=utf-8"],["events","text/event-stream"],["flac","audio/flac"],["gz","application/gzip"],["hta","application/hta"],["html","text/html; charset=utf-8"],["ico","image/x-icon"],["jpg","image/jpeg"],["js","text/javascript; charset=utf-8"],["json","application/json; charset=utf-8"],["mid","audio/midi"],["mp3","audio/mpeg3"],["pdf",
7
+ "application/pdf"],["png","image/png"],["rss","application/rss+xml; charset=utf-8"],["txt","text/plain; charset=utf-8"],["xml","application/xml; charset=utf-8"],["xz","application/x-xz"],["zip","application/zip"]]),Z=new Set("apk bpg flac gz jpg mp3 pdf png xz zip".split(" ")),aa=new Map,r={},E=global.rtjscomp={actions:r,version:"0.9.8"};Object.fromEntries||(Object.fromEntries=a=>{const b={};for(const c of a)b[c[0]]=c[1];return b});let R=D.watch;if(Ba){const a=R,b=new Map;R=(c,f,k)=>{b.has(c)||a(c,
8
+ f,()=>{const m=b.get(c);m&&m()});b.set(c,k);return{close:()=>b.set(c,null)}}}global.globals=E;global.actions=E.actions;global.data_load=a=>{d("[deprecated] synchronous load file: data/"+a);try{return D.readFileSync("data/"+a,"utf8")}catch(b){return null}};global.data_save=(a,b)=>(d("[deprecated] synchronous save file: data/"+a),D.writeFileSync("data/"+a,b,"utf8"));global.number_check_int=a=>Math.floor(a)===a;global.number_check_uint=a=>0<=a&&number_check_int(a);E.data_load=async a=>{u&&d("load file: data/"+
9
+ a);const b=await G.readFile("data/"+a,"utf8").catch(()=>null);return a.endsWith(".json")?JSON.parse(b||null):b};E.data_load_watch=(a,b)=>pa("data/"+a,c=>b(a.endsWith(".json")?JSON.parse(c||null):c));E.data_save=(a,b)=>(u&&d("save file: data/"+a),G.writeFile("data/"+a,a.endsWith(".json")?JSON.stringify(b):b,"utf8"));const Ga=a=>{try{return`:${a.stack.split("\n",2)[1].split(",").pop().match(Va)[1]-2}`}catch(b){return""}},Ha=new Set,qa=new Map,ra=new Map,sa=a=>{var b=qa.get(a);if(null!=b)return b;u&&
10
+ d("require module: "+a);b=require.resolve(a,Ca);Ha.add(b);qa.set(a,b=require(b));return b},ta=async a=>{let b=ra.get(a);if(null!=b)return b;u&&d("import module: "+a);ra.set(a,b=await import("file://"+require.resolve(a,Ca)));return b};r.module_cache_clear=()=>{for(const a of Ha)delete require.cache[a];qa.clear();ra.clear()};const ua=ta.constructor,H=new Map;let S=null,va=null;const Xa=async a=>{await Promise.all([...H.values()].filter(c=>4>c.status&&!a.includes(c.path)).map(c=>(c.dependencies=
11
+ null,c)).map(Ia));const b=[];for(const c of a){let f=H.get(c);if(null==f)H.set(c,f={content:null,dependencies:null,x0:null,x1:null,x2:null,path:c,x5:null,x4:null,x7:null,x6:null,status:0,x8:null});else if(4>f.status)continue;b.push(f)}await Promise.all(b.map(ba))},Ya=()=>Promise.all([...H.values()].map(a=>(a.dependencies=null,a)).map(Ia)),ba=async a=>{S||(S=new Promise(m=>{va=m}));const {path:b}=a;u&&d(b+": prepare for (re)start");let c=0;try{if(1===a.status||2===a.status)u&&d(b+": abort previous start"),
12
+ a.status=0,a.x4&&a.x4();else if(3===a.status){a.status=0;for(var f of H.values())(2===f.status||3===f.status)&&f.dependencies&&f.dependencies.includes(a)&&(f.dependencies=null,ba(f));Ja(a)}await a.x7;3<a.status&&(a.status=0);a.x7=new Promise(l=>{a.x6=l});if(!a.x1){f="public/"+b+".service.js";var k=await G.readFile(f,"utf8");if(0!==a.status)return;if(!a.x8){let l=0;a.x8=R(f,ja,()=>(clearTimeout(l),l=setTimeout(()=>(u&&d("file updated: "+b),a.x1=null,ba(a)),50)))}k.includes("globals.")&&d(`[deprecated] ${b}: uses globals object`);
13
+ a.x0=[];for(let [,l]of k.matchAll(Wa)){const w=l.charCodeAt(0),t=l.charCodeAt(l.length-1);if(3>l.length||!(34===w&&34===t||39===w&&39===t))throw Error("service_require() needs inline string");a.x0.includes(l=l.slice(1,-1))||a.x0.push(l)}a.x1=new ua("require","custom_import","service_require","service_require_try",`const log=a=>rtjscomp.log(${JSON.stringify(b+": ")}+a);${k.replace(ia,"custom_import(")}`)}a.dependencies=[];k=!1;for(const l of a.x0){const w=H.get(l);if(null==w)throw Error("unknown required service: "+
14
+ l);a.dependencies.push(w);k=k||3!==w.status}if(k&&(u&&d(b+": wait for dependencies"),a.status=1,a.x5=new Promise(l=>{a.x4=l}),await a.x5,1!==a.status))return;d("start service: "+b);a.status=2;c=setInterval(()=>{d(`[warning] ${b}: still starting`)},5E3);const m=a.content={},h=await a.x1.call(m,sa,ta,Ka,La);if(2!==a.status)return;"function"===typeof h&&(a.x2=h);const q=m.start;if(q&&(d(`[deprecated] ${b}: has start method`),delete m.start,await q(),2!==a.status))return;m.stop&&(d(`[deprecated] ${b}: has stop method`),
15
+ a.x2=m.stop,delete m.stop);u&&d("started service: "+b);a.status=3}catch(m){m instanceof Error||(m=Error(m+"?! wtf"));d(`[error] ${b}${Ga(m)}: ${m.message}`);a.status=5;a.dependencies=null;return}finally{clearInterval(c),a.x5=a.x4=null,3!==a.status&&(a.x6(),Ma())}a:for(const m of H.values())if(1===m.status){for(const h of m.dependencies)if(3!==h.status)continue a;m.x4()}Ma()},Ma=()=>{if(S){for(const a of H.values())if(3>a.status)return;va();S=va=null}},Ia=async a=>{d("stop service: "+a.path);a.status=
16
+ 4;a.x1=null;a.x8&&a.x8.close();for(const b of H.values())b.dependencies&&b.dependencies.includes(a)&&(b.dependencies=null,4!==b.status&&ba(b));a.x4?a.x4():await Ja(a);H.delete(a.path);u&&d("stopped service: "+a.path)},Ja=async a=>{const {x2:b,path:c}=a;if(b){a.x2=null;const f=setInterval(()=>{d(`[warning] ${c}: still stopping`)},1E3);try{await b()}catch(k){d(`[error] ${c}${Ga(k)} stop handler: ${k.message}`),a.status=5}clearInterval(f)}a.x6()},Ka=a=>{const b=H.get(a);if(null!=b&&3===b.status)return b.content;
17
+ throw Error("service required: "+a);},La=a=>{a=H.get(a);return null!=a&&3===a.status?a.content:null},Za=(a,b)=>{const c=R(a,ja,()=>(c.close(),u&&d("file updated: "+a),b()))},pa=async(a,b)=>{try{const f=await G.readFile(a,"utf8");u&&d("load file: "+a);await b(f)}catch(f){return await b(null),null}let c=0;return R(a,ja,()=>(clearTimeout(c),c=setTimeout(()=>O||(u&&d("file updated: "+a),G.readFile(a,"utf8").catch(()=>null).then(b)),50)))},Na=(a,b,c)=>{if(null===a||!(b in a))return c;c=a[b];if("boolean"!==
18
+ typeof c)throw b+" must be boolean";delete a[b];return c},T=(a,b,c)=>{if(null===a||!(b in a))return c;c=a[b];if("number"!==typeof c||0>c||0<c%1)throw b+" must be positive integer";delete a[b];return c},J=(a,b)=>{if(null===a||!(b in a))return null;const c=a[b];if("object"!==typeof c||!c||null==c.length||c.some(f=>"string"!==typeof f))throw b+" must be array of strings";delete a[b];return c},Oa=(a,b)=>{if(null===a||!(b in a))return null;let c=a[b];if("object"!==typeof c||!c||(c=Object.entries(c)).some(([,
19
+ f])=>"string"!==typeof f))throw b+" must be object of strings";delete a[b];return c},U=a=>a.split("\n").filter(b=>0<b.length&&35!==b.charCodeAt(0)),Pa=a=>Object.fromEntries(a.split("\n").filter(b=>0<b.length&&35!==b.charCodeAt(0)).map(b=>b.split(":",2))),K=(a,b=!1)=>{if(!b&&!a)throw"path is empty";if(47===a.charCodeAt(0))throw"path must not start with /";if(47===a.charCodeAt(a.length-1))throw"path must not end with /";if(a.includes(".."))throw"path must not contain ..";if(a.includes("~"))throw"path must not contain ~";
20
+ if(a.includes("//"))throw"path must not contain //";};let Qa=E.log_history=[];r.log_clear=()=>{Qa=E.log_history=[]};const d=E.log=a=>(console.log(a),Qa.push(a),V?ca("log",[a]):void 0),V=D.existsSync("spam.csv");E.spam_history="";r.spam_save=async(a=!1)=>{if(V)try{const b=E.spam_history;E.spam_history="";await G.appendFile("spam.csv",b,"utf8");u&&!a&&d("spam.csv saved")}catch(b){d("[error] cannot save spam.csv: "+b.message)}};const ca=(a,b)=>{E.spam_history+=Date.now()+","+a+","+JSON.stringify(b)+
21
+ "\n";1E5<=E.spam_history.length&&r.spam_save()},$a=(a,b,c)=>{b=Buffer.from(b);34===b[0]&&(b=b.subarray(1,-1));const f=b.length,k=f+4,m=a.length-k;var h=0;let q=0;for(;0<=(q=a.indexOf(45,q))&&q<=m;)if(45!==a[q+1]||0<q&&13!==a[q-2]||0<q&&10!==a[q-1]||0!==a.compare(b,0,f,q+2,q+2+f))++q;else{if(0<h){if(20>q-h)throw"part too short";for(var l=h;0<=(l=a.indexOf(13,l))&&10!==a[l+1]||13!==a[l+2]||10!==a[l+3];)++l;if(0>l)throw"part header end not found";let w="",t="";for(const C of a.toString("utf8",h,l).split("\r\n",
22
+ 2)){if(!C.startsWith("Content-"))throw"illegal part header";const [A,y]=C.slice(8).split(": ",2);if("Disposition"===A){if(!y.startsWith("form-data; "))throw"illegal disposition part header";w=y.slice(11)}else if("Type"===A)t=y;else throw"illegal part header";}if(!w)throw"part disposition header missing";let x=h="";for(const C of w.split("; ")){let [A,y]=C.split("=",2);34===y.charCodeAt(0)&&(y=y.slice(1,-1));if("name"===A)h=y;else if("filename"===A)x=y;else throw"illegal disposition part header";}if(!h)throw"part name header missing";
23
+ l=t?{filename:x,data:a.subarray(l+4,q-2),type:t}:a.toString("utf8",l+4,q-2);if(h.endsWith("[]"))if(h=h.slice(0,-2),h in c){if(!(c[h]instanceof Array))throw"duplicate part name";c[h].push(l)}else c[h]=[l];else{if(h in c)throw"duplicate part name";c[h]=l}}h=q+k;q=h+1}},wa=(a,b)=>{for(const c of a.split("&")){let [f,k]=c.split("=",2);(a=f.endsWith("[]"))&&(f=f.slice(0,-2));if(!f)throw"key is empty";k=decodeURIComponent(k||"");if(f in b){if(b[f]instanceof Array!==a)throw"type mismatch";a?b[f].push(k):
24
+ b[f]=k}else b[f]=a?[k]:k}},Ra=async(a,b,c)=>{const f=a.method,k=a.headers,m=k["x-forwarded-for"]||a.socket.remoteAddress,h="HEAD"===f;"x-forwarded-proto"in k&&(c="https"===k["x-forwarded-proto"]);V&&ca("request",[c,a.url,m]);try{const z=Ua.parse(a.url,!1);let g=z.pathname||"/";if(47!==g.charCodeAt(0)||g.includes("//"))throw 404;if(1<g.length&&g.endsWith("/")&&(g=g.slice(0,-1),g.lastIndexOf("/")<g.lastIndexOf(".")))throw b.setHeader("Location",g),301;g=g.slice(1);if(!(g.includes("php")||g.includes("sql")||
25
+ g.includes(".git/")||ka.has(g))){b.setHeader("Server","l3p3 rtjscomp v0.9.8");b.setHeader("Access-Control-Allow-Origin","*");var q=null,l=null;if(P.has(g))throw b.setHeader("Location",P.get(g)),301;if(Y.has(g))g=Y.get(g);else{var w=g.split("/"),t=Q.get(w.shift());if(null!=t)a:for(var x of t){var C=x.x3,A=C.length;if(A===w.length){t={};for(let p=0;p<A;++p)if(42===C[p].charCodeAt(0))1<C[p].length&&(t[C[p].slice(1)]=w[p]);else if(C[p]!==w[p])continue a;g=x.value;q=t;break}}}var y=g.lastIndexOf(".");
26
+ if(g.includes("..")||g.includes("~")||y<=g.lastIndexOf("/"))throw 404;var F=g.slice(y+1).toLowerCase();y=0;var I=na.has(F)&&!ma.has(g);if(!h&&"GET"!==f){if(!I)throw 405;if("content-length"in k){var n=Number(k["content-length"]);if(isNaN(n)||0>n||0<n%1)throw 400;if(n>Fa)throw 413;l=new Promise(p=>{const e=[];a.on("data",B=>{e.push(B)});a.on("end",B=>{B&&e.push(B);p(Buffer.concat(e))})})}}w=n=null;x="public/"+g;if(I&&aa.has(g))n=aa.get(g);else{u&&d(`load ${I?"dynam":"stat"}ic file: ${g}`);if(la.has(g)||
27
+ g.endsWith(".service.js"))throw 403;if(!D.existsSync(x))throw 404;w=D.statSync(x);if(w.isDirectory())throw 403;if(I){const p=await G.readFile(x,"utf8");try{if(p.includes("\r"))throw"illegal line break, must be unix";if(p.includes("response.write(")||p.includes("response.end("))throw"response.write() not allowed, use output.write()";p.includes("globals.")&&d(`[deprecated] ${g}: uses globals object`);const e=p.length;let B=`const log=a=>rtjscomp.log(${JSON.stringify(g+": ")}+a);`;C=!1;for(t=A=0;t<e;)if(C){if(0>
28
+ (t=p.indexOf("?>",A=t+2)))throw'"?>" missing';C=!1;A<t&&(B=61!==p.charCodeAt(A)?B+(p.slice(A,t).replace(ia,"custom_import(")+";"):B+`output.write(''+(${p.slice(++A,t).replace(ia,"custom_import(")}));`);t+=2}else-1<(t=p.indexOf("<?",A=t))?C=!0:t=e,A<t&&(B+=`output.write(${JSON.stringify(p.slice(A,t))});`);try{n=new ua("input","output","request","response","require","custom_import","service_require","service_require_try",B)}catch(ab){throw ab.message;}}catch(e){throw d(`[error] ${g} compile: ${e}`),
29
+ 500;}aa.set(g,n);Za(x,()=>aa.delete(g))}}b.statusCode=200;b.setHeader("Content-Type",oa.get(F)||oa.get("txt"));if(I){var v=q||{};if(k.cookie)for(let e of k.cookie.split(";")){e=e.trim();const B=e.indexOf("=");0<B?v[e.slice(0,B).trimRight()]=decodeURI(e.slice(B+1).trimLeft()):0>B&&(v[e]=void 0)}if(k["x-input"])try{wa(k["x-input"],v)}catch(e){throw d(`[error] ${g} request x-input: ${e}`),400;}if(z.query)try{wa(z.query,v)}catch(e){throw d(`[error] ${g} request query: ${e}`),400;}if(l)try{const e=a.headers["content-type"]||
30
+ "",B=v.body=await l;switch(e.split(";",1)[0]){case "application/json":Object.assign(v,JSON.parse(B.toString()));break;case "application/x-www-form-urlencoded":wa(B.toString(),v);break;case "multipart/form-data":$a(B,e.split("boundary=",2)[1].split(";",1)[0],v)}}catch(e){throw d(`[error] ${g} request body: ${e.message||e}`),400;}v.https=c;v.ip=m;v.method=h?"get":f.toLowerCase();v.path=z.pathname;v.user_agent=k["user-agent"];c=b;b.setHeader("Cache-Control","no-cache, no-store");if(X&&"accept-encoding"in
31
+ k&&!Z.has(F)){const e=k["accept-encoding"].split(Aa);za&&e.includes("zstd")?(y=3,b.setHeader("Content-Encoding","zstd"),h||(c=L.createZstdCompress(Da)).pipe(b)):ya&&e.includes("br")?(y=2,b.setHeader("Content-Encoding","br"),h||(c=L.createBrotliCompress()).pipe(b)):0<ha.level&&e.includes("gzip")&&(y=1,b.setHeader("Content-Encoding","gzip"),h||(c=L.createGzip(ha)).pipe(b))}V&&ca("execute",[g,Object.fromEntries(Object.entries(v).filter(e=>"body"!==e[0]).map(e=>"password"===e[0]?[e[0],"***"]:e).map(e=>
32
+ "file"===e[0]?[e[0],"..."]:e).map(e=>"object"!==typeof e[1]||e[1].length?e:[e[0],Object.keys(e[1]).slice(0,20)]).map(e=>"user_agent"!==e[0]&&"string"===typeof e[1]&&20<e[1].length?[e[0],e[1].slice(0,20)+"..."]:e))]);h&&(c.write=c.end=()=>{throw null;});await S;let p;try{p=await n(v,c,a,b,sa,ta,Ka,La)}catch(e){e instanceof Error?(d(`[error] ${g}: ${e.message}`),p=e.message.startsWith("service required: ")?503:500):"number"===typeof e?(d(`[deprecated] ${g}: status code thrown, use return instead`),
33
+ p=e):null!==e&&(d(`[error] ${g}: invalid throw type: ${typeof e}`),p=500)}h&&(delete c.write,delete c.end);if(null!=p){b.headersSent?(null!=b.writableEnded?b.writableEnded:b.finished)||c.end(`${"html"===F?"<hr>":"\n\n---\n"}ERROR!`):0!==y&&b.removeHeader("Content-Encoding");if("number"!==typeof p)throw d(`[error] ${g}: invalid return type: ${typeof p}`),500;if(b.headersSent&&500>p)throw d(`[error] ${g}: status code after content`),500;throw p;}c.end()}else{v=X&&!Z.has(F);F=x;if(v&&"accept-encoding"in
34
+ k){const p=k["accept-encoding"].split(Aa);p.includes("zstd")&&D.existsSync(x+".zst")?(y=3,F+=".zst"):p.includes("br")&&D.existsSync(x+".br")?(y=2,F+=".br"):p.includes("gzip")&&D.existsSync(x+".gz")&&(y=1,F+=".gz")}V&&ca("static_send",[g,y]);b.setHeader("Cache-Control","public, max-age=600");v&&b.setHeader("Vary","Accept-Encoding");switch(y){case 0:b.setHeader("Content-Length",w.size);break;case 1:b.setHeader("Content-Encoding","gzip");break;case 2:b.setHeader("Content-Encoding","br");break;case 3:b.setHeader("Content-Encoding",
35
+ "zstd")}h?b.end():D.createReadStream(F).pipe(b)}}}catch(z){"number"!==typeof z&&(console.error(z),z=500),(500<=z||u&&400<=z)&&d(`[error] request failed: ${z}; ${m}; ${a.url}`),b.headersSent||(b.writeHead(z,{"Content-Type":"text/html","Cache-Control":"no-cache, no-store"}),b.end(`<!DOCTYPE html><html><body><h1>HTTP ${z}: ${xa.STATUS_CODES[z]||"Error"}</h1></body></html>`)),"content-length"in k&&a.socket.destroy()}};r.halt=async()=>{O=!0;u&&d("stop all");await Promise.all([r.http_stop&&r.http_stop(),
36
+ r.https_stop&&r.https_stop(),Ya()]);await r.spam_save();d("stopped all")};r.exit=async a=>{O||("number"!==typeof a&&(a=0),await r.halt(),u&&d("exit"),process.exit(a))};process.on("uncaughtException",a=>{"symbol"===typeof a&&(a=a.toString());d("[error] uncaughtException: "+(a.message||a));console.error(a);O&&process.exit(1);r.exit(1)});process.on("unhandledRejection",a=>{d("[error] unhandledRejection: "+(a.message||a));console.error(a);O&&process.exit(1);r.exit(1)});process.on("exit",r.exit);process.on("SIGINT",
37
+ r.exit);process.on("SIGUSR2",r.exit);process.on("SIGTERM",r.exit);d(`rtjscomp v${"0.9.8"} in ${Ba?"bun":"node"} on ${process.platform.replace("win32","windows")}`);u&&!ya&&d("[hint] brotli not available");u&&!za&&d("[hint] zstd not available");await pa("config/init.js",async a=>{if(a){d("[deprecated] run global init script");try{await (new ua("require",a))(sa)}catch(b){d("[error] init.js: "+b.message)}}});const [bb,cb,...Sa]=await Promise.all([G.stat("data/").catch(a=>null),G.stat("public/").catch(a=>
38
+ null),..."file_blocks file_privates file_raws file_type_dyns file_type_mimes file_type_nocompress path_aliases port_http port_https services".split(" ").map(a=>G.readFile("config/"+a+".txt","utf8").catch(b=>null))]);bb||D.mkdirSync("data/");cb||D.cpSync(__dirname+"/public/","public/",{recursive:!0});if(Sa.some(a=>null!==a)){const a=JSON.parse(await G.readFile("rtjscomp.json","utf8").catch(x=>null))||{},[b,c,f,k,m,h,q,l,w,t]=Sa;b&&(a.path_ghosts=U(b));c&&(a.path_hiddens=U(c));f&&(a.path_statics=U(f));
39
+ k&&(a.type_dynamics=U(k));m&&(a.type_mimes=Pa(m));h&&(a.type_raws=U(h));q&&(a.path_aliases=Pa(q));if(l){const x=Number(l);isNaN(x)||(a.port_http=x)}if(w){const x=Number(w);isNaN(x)||(a.port_https=x)}t&&(a.services=t.split("\n").filter(x=>0<x.length));await G.writeFile("rtjscomp.json",JSON.stringify(a,null,"\t")+"\n","utf8");d("[deprecated] config files found, rtjscomp.json written, please delete config files")}let Ta=0,da=!1,W=null;const ea=new Map,fa=xa.createServer((a,b)=>Ra(a,b,!1));fa.on("error",
40
+ a=>{d("[error] http: "+a.message);W&&W()});fa.on("connection",a=>{const b=++Ta;ea.set(b,a);a.on("close",()=>{ea.delete(b)})});r.http_start=async()=>{await r.http_stop();M&&(da=!0,d("start http: http://localhost:"+M),await new Promise(a=>fa.listen(M,W=a)),W?W=null:u&&d("started http"))};r.http_stop=async()=>{if(da){da=!1;d("stop http");var a=setTimeout(r.http_kill,5E3);await new Promise(b=>fa.close(b));clearTimeout(a);u&&d("stopped http")}};r.http_kill=async()=>{da||(d("kill http"),await Promise.all([...ea.values()].map(a=>
41
+ a.destroy())),u&&d("killed http"),ea.clear())};try{const a=D.readFileSync("config/ssl/domain.key"),b=D.readFileSync("config/ssl/chained.pem");let c=!1,f=null;const k=new Map,m=require("https").createServer({key:a,cert:b},(h,q)=>Ra(h,q,!0));m.on("error",h=>{d("[error] https: "+h.message);f&&f()});m.on("connection",h=>{const q=++Ta;k.set(q,h);h.on("close",()=>{k.delete(q)})});r.https_start=async()=>{await r.https_stop();N&&(c=!0,d("start https: https://localhost:"+N),await new Promise(h=>m.listen(N,
42
+ f=h)),f?f=null:u&&d("started https"))};r.https_stop=async()=>{if(c){c=!1;d("stop https");var h=setTimeout(r.https_kill,5E3);await new Promise(q=>m.close(q));clearTimeout(h);u&&d("stopped https")}};r.https_kill=async()=>{c||(d("kill https"),await Promise.all([...k.values()].map(h=>h.destroy())),u&&d("killed https"),k.clear())}}catch(a){u&&d("[hint] https: no cert, disabled")}await pa("rtjscomp.json",a=>{try{a=JSON.parse(a);if("object"!==typeof a)throw"must contain {}";const b=Na(a,"compress",!0),c=
43
+ T(a,"gzip_level",3),f=Na(a,"log_verbose",Ea),k=Oa(a,"path_aliases"),m=J(a,"path_ghosts"),h=J(a,"path_hiddens"),q=J(a,"path_statics"),l=T(a,"port_http",8080),w=T(a,"port_https",0),t=J(a,"services")||[],x=J(a,"type_dynamics"),C=Oa(a,"type_mimes"),A=J(a,"type_raws"),y=T(a,"upload_limit",10),F=T(a,"zstd_level",3);if(a){const n=Object.keys(a);if(0<n.length)throw"unknown: "+n.join(", ");}if(9<c)throw"gzip_level > 9";if(65535<l||65535<w)throw"port > 65535";if(19<F)throw"zstd_level > 19";X=b;ha.level=X?c:
44
+ 0;Da.params[100]=F;u=f;Fa=1048576*y;if(m){ka.clear();for(const n of m)K(n),ka.add(n)}if(h){la.clear();for(const n of h)K(n),la.add(n)}if(q){ma.clear();for(const n of q)K(n),ma.add(n)}if(k){Y.clear();P.clear();Q.clear();for(const [n,v]of k)if(K(n,!0),K(v),n.includes("*")){const z=n.split("/"),g=z.shift();Q.has(g)?Q.get(g).push({x3:z,value:v}):Q.set(g,[{x3:z,value:v}])}else{Y.set(n,v);const z=P.get(v);(null==z||z.length-1>v.length)&&P.set(v,"/"+n)}}if(x){na.clear();for(const n of x)na.add(n)}if(C)for(const [n,
45
+ v]of C)oa.set(n,v);if(A){Z.clear();for(const n of A)Z.add(n)}for(const n of t)K(n);const I=[Xa(t.filter(n=>35!==n.charCodeAt(0)))];l!==M&&(M=l,I.push(0<l?r.http_start():r.http_stop()));null!=r.https_stop&&w!==N&&(N=w,I.push(0<w?r.https_start():r.https_stop()));return Promise.all(I)}catch(b){d("[error] rtjscomp.json: "+(b.message||b))}});u&&d("started all")})();