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.
- package/README.md +1 -0
- package/package.json +1 -1
- 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
package/rtjscomp.js
CHANGED
|
@@ -2,44 +2,44 @@
|
|
|
2
2
|
"use strict";/*
|
|
3
3
|
RTJSCOMP by L3P3, 2017-2025
|
|
4
4
|
*/
|
|
5
|
-
(async()=>{const
|
|
6
|
-
"/"]]),
|
|
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,
|
|
8
|
-
f,()=>{const m=b.get(c);m&&m()});b.set(c,k);return{close:()=>b.set(c,null)}}}global.globals=
|
|
9
|
-
a);const b=await
|
|
10
|
-
d("require module: "+a);b=require.resolve(a,Ca);
|
|
11
|
-
null,c)).map(
|
|
12
|
-
a.status=0,a.x4&&a.x4();else if(3===a.status){a.status=0;for(var f of
|
|
13
|
-
a.x0=[];for(let [,l]of k.matchAll(
|
|
14
|
-
l);a.dependencies.push(
|
|
15
|
-
a.x2=m.stop,delete m.stop);
|
|
16
|
-
4;a.x1=null;a.x8&&a.x8.close();for(const b of
|
|
17
|
-
throw Error("service required: "+a);},
|
|
18
|
-
typeof c)throw b+" must be boolean";delete a[b];return c},
|
|
19
|
-
f])=>"string"!==typeof f))throw b+" must be object of strings";delete a[b];return c}
|
|
20
|
-
if(a.includes("//"))throw"path must not contain //";};let
|
|
21
|
-
"\n";1E5<=
|
|
22
|
-
2)){if(!
|
|
23
|
-
l=
|
|
24
|
-
b[f]=k}else b[f]=a?[k]:k}},
|
|
25
|
-
|
|
26
|
-
if(
|
|
27
|
-
if(D){const
|
|
28
|
-
"custom_import(")+";"):
|
|
29
|
-
if(
|
|
30
|
-
break;case "application/x-www-form-urlencoded":
|
|
31
|
-
"zstd"),
|
|
32
|
-
"user_agent"!==e[0]&&"string"===typeof e[1]&&20<e[1].length?[e[0],e[1].slice(0,20)+"..."]:e))]);
|
|
33
|
-
(null!=b.writableEnded?b.writableEnded:b.finished)||c.end(`${"html"===
|
|
34
|
-
".br")?(
|
|
35
|
-
(500<=
|
|
36
|
-
process.exit(a))};process.on("uncaughtException",a=>{"symbol"===typeof a&&(a=a.toString());d("[error] uncaughtException: "+(a.message||a));console.error(a);
|
|
37
|
-
"windows")}`);
|
|
38
|
-
|
|
39
|
-
isNaN(
|
|
40
|
-
|
|
41
|
-
let c=!1,f=null;const k=new Map,m=require("https").createServer({key:a,cert:b},(
|
|
42
|
-
m.close(
|
|
43
|
-
8080),
|
|
44
|
-
|
|
45
|
-
|
|
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")})();
|