molnos 1.0.3 → 1.1.0

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/Dockerfile ADDED
@@ -0,0 +1,20 @@
1
+ FROM node:24-alpine
2
+
3
+ WORKDIR /app
4
+
5
+ LABEL org.opencontainers.image.source="https://github.com/molnoscloud/molnos-core"
6
+ LABEL org.opencontainers.image.description="MolnOS Core"
7
+ LABEL org.opencontainers.image.licenses="SEE-LICENSE"
8
+
9
+ # Copy bundled runtime files (all dependencies are bundled in)
10
+ COPY . /app/
11
+
12
+ EXPOSE 3000
13
+
14
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
15
+ CMD node -e "require('http').get('http://localhost:3000/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))" || exit 1
16
+
17
+ # Users must mount their config file at this path
18
+ ENV MOLNOS_CONFIG_FILE=/app/molnos.config.json
19
+
20
+ CMD ["node", "molnos_core.mjs"]
package/README.md CHANGED
@@ -10,9 +10,9 @@ Create `molnos.config.json` in the project root (setting your own details):
10
10
  {
11
11
  "email": {
12
12
  "emailSubject": "Sign In To MolnOS",
13
- "user": "signin@molnos.cloud",
13
+ "user": "signin@yourdomain.com",
14
14
  "password": "",
15
- "host": "smtp.protonmail.ch",
15
+ "host": "smtp.yourprovider.com",
16
16
  "port": 465,
17
17
  "secure": true,
18
18
  "maxRetries": 2
@@ -32,6 +32,30 @@ Create `molnos.config.json` in the project root (setting your own details):
32
32
  "maxActiveSessions": 3,
33
33
  "consoleUrl": "http://localhost:8000"
34
34
  },
35
+ "oauth": {
36
+ "presets": {
37
+ "github": {
38
+ "clientId": "github-id",
39
+ "clientSecret": "github-secret",
40
+ "redirectUri": "http://localhost:3000/auth/oauth/github/callback"
41
+ },
42
+ "google": {
43
+ "clientId": "google-id",
44
+ "clientSecret": "google-secret",
45
+ "redirectUri": "http: //localhost:3000/auth/oauth/google/callback"
46
+ },
47
+ "microsoft": {
48
+ "clientId": "microsoft-id",
49
+ "clientSecret": "microsoft-secret",
50
+ "redirectUri": "http: //localhost:3000/auth/oauth/microsoft/callback"
51
+ },
52
+ "gitlab": {
53
+ "clientId": "gitlab-id",
54
+ "clientSecret": "gitlab-secret",
55
+ "redirectUri": "http: //localhost:3000/auth/oauth/gitlab/callback"
56
+ }
57
+ }
58
+ }
35
59
  "server": {
36
60
  "allowedDomains": [
37
61
  "*"
@@ -40,27 +64,18 @@ Create `molnos.config.json` in the project root (setting your own details):
40
64
  }
41
65
  ```
42
66
 
43
- Start the server with:
44
-
45
- ```bash
46
- npm start
47
- ```
48
-
49
67
  The API will be available at `http://localhost:3000`.
50
68
 
51
- ## Essential Commands
52
-
53
- - `npm start` - Build and start the server
54
- - `npm run start:clean` - Start with fresh database (wipes all data)
55
- - `npm test` - Run linting and tests
56
- - `npm run build` - Build for distribution
57
-
58
69
  ## Using with MolnOS Console
59
70
 
60
- When running the Console project locally, configure it to use Core's API URL:
71
+ When running the Console locally, configure it to use Core's API URL:
61
72
 
62
73
  ```text
63
74
  http://localhost:3000
64
75
  ```
65
76
 
66
77
  The Console's API URL (configured in `auth.consoleUrl` above) should match the Console's running port, typically `http://localhost:8000`.
78
+
79
+ ## See the documentation for more details
80
+
81
+ For further details, see the [MolnOS documentation](https://docs.molnos.cloud).
package/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.1.0
@@ -1,2 +1,11 @@
1
1
  // MolnOS Core - See LICENSE file for copyright and license details.
2
- var ae=(e,t,s)=>(r,n)=>{let a=-1;return o(0);async function o(i){if(i<=a)throw new Error("next() called multiple times");a=i;let c,l=!1,h;if(e[i]?(h=e[i][0][0],r.req.routeIndex=i):h=i===e.length&&n||void 0,h)try{c=await h(r,()=>o(i+1))}catch(u){if(u instanceof Error&&t)r.error=u,c=await t(u,r),l=!0;else throw u}else r.finalized===!1&&s&&(c=await s(r));return c&&(r.finalized===!1||l)&&(r.res=c),r}};var Pe=Symbol();var Ce=async(e,t=Object.create(null))=>{let{all:s=!1,dot:r=!1}=t,a=(e instanceof U?e.raw.headers:e.headers).get("Content-Type");return a?.startsWith("multipart/form-data")||a?.startsWith("application/x-www-form-urlencoded")?At(e,{all:s,dot:r}):{}};async function At(e,t){let s=await e.formData();return s?Mt(s,t):{}}function Mt(e,t){let s=Object.create(null);return e.forEach((r,n)=>{t.all||n.endsWith("[]")?Dt(s,n,r):s[n]=r}),t.dot&&Object.entries(s).forEach(([r,n])=>{r.includes(".")&&(Ht(s,r,n),delete s[r])}),s}var Dt=(e,t,s)=>{e[t]!==void 0?Array.isArray(e[t])?e[t].push(s):e[t]=[e[t],s]:t.endsWith("[]")?e[t]=[s]:e[t]=s},Ht=(e,t,s)=>{let r=e,n=t.split(".");n.forEach((a,o)=>{o===n.length-1?r[a]=s:((!r[a]||typeof r[a]!="object"||Array.isArray(r[a])||r[a]instanceof File)&&(r[a]=Object.create(null)),r=r[a])})};var ie=e=>{let t=e.split("/");return t[0]===""&&t.shift(),t},je=e=>{let{groups:t,path:s}=kt(e),r=ie(s);return $t(r,t)},kt=e=>{let t=[];return e=e.replace(/\{[^}]+\}/g,(s,r)=>{let n=`@${r}`;return t.push([n,s]),n}),{groups:t,path:e}},$t=(e,t)=>{for(let s=t.length-1;s>=0;s--){let[r]=t[s];for(let n=e.length-1;n>=0;n--)if(e[n].includes(r)){e[n]=e[n].replace(r,t[s][1]);break}}return e},V={},Oe=(e,t)=>{if(e==="*")return"*";let s=e.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);if(s){let r=`${e}#${t}`;return V[r]||(s[2]?V[r]=t&&t[0]!==":"&&t[0]!=="*"?[r,s[1],new RegExp(`^${s[2]}(?=/${t})`)]:[e,s[1],new RegExp(`^${s[2]}$`)]:V[r]=[e,s[1],!0]),V[r]}return null},W=(e,t)=>{try{return t(e)}catch{return e.replace(/(?:%[0-9A-Fa-f]{2})+/g,s=>{try{return t(s)}catch{return s}})}},Lt=e=>W(e,decodeURI),ce=e=>{let t=e.url,s=t.indexOf("/",t.indexOf(":")+4),r=s;for(;r<t.length;r++){let n=t.charCodeAt(r);if(n===37){let a=t.indexOf("?",r),o=t.slice(s,a===-1?void 0:a);return Lt(o.includes("%25")?o.replace(/%25/g,"%2525"):o)}else if(n===63)break}return t.slice(s,r)};var Te=e=>{let t=ce(e);return t.length>1&&t.at(-1)==="/"?t.slice(0,-1):t},C=(e,t,...s)=>(s.length&&(t=C(t,...s)),`${e?.[0]==="/"?"":"/"}${e}${t==="/"?"":`${e?.at(-1)==="/"?"":"/"}${t?.[0]==="/"?t.slice(1):t}`}`),G=e=>{if(e.charCodeAt(e.length-1)!==63||!e.includes(":"))return null;let t=e.split("/"),s=[],r="";return t.forEach(n=>{if(n!==""&&!/\:/.test(n))r+="/"+n;else if(/\:/.test(n))if(/\?/.test(n)){s.length===0&&r===""?s.push("/"):s.push(r);let a=n.replace("?","");r+="/"+a,s.push(r)}else r+="/"+n}),s.filter((n,a,o)=>o.indexOf(n)===a)},oe=e=>/[%+]/.test(e)?(e.indexOf("+")!==-1&&(e=e.replace(/\+/g," ")),e.indexOf("%")!==-1?W(e,le):e):e,Ae=(e,t,s)=>{let r;if(!s&&t&&!/[%+]/.test(t)){let o=e.indexOf("?",8);if(o===-1)return;for(e.startsWith(t,o+1)||(o=e.indexOf(`&${t}`,o+1));o!==-1;){let i=e.charCodeAt(o+t.length+1);if(i===61){let c=o+t.length+2,l=e.indexOf("&",c);return oe(e.slice(c,l===-1?void 0:l))}else if(i==38||isNaN(i))return"";o=e.indexOf(`&${t}`,o+1)}if(r=/[%+]/.test(e),!r)return}let n={};r??=/[%+]/.test(e);let a=e.indexOf("?",8);for(;a!==-1;){let o=e.indexOf("&",a+1),i=e.indexOf("=",a);i>o&&o!==-1&&(i=-1);let c=e.slice(a+1,i===-1?o===-1?void 0:o:i);if(r&&(c=oe(c)),a=o,c==="")continue;let l;i===-1?l="":(l=e.slice(i+1,o===-1?void 0:o),r&&(l=oe(l))),s?(n[c]&&Array.isArray(n[c])||(n[c]=[]),n[c].push(l)):n[c]??=l}return t?n[t]:n},Me=Ae,De=(e,t)=>Ae(e,t,!0),le=decodeURIComponent;var He=e=>W(e,le),U=class{raw;#t;#e;routeIndex=0;path;bodyCache={};constructor(e,t="/",s=[[]]){this.raw=e,this.path=t,this.#e=s,this.#t={}}param(e){return e?this.#r(e):this.#a()}#r(e){let t=this.#e[0][this.routeIndex][1][e],s=this.#n(t);return s&&/\%/.test(s)?He(s):s}#a(){let e={},t=Object.keys(this.#e[0][this.routeIndex][1]);for(let s of t){let r=this.#n(this.#e[0][this.routeIndex][1][s]);r!==void 0&&(e[s]=/\%/.test(r)?He(r):r)}return e}#n(e){return this.#e[1]?this.#e[1][e]:e}query(e){return Me(this.url,e)}queries(e){return De(this.url,e)}header(e){if(e)return this.raw.headers.get(e)??void 0;let t={};return this.raw.headers.forEach((s,r)=>{t[r]=s}),t}async parseBody(e){return this.bodyCache.parsedBody??=await Ce(this,e)}#s=e=>{let{bodyCache:t,raw:s}=this,r=t[e];if(r)return r;let n=Object.keys(t)[0];return n?t[n].then(a=>(n==="json"&&(a=JSON.stringify(a)),new Response(a)[e]())):t[e]=s[e]()};json(){return this.#s("text").then(e=>JSON.parse(e))}text(){return this.#s("text")}arrayBuffer(){return this.#s("arrayBuffer")}blob(){return this.#s("blob")}formData(){return this.#s("formData")}addValidatedData(e,t){this.#t[e]=t}valid(e){return this.#t[e]}get url(){return this.raw.url}get method(){return this.raw.method}get[Pe](){return this.#e}get matchedRoutes(){return this.#e[0].map(([[,e]])=>e)}get routePath(){return this.#e[0].map(([[,e]])=>e)[this.routeIndex].path}};var ke={Stringify:1,BeforeStream:2,Stream:3},It=(e,t)=>{let s=new String(e);return s.isEscaped=!0,s.callbacks=t,s};var he=async(e,t,s,r,n)=>{typeof e=="object"&&!(e instanceof String)&&(e instanceof Promise||(e=e.toString()),e instanceof Promise&&(e=await e));let a=e.callbacks;if(!a?.length)return Promise.resolve(e);n?n[0]+=e:n=[e];let o=Promise.all(a.map(i=>i({phase:t,buffer:n,context:r}))).then(i=>Promise.all(i.filter(Boolean).map(c=>he(c,t,!1,r,n))).then(()=>n[0]));return s?It(await o,a):o};var qt="text/plain; charset=UTF-8",ue=(e,t)=>({"Content-Type":e,...t}),$e=class{#t;#e;env={};#r;finalized=!1;error;#a;#n;#s;#h;#c;#l;#i;#u;#f;constructor(e,t){this.#t=e,t&&(this.#n=t.executionCtx,this.env=t.env,this.#l=t.notFoundHandler,this.#f=t.path,this.#u=t.matchResult)}get req(){return this.#e??=new U(this.#t,this.#f,this.#u),this.#e}get event(){if(this.#n&&"respondWith"in this.#n)return this.#n;throw Error("This context has no FetchEvent")}get executionCtx(){if(this.#n)return this.#n;throw Error("This context has no ExecutionContext")}get res(){return this.#s||=new Response(null,{headers:this.#i??=new Headers})}set res(e){if(this.#s&&e){e=new Response(e.body,e);for(let[t,s]of this.#s.headers.entries())if(t!=="content-type")if(t==="set-cookie"){let r=this.#s.headers.getSetCookie();e.headers.delete("set-cookie");for(let n of r)e.headers.append("set-cookie",n)}else e.headers.set(t,s)}this.#s=e,this.finalized=!0}render=(...e)=>(this.#c??=t=>this.html(t),this.#c(...e));setLayout=e=>this.#h=e;getLayout=()=>this.#h;setRenderer=e=>{this.#c=e};header=(e,t,s)=>{this.finalized&&(this.#s=new Response(this.#s.body,this.#s));let r=this.#s?this.#s.headers:this.#i??=new Headers;t===void 0?r.delete(e):s?.append?r.append(e,t):r.set(e,t)};status=e=>{this.#a=e};set=(e,t)=>{this.#r??=new Map,this.#r.set(e,t)};get=e=>this.#r?this.#r.get(e):void 0;get var(){return this.#r?Object.fromEntries(this.#r):{}}#o(e,t,s){let r=this.#s?new Headers(this.#s.headers):this.#i??new Headers;if(typeof t=="object"&&"headers"in t){let a=t.headers instanceof Headers?t.headers:new Headers(t.headers);for(let[o,i]of a)o.toLowerCase()==="set-cookie"?r.append(o,i):r.set(o,i)}if(s)for(let[a,o]of Object.entries(s))if(typeof o=="string")r.set(a,o);else{r.delete(a);for(let i of o)r.append(a,i)}let n=typeof t=="number"?t:t?.status??this.#a;return new Response(e,{status:n,headers:r})}newResponse=(...e)=>this.#o(...e);body=(e,t,s)=>this.#o(e,t,s);text=(e,t,s)=>!this.#i&&!this.#a&&!t&&!s&&!this.finalized?new Response(e):this.#o(e,t,ue(qt,s));json=(e,t,s)=>this.#o(JSON.stringify(e),t,ue("application/json",s));html=(e,t,s)=>{let r=n=>this.#o(n,t,ue("text/html; charset=UTF-8",s));return typeof e=="object"?he(e,ke.Stringify,!1,{}).then(r):r(e)};redirect=(e,t)=>{let s=String(e);return this.header("Location",/[^\x00-\xFF]/.test(s)?encodeURI(s):s),this.newResponse(null,t??302)};notFound=()=>(this.#l??=()=>new Response,this.#l(this))};var f="ALL",Le="all",Ie=["get","post","put","delete","options","patch"],K="Can not add a route since the matcher is already built.",J=class extends Error{};var qe="__COMPOSED_HANDLER";var _t=e=>e.text("404 Not Found",404),_e=(e,t)=>{if("getResponse"in e){let s=e.getResponse();return t.newResponse(s.body,s)}return console.error(e),t.text("Internal Server Error",500)},Ne=class Fe{get;post;put;delete;options;patch;all;on;use;router;getPath;_basePath="/";#t="/";routes=[];constructor(t={}){[...Ie,Le].forEach(a=>{this[a]=(o,...i)=>(typeof o=="string"?this.#t=o:this.#a(a,this.#t,o),i.forEach(c=>{this.#a(a,this.#t,c)}),this)}),this.on=(a,o,...i)=>{for(let c of[o].flat()){this.#t=c;for(let l of[a].flat())i.map(h=>{this.#a(l.toUpperCase(),this.#t,h)})}return this},this.use=(a,...o)=>(typeof a=="string"?this.#t=a:(this.#t="*",o.unshift(a)),o.forEach(i=>{this.#a(f,this.#t,i)}),this);let{strict:r,...n}=t;Object.assign(this,n),this.getPath=r??!0?t.getPath??ce:Te}#e(){let t=new Fe({router:this.router,getPath:this.getPath});return t.errorHandler=this.errorHandler,t.#r=this.#r,t.routes=this.routes,t}#r=_t;errorHandler=_e;route(t,s){let r=this.basePath(t);return s.routes.map(n=>{let a;s.errorHandler===_e?a=n.handler:(a=async(o,i)=>(await ae([],s.errorHandler)(o,()=>n.handler(o,i))).res,a[qe]=n.handler),r.#a(n.method,n.path,a)}),this}basePath(t){let s=this.#e();return s._basePath=C(this._basePath,t),s}onError=t=>(this.errorHandler=t,this);notFound=t=>(this.#r=t,this);mount(t,s,r){let n,a;r&&(typeof r=="function"?a=r:(a=r.optionHandler,r.replaceRequest===!1?n=c=>c:n=r.replaceRequest));let o=a?c=>{let l=a(c);return Array.isArray(l)?l:[l]}:c=>{let l;try{l=c.executionCtx}catch{}return[c.env,l]};n||=(()=>{let c=C(this._basePath,t),l=c==="/"?0:c.length;return h=>{let u=new URL(h.url);return u.pathname=u.pathname.slice(l)||"/",new Request(u,h)}})();let i=async(c,l)=>{let h=await s(n(c.req.raw),...o(c));if(h)return h;await l()};return this.#a(f,C(t,"*"),i),this}#a(t,s,r){t=t.toUpperCase(),s=C(this._basePath,s);let n={basePath:this._basePath,path:s,method:t,handler:r};this.router.add(t,s,[r,n]),this.routes.push(n)}#n(t,s){if(t instanceof Error)return this.errorHandler(t,s);throw t}#s(t,s,r,n){if(n==="HEAD")return(async()=>new Response(null,await this.#s(t,s,r,"GET")))();let a=this.getPath(t,{env:r}),o=this.router.match(n,a),i=new $e(t,{path:a,matchResult:o,env:r,executionCtx:s,notFoundHandler:this.#r});if(o[0].length===1){let l;try{l=o[0][0][0][0](i,async()=>{i.res=await this.#r(i)})}catch(h){return this.#n(h,i)}return l instanceof Promise?l.then(h=>h||(i.finalized?i.res:this.#r(i))).catch(h=>this.#n(h,i)):l??this.#r(i)}let c=ae(o[0],this.errorHandler,this.#r);return(async()=>{try{let l=await c(i);if(!l.finalized)throw new Error("Context is not finalized. Did you forget to return a Response object or `await next()`?");return l.res}catch(l){return this.#n(l,i)}})()}fetch=(t,...s)=>this.#s(t,s[1],s[0],t.method);request=(t,s,r,n)=>t instanceof Request?this.fetch(s?new Request(t,s):t,r,n):(t=t.toString(),this.fetch(new Request(/^https?:\/\//.test(t)?t:`http://localhost${C("/",t)}`,s),r,n));fire=()=>{addEventListener("fetch",t=>{t.respondWith(this.#s(t.request,t,void 0,t.request.method))})}};var Q=[];function fe(e,t){let s=this.buildAllMatchers(),r=((n,a)=>{let o=s[n]||s[f],i=o[2][a];if(i)return i;let c=a.match(o[0]);if(!c)return[[],Q];let l=c.indexOf("",1);return[o[1][l],c]});return this.match=r,r(e,t)}var X="[^/]+",I=".*",q="(?:|/.*)",j=Symbol(),Nt=new Set(".\\+*[^]$()");function Ft(e,t){return e.length===1?t.length===1?e<t?-1:1:-1:t.length===1||e===I||e===q?1:t===I||t===q?-1:e===X?1:t===X?-1:e.length===t.length?e<t?-1:1:t.length-e.length}var Be=class de{#t;#e;#r=Object.create(null);insert(t,s,r,n,a){if(t.length===0){if(this.#t!==void 0)throw j;if(a)return;this.#t=s;return}let[o,...i]=t,c=o==="*"?i.length===0?["","",I]:["","",X]:o==="/*"?["","",q]:o.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/),l;if(c){let h=c[1],u=c[2]||X;if(h&&c[2]&&(u===".*"||(u=u.replace(/^\((?!\?:)(?=[^)]+\)$)/,"(?:"),/\((?!\?:)/.test(u))))throw j;if(l=this.#r[u],!l){if(Object.keys(this.#r).some(d=>d!==I&&d!==q))throw j;if(a)return;l=this.#r[u]=new de,h!==""&&(l.#e=n.varIndex++)}!a&&h!==""&&r.push([h,l.#e])}else if(l=this.#r[o],!l){if(Object.keys(this.#r).some(h=>h.length>1&&h!==I&&h!==q))throw j;if(a)return;l=this.#r[o]=new de}l.insert(i,s,r,n,a)}buildRegExpStr(){let s=Object.keys(this.#r).sort(Ft).map(r=>{let n=this.#r[r];return(typeof n.#e=="number"?`(${r})@${n.#e}`:Nt.has(r)?`\\${r}`:r)+n.buildRegExpStr()});return typeof this.#t=="number"&&s.unshift(`#${this.#t}`),s.length===0?"":s.length===1?s[0]:"(?:"+s.join("|")+")"}};var ze=class{#t={varIndex:0};#e=new Be;insert(e,t,s){let r=[],n=[];for(let o=0;;){let i=!1;if(e=e.replace(/\{[^}]+\}/g,c=>{let l=`@\\${o}`;return n[o]=[l,c],o++,i=!0,l}),!i)break}let a=e.match(/(?::[^\/]+)|(?:\/\*$)|./g)||[];for(let o=n.length-1;o>=0;o--){let[i]=n[o];for(let c=a.length-1;c>=0;c--)if(a[c].indexOf(i)!==-1){a[c]=a[c].replace(i,n[o][1]);break}}return this.#e.insert(a,t,r,this.#t,s),r}buildRegExp(){let e=this.#e.buildRegExpStr();if(e==="")return[/^$/,[],[]];let t=0,s=[],r=[];return e=e.replace(/#(\d+)|@(\d+)|\.\*\$/g,(n,a,o)=>a!==void 0?(s[++t]=Number(a),"$()"):(o!==void 0&&(r[Number(o)]=++t),"")),[new RegExp(`^${e}`),s,r]}};var Bt=[/^$/,[],Object.create(null)],Ue=Object.create(null);function Ve(e){return Ue[e]??=new RegExp(e==="*"?"":`^${e.replace(/\/\*$|([.\\+*[^\]$()])/g,(t,s)=>s?`\\${s}`:"(?:|/.*)")}$`)}function zt(){Ue=Object.create(null)}function Ut(e){let t=new ze,s=[];if(e.length===0)return Bt;let r=e.map(l=>[!/\*|\/:/.test(l[0]),...l]).sort(([l,h],[u,d])=>l?1:u?-1:h.length-d.length),n=Object.create(null);for(let l=0,h=-1,u=r.length;l<u;l++){let[d,m,v]=r[l];d?n[m]=[v.map(([g])=>[g,Object.create(null)]),Q]:h++;let p;try{p=t.insert(m,h,d)}catch(g){throw g===j?new J(m):g}d||(s[h]=v.map(([g,x])=>{let B=Object.create(null);for(x-=1;x>=0;x--){let[z,E]=p[x];B[z]=E}return[g,B]}))}let[a,o,i]=t.buildRegExp();for(let l=0,h=s.length;l<h;l++)for(let u=0,d=s[l].length;u<d;u++){let m=s[l][u]?.[1];if(!m)continue;let v=Object.keys(m);for(let p=0,g=v.length;p<g;p++)m[v[p]]=i[m[v[p]]]}let c=[];for(let l in o)c[l]=s[o[l]];return[a,c,n]}function M(e,t){if(e){for(let s of Object.keys(e).sort((r,n)=>n.length-r.length))if(Ve(s).test(t))return[...e[s]]}}var Y=class{name="RegExpRouter";#t;#e;constructor(){this.#t={[f]:Object.create(null)},this.#e={[f]:Object.create(null)}}add(e,t,s){let r=this.#t,n=this.#e;if(!r||!n)throw new Error(K);r[e]||[r,n].forEach(i=>{i[e]=Object.create(null),Object.keys(i[f]).forEach(c=>{i[e][c]=[...i[f][c]]})}),t==="/*"&&(t="*");let a=(t.match(/\/:/g)||[]).length;if(/\*$/.test(t)){let i=Ve(t);e===f?Object.keys(r).forEach(c=>{r[c][t]||=M(r[c],t)||M(r[f],t)||[]}):r[e][t]||=M(r[e],t)||M(r[f],t)||[],Object.keys(r).forEach(c=>{(e===f||e===c)&&Object.keys(r[c]).forEach(l=>{i.test(l)&&r[c][l].push([s,a])})}),Object.keys(n).forEach(c=>{(e===f||e===c)&&Object.keys(n[c]).forEach(l=>i.test(l)&&n[c][l].push([s,a]))});return}let o=G(t)||[t];for(let i=0,c=o.length;i<c;i++){let l=o[i];Object.keys(n).forEach(h=>{(e===f||e===h)&&(n[h][l]||=[...M(r[h],l)||M(r[f],l)||[]],n[h][l].push([s,a-c+i+1]))})}}match=fe;buildAllMatchers(){let e=Object.create(null);return Object.keys(this.#e).concat(Object.keys(this.#t)).forEach(t=>{e[t]||=this.#r(t)}),this.#t=this.#e=void 0,zt(),e}#r(e){let t=[],s=e===f;return[this.#t,this.#e].forEach(r=>{let n=r[e]?Object.keys(r[e]).map(a=>[a,r[e][a]]):[];n.length!==0?(s||=!0,t.push(...n)):e!==f&&t.push(...Object.keys(r[f]).map(a=>[a,r[f][a]]))}),s?Ut(t):null}};var pe=class{name="SmartRouter";#t=[];#e=[];constructor(e){this.#t=e.routers}add(e,t,s){if(!this.#e)throw new Error(K);this.#e.push([e,t,s])}match(e,t){if(!this.#e)throw new Error("Fatal error");let s=this.#t,r=this.#e,n=s.length,a=0,o;for(;a<n;a++){let i=s[a];try{for(let c=0,l=r.length;c<l;c++)i.add(...r[c]);o=i.match(e,t)}catch(c){if(c instanceof J)continue;throw c}this.match=i.match.bind(i),this.#t=[i],this.#e=void 0;break}if(a===n)throw new Error("Fatal error");return this.name=`SmartRouter + ${this.activeRouter.name}`,o}get activeRouter(){if(this.#e||this.#t.length!==1)throw new Error("No active router has been determined yet.");return this.#t[0]}};var _=Object.create(null),We=class Ge{#t;#e;#r;#a=0;#n=_;constructor(t,s,r){if(this.#e=r||Object.create(null),this.#t=[],t&&s){let n=Object.create(null);n[t]={handler:s,possibleKeys:[],score:0},this.#t=[n]}this.#r=[]}insert(t,s,r){this.#a=++this.#a;let n=this,a=je(s),o=[];for(let i=0,c=a.length;i<c;i++){let l=a[i],h=a[i+1],u=Oe(l,h),d=Array.isArray(u)?u[0]:l;if(d in n.#e){n=n.#e[d],u&&o.push(u[1]);continue}n.#e[d]=new Ge,u&&(n.#r.push(u),o.push(u[1])),n=n.#e[d]}return n.#t.push({[t]:{handler:r,possibleKeys:o.filter((i,c,l)=>l.indexOf(i)===c),score:this.#a}}),n}#s(t,s,r,n){let a=[];for(let o=0,i=t.#t.length;o<i;o++){let c=t.#t[o],l=c[s]||c[f],h={};if(l!==void 0&&(l.params=Object.create(null),a.push(l),r!==_||n&&n!==_))for(let u=0,d=l.possibleKeys.length;u<d;u++){let m=l.possibleKeys[u],v=h[l.score];l.params[m]=n?.[m]&&!v?n[m]:r[m]??n?.[m],h[l.score]=!0}}return a}search(t,s){let r=[];this.#n=_;let a=[this],o=ie(s),i=[];for(let c=0,l=o.length;c<l;c++){let h=o[c],u=c===l-1,d=[];for(let m=0,v=a.length;m<v;m++){let p=a[m],g=p.#e[h];g&&(g.#n=p.#n,u?(g.#e["*"]&&r.push(...this.#s(g.#e["*"],t,p.#n)),r.push(...this.#s(g,t,p.#n))):d.push(g));for(let x=0,B=p.#r.length;x<B;x++){let z=p.#r[x],E=p.#n===_?{}:{...p.#n};if(z==="*"){let S=p.#e["*"];S&&(r.push(...this.#s(S,t,p.#n)),S.#n=E,d.push(S));continue}let[jt,Se,L]=z;if(!h&&!(L instanceof RegExp))continue;let R=p.#e[jt],Ot=o.slice(c).join("/");if(L instanceof RegExp){let S=L.exec(Ot);if(S){if(E[Se]=S[0],r.push(...this.#s(R,t,p.#n,E)),Object.keys(R.#e).length){R.#n=E;let Tt=S[0].match(/\//)?.length??0;(i[Tt]||=[]).push(R)}continue}}(L===!0||L.test(h))&&(E[Se]=h,u?(r.push(...this.#s(R,t,E,p.#n)),R.#e["*"]&&r.push(...this.#s(R.#e["*"],t,E,p.#n))):(R.#n=E,d.push(R)))}}a=d.concat(i.shift()??[])}return r.length>1&&r.sort((c,l)=>c.score-l.score),[r.map(({handler:c,params:l})=>[c,l])]}};var me=class{name="TrieRouter";#t;constructor(){this.#t=new We}add(e,t,s){let r=G(t);if(r){for(let n=0,a=r.length;n<a;n++)this.#t.insert(e,r[n],s);return}this.#t.insert(e,t,s)}match(e,t){return this.#t.search(e,t)}};var ye=class extends Ne{constructor(e={}){super(e),this.router=e.router??new pe({routers:[new Y,new me]})}};import{join as Ct}from"node:path";function O(e){if(!e||typeof e!="string")throw new Error("Table name must be a non-empty string");if(e.length>255)throw new Error("Table name must not exceed 255 characters");if(e.includes("/")||e.includes("\\"))throw new Error("Table name must not contain path separators");if(e.includes(".."))throw new Error('Table name must not contain ".."');if(e.startsWith("."))throw new Error('Table name must not start with "."');if(e.includes("\0"))throw new Error("Table name must not contain null bytes");if(["CON","PRN","AUX","NUL","COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9"].includes(e.toUpperCase()))throw new Error(`Table name "${e}" is reserved by the filesystem`)}function Z(e){if(e==null)throw new Error("Key must be defined");if(typeof e!="string")throw new Error("Key must be a string");if(e.length===0)throw new Error("Key must not be empty");if(e.length>1024)throw new Error("Key must not exceed 1024 characters");if(e.includes("\0"))throw new Error("Key must not contain null bytes")}function Ke(e){if(e===void 0)throw new Error("Value must not be undefined (use null instead)");let t=typeof e;if(t==="function")throw new Error("Value must be JSON-serializable: functions are not supported");if(t==="symbol")throw new Error("Value must be JSON-serializable: symbols are not supported");try{if(JSON.stringify(e)===void 0)throw new Error("Value must be JSON-serializable: value cannot be serialized")}catch(s){throw new Error(`Value must be JSON-serializable: ${s instanceof Error?s.message:String(s)}`)}}function ee(e){if(!e.deflate&&!e.inflate)throw new Error("Dictionary must provide either deflate or inflate mapping");if(e.deflate&&e.inflate)throw new Error("Dictionary should provide only one of deflate or inflate (not both). The inverse will be auto-generated.");return e.deflate?{deflate:e.deflate,inflate:Je(e.deflate)}:{deflate:Je(e.inflate),inflate:e.inflate}}function Je(e){let t={};for(let[s,r]of Object.entries(e))t[r]=s;return t}function D(e,t){if(e==null||typeof e!="object")return e;if(Array.isArray(e))return e.map(r=>D(r,t));let s={};for(let[r,n]of Object.entries(e)){let a=t[r]||r;s[a]=D(n,t)}return s}import{existsSync as be,mkdirSync as Vt,readdirSync as Wt,openSync as Gt,closeSync as Kt}from"fs";import{readFile as Jt,writeFile as Qt,rename as Xt,unlink as Qe,open as Yt}from"fs/promises";import{join as ge,dirname as Zt}from"path";var we=class{data=new Map;databaseDirectory;dictionaries=new Map;useFsync;constructor(e){this.databaseDirectory=e.databaseDirectory,this.useFsync=e.durableWrites??!1,e.dictionaries&&Object.entries(e.dictionaries).forEach(([t,s])=>{let r=ee(s);this.dictionaries.set(t,r)}),be(this.databaseDirectory)||Vt(this.databaseDirectory,{recursive:!0})}async start(){try{let e=Wt(this.databaseDirectory);for(let t of e)!t.endsWith(".tmp")&&!t.startsWith(".")&&await this.loadTable(t)}catch(e){throw console.error("Failed to start database:",e),e}}async write(e,t,s,r,n){if(O(e),Z(t),Ke(s),n&&!this.dictionaries.has(n))throw new Error(`Dictionary "${n}" not found. Available dictionaries: ${Array.from(this.dictionaries.keys()).join(", ")||"none"}`);try{this.data.has(e)||this.data.set(e,new Map);let a=this.data.get(e),i=(a.get(t)?.version||0)+1,c={value:s,version:i,timestamp:Date.now(),expiration:r||null,dictionaryName:n||void 0};return a.set(t,c),await this.persistTable(e),!0}catch(a){return console.error(`Write failed for ${e}:${t}:`,a),!1}}async get(e,t){O(e),t!==void 0&&Z(t);try{this.data.has(e)||await this.loadTable(e);let s=this.data.get(e);if(!s)return t?void 0:[];if(t!==void 0){let a=s.get(t);if(!a)return;if(this.isExpired(a)){s.delete(t),await this.persistTable(e);return}return a.value}let r=[],n=[];for(let[a,o]of s.entries())this.isExpired(o)?n.push(a):r.push([a,o.value]);if(n.length>0){for(let a of n)s.delete(a);await this.persistTable(e)}return r}catch(s){return console.error(`Read failed for ${e}:${t}:`,s),t?void 0:[]}}async delete(e,t){O(e),Z(t);try{this.data.has(e)||await this.loadTable(e);let s=this.data.get(e);if(!s||!s.has(t))return!1;let r=s.get(t);return r?this.isExpired(r)?(s.delete(t),await this.persistTable(e),!1):(s.delete(t),await this.persistTable(e),!0):!1}catch(s){return console.error(`Delete failed for ${e}:${t}:`,s),!1}}async getTableSize(e){O(e);try{this.data.has(e)||await this.loadTable(e);let t=this.data.get(e);if(!t)return 0;let s=0,r=[];for(let[n,a]of t.entries())this.isExpired(a)?r.push(n):s++;if(r.length>0){for(let n of r)t.delete(n);await this.persistTable(e)}return s}catch(t){return console.error(`Get table size failed for ${e}:`,t),0}}isExpired(e){return e.expiration===null?!1:Date.now()>e.expiration}async cleanupExpired(e){O(e);try{this.data.has(e)||await this.loadTable(e);let t=this.data.get(e);if(!t)return 0;let s=[];for(let[r,n]of t.entries())this.isExpired(n)&&s.push(r);for(let r of s)t.delete(r);return s.length>0&&await this.persistTable(e),s.length}catch(t){return console.error(`Cleanup failed for ${e}:`,t),0}}async cleanupAllExpired(){let e=0;for(let t of this.data.keys())e+=await this.cleanupExpired(t);return e}async deleteTable(e){O(e);try{this.data.delete(e);let t=ge(this.databaseDirectory,e);return be(t)&&await Qe(t),!0}catch(t){return console.error(`Delete table failed for ${e}:`,t),!1}}listTables(){return Array.from(this.data.keys())}async flush(){try{let e=Array.from(this.data.keys()).map(t=>this.persistTable(t));await Promise.all(e)}catch(e){throw console.error("Flush failed:",e),e}}async close(){await this.flush()}addDictionary(e,t){let s=ee(t);this.dictionaries.set(e,s)}removeDictionary(e){return this.dictionaries.delete(e)}listDictionaries(){return Array.from(this.dictionaries.keys())}async loadTable(e){let t=ge(this.databaseDirectory,e);if(!be(t)){this.data.set(e,new Map);return}try{let s=await Jt(t);if(s.length===0){this.data.set(e,new Map);return}let r=this.deserializeTable(s);this.data.set(e,r)}catch(s){console.error(`Failed to load table ${e}:`,s),this.data.set(e,new Map)}}async persistTable(e){let t=this.data.get(e);if(!t)return;let s=this.serializeTable(t),r=ge(this.databaseDirectory,e),n=`${r}.tmp.${Date.now()}.${Math.random().toString(36).substring(7)}`;try{if(await Qt(n,s),this.useFsync){let a=await Yt(n,"r+");try{await a.sync()}finally{await a.close()}}if(await Xt(n,r),this.useFsync){let a=Zt(r),o=Gt(a,"r");try{Kt(o)}catch{}}}catch(a){try{await Qe(n)}catch{}throw a}}serializeTable(e){let t=Array.from(e.entries()).map(([s,r])=>{let n=r.dictionaryName?this.dictionaries.get(r.dictionaryName):void 0,a={d:n?D(r.value,n.deflate):r.value,v:r.version,t:r.timestamp,x:r.expiration};return r.dictionaryName&&(a.n=r.dictionaryName),[s,a]});return Buffer.from(JSON.stringify(t),"utf8")}deserializeTable(e){let s=JSON.parse(e.toString("utf8")).map(([r,n])=>{let a=n.n,o=a?this.dictionaries.get(a):void 0;return[r,{value:o?D(n.d,o.inflate):n.d,version:n.v,timestamp:n.t,expiration:n.x,dictionaryName:a||void 0}]});return new Map(s)}};import{createServer as er}from"http";import{Http2ServerRequest as tr}from"http2";import{Http2ServerRequest as ve}from"http2";import{Readable as Xe}from"stream";import dr from"crypto";var T=class extends Error{constructor(e,t){super(e,t),this.name="RequestError"}},rr=e=>e instanceof T?e:new T(e.message,{cause:e}),sr=global.Request,N=class extends sr{constructor(e,t){typeof e=="object"&&$ in e&&(e=e[$]()),typeof t?.body?.getReader<"u"&&(t.duplex??="half"),super(e,t)}},nr=e=>{let t=[],s=e.rawHeaders;for(let r=0;r<s.length;r+=2){let{[r]:n,[r+1]:a}=s;n.charCodeAt(0)!==58&&t.push([n,a])}return new Headers(t)},Ze=Symbol("wrapBodyStream"),ar=(e,t,s,r,n)=>{let a={method:e,headers:s,signal:n.signal};if(e==="TRACE"){a.method="GET";let o=new N(t,a);return Object.defineProperty(o,"method",{get(){return"TRACE"}}),o}if(!(e==="GET"||e==="HEAD"))if("rawBody"in r&&r.rawBody instanceof Buffer)a.body=new ReadableStream({start(o){o.enqueue(r.rawBody),o.close()}});else if(r[Ze]){let o;a.body=new ReadableStream({async pull(i){try{o||=Xe.toWeb(r).getReader();let{done:c,value:l}=await o.read();c?i.close():i.enqueue(l)}catch(c){i.error(c)}}})}else a.body=Xe.toWeb(r);return new N(t,a)},$=Symbol("getRequestCache"),or=Symbol("requestCache"),te=Symbol("incomingKey"),re=Symbol("urlKey"),ir=Symbol("headersKey"),k=Symbol("abortControllerKey"),cr=Symbol("getAbortController"),se={get method(){return this[te].method||"GET"},get url(){return this[re]},get headers(){return this[ir]||=nr(this[te])},[cr](){return this[$](),this[k]},[$](){return this[k]||=new AbortController,this[or]||=ar(this.method,this[re],this.headers,this[te],this[k])}};["body","bodyUsed","cache","credentials","destination","integrity","mode","redirect","referrer","referrerPolicy","signal","keepalive"].forEach(e=>{Object.defineProperty(se,e,{get(){return this[$]()[e]}})});["arrayBuffer","blob","clone","formData","json","text"].forEach(e=>{Object.defineProperty(se,e,{value:function(){return this[$]()[e]()}})});Object.setPrototypeOf(se,N.prototype);var lr=(e,t)=>{let s=Object.create(se);s[te]=e;let r=e.url||"";if(r[0]!=="/"&&(r.startsWith("http://")||r.startsWith("https://"))){if(e instanceof ve)throw new T("Absolute URL for :path is not allowed in HTTP/2");try{let i=new URL(r);s[re]=i.href}catch(i){throw new T("Invalid absolute URL",{cause:i})}return s}let n=(e instanceof ve?e.authority:e.headers.host)||t;if(!n)throw new T("Missing host header");let a;if(e instanceof ve){if(a=e.scheme,!(a==="http"||a==="https"))throw new T("Unsupported scheme")}else a=e.socket&&e.socket.encrypted?"https":"http";let o=new URL(`${a}://${n}${r}`);if(o.hostname.length!==n.length&&o.hostname!==n.replace(/:\d+$/,""))throw new T("Invalid host header");return s[re]=o.href,s},Ye=Symbol("responseCache"),H=Symbol("getResponseCache"),A=Symbol("cache"),Re=global.Response,F=class et{#t;#e;[H](){return delete this[A],this[Ye]||=new Re(this.#t,this.#e)}constructor(t,s){let r;if(this.#t=t,s instanceof et){let n=s[Ye];if(n){this.#e=n,this[H]();return}else this.#e=s.#e,r=new Headers(s.#e.headers)}else this.#e=s;(typeof t=="string"||typeof t?.getReader<"u"||t instanceof Blob||t instanceof Uint8Array)&&(r||=s?.headers||{"content-type":"text/plain; charset=UTF-8"},this[A]=[s?.status||200,t,r])}get headers(){let t=this[A];return t?(t[2]instanceof Headers||(t[2]=new Headers(t[2])),t[2]):this[H]().headers}get status(){return this[A]?.[0]??this[H]().status}get ok(){let t=this.status;return t>=200&&t<300}};["body","bodyUsed","redirected","statusText","trailers","type","url"].forEach(e=>{Object.defineProperty(F.prototype,e,{get(){return this[H]()[e]}})});["arrayBuffer","blob","clone","formData","json","text"].forEach(e=>{Object.defineProperty(F.prototype,e,{value:function(){return this[H]()[e]()}})});Object.setPrototypeOf(F,Re);Object.setPrototypeOf(F.prototype,Re.prototype);async function hr(e){return Promise.race([e,Promise.resolve().then(()=>Promise.resolve(void 0))])}function tt(e,t,s){let r=i=>{e.cancel(i).catch(()=>{})};return t.on("close",r),t.on("error",r),(s??e.read()).then(o,n),e.closed.finally(()=>{t.off("close",r),t.off("error",r)});function n(i){i&&t.destroy(i)}function a(){e.read().then(o,n)}function o({done:i,value:c}){try{if(i)t.end();else if(!t.write(c))t.once("drain",a);else return e.read().then(o,n)}catch(l){n(l)}}}function ur(e,t){if(e.locked)throw new TypeError("ReadableStream is locked.");return t.destroyed?void 0:tt(e.getReader(),t)}var rt=e=>{let t={};e instanceof Headers||(e=new Headers(e??void 0));let s=[];for(let[r,n]of e)r==="set-cookie"?s.push(n):t[r]=n;return s.length>0&&(t["set-cookie"]=s),t["content-type"]??="text/plain; charset=UTF-8",t},fr="x-hono-already-sent",pr=global.fetch;typeof global.crypto>"u"&&(global.crypto=dr);global.fetch=(e,t)=>(t={compress:!1,...t},pr(e,t));var xe=Symbol("outgoingEnded"),mr=()=>new Response(null,{status:400}),st=e=>new Response(null,{status:e instanceof Error&&(e.name==="TimeoutError"||e.constructor.name==="TimeoutError")?504:500}),Ee=(e,t)=>{let s=e instanceof Error?e:new Error("unknown error",{cause:e});s.code==="ERR_STREAM_PREMATURE_CLOSE"?console.info("The user aborted a request."):(console.error(e),t.headersSent||t.writeHead(500,{"Content-Type":"text/plain"}),t.end(`Error: ${s.message}`),t.destroy(s))},nt=e=>{"flushHeaders"in e&&e.writable&&e.flushHeaders()},at=async(e,t)=>{let[s,r,n]=e[A];n instanceof Headers&&(n=rt(n)),typeof r=="string"?n["Content-Length"]=Buffer.byteLength(r):r instanceof Uint8Array?n["Content-Length"]=r.byteLength:r instanceof Blob&&(n["Content-Length"]=r.size),t.writeHead(s,n),typeof r=="string"||r instanceof Uint8Array?t.end(r):r instanceof Blob?t.end(new Uint8Array(await r.arrayBuffer())):(nt(t),await ur(r,t)?.catch(a=>Ee(a,t))),t[xe]?.()},yr=e=>typeof e.then=="function",br=async(e,t,s={})=>{if(yr(e))if(s.errorHandler)try{e=await e}catch(n){let a=await s.errorHandler(n);if(!a)return;e=a}else e=await e.catch(st);if(A in e)return at(e,t);let r=rt(e.headers);if(e.body){let n=e.body.getReader(),a=[],o=!1,i;if(r["transfer-encoding"]!=="chunked"){let c=2;for(let l=0;l<c;l++){i||=n.read();let h=await hr(i).catch(u=>{console.error(u),o=!0});if(!h){if(l===1){await new Promise(u=>setTimeout(u)),c=3;continue}break}if(i=void 0,h.value&&a.push(h.value),h.done){o=!0;break}}o&&!("content-length"in r)&&(r["content-length"]=a.reduce((l,h)=>l+h.length,0))}t.writeHead(e.status,r),a.forEach(c=>{t.write(c)}),o?t.end():(a.length===0&&nt(t),await tt(n,t,i))}else r[fr]||(t.writeHead(e.status,r),t.end());t[xe]?.()},gr=(e,t={})=>{let s=t.autoCleanupIncoming??!0;return t.overrideGlobalObjects!==!1&&global.Request!==N&&(Object.defineProperty(global,"Request",{value:N}),Object.defineProperty(global,"Response",{value:F})),async(r,n)=>{let a,o;try{o=lr(r,t.hostname);let i=!s||r.method==="GET"||r.method==="HEAD";if(i||(r[Ze]=!0,r.on("end",()=>{i=!0}),r instanceof tr&&(n[xe]=()=>{i||setTimeout(()=>{i||setTimeout(()=>{r.destroy(),n.destroy()})})})),n.on("close",()=>{o[k]&&(r.errored?o[k].abort(r.errored.toString()):n.writableFinished||o[k].abort("Client connection prematurely closed.")),i||setTimeout(()=>{i||setTimeout(()=>{r.destroy()})})}),a=e(o,{incoming:r,outgoing:n}),A in a)return at(a,n)}catch(i){if(a)return Ee(i,n);if(t.errorHandler){if(a=await t.errorHandler(o?i:rr(i)),!a)return}else o?a=st(i):a=mr()}try{return await br(a,n,t)}catch(i){return Ee(i,n)}}},wr=e=>{let t=e.fetch,s=gr(t,{hostname:e.hostname,overrideGlobalObjects:e.overrideGlobalObjects,autoCleanupIncoming:e.autoCleanupIncoming});return(e.createServer||er)(e.serverOptions||{},s)},ot=(e,t)=>{let s=wr(e);return s.listen(e?.port??3e3,e.hostname,()=>{let r=s.address();t&&t(r)}),s};import{statSync as Hr}from"node:fs";import{readFileSync as vr,existsSync as Er}from"node:fs";function it(){let e=process.env.MOLNOS_RUNTIME_CONFIG;if(!e||!Er(e))return{molnos:{dataPath:"data"},server:{host:"localhost",port:3e3}};try{let t=vr(e,"utf-8");return JSON.parse(t)}catch(t){return console.error("[loadRuntimeConfig] Failed to load runtime config:",t),{molnos:{dataPath:"data"},server:{host:"localhost",port:3e3}}}}var w=class{isSilent;propertyPath="";constructor(e=!1){this.isSilent=e}test(e,t){if(!t)throw new Error("Missing input!");this.updatePropertyPath();let{results:s,errors:r}=this.validate(e.properties,t),n=this.compileErrors(s,r),a=this.isSuccessful(s,n);return{errors:n,success:a}}compileErrors(e,t){let s=e.filter(r=>r.success===!1);return[...t,...s].flatMap(r=>r)}isSuccessful(e,t){return e.every(s=>s.success===!0)&&t.length===0}validate(e,t,s=[],r=[]){let n=e?.additionalProperties??!0,a=e?.required||[];r=this.checkForRequiredKeysErrors(a,t,r),r=this.checkForDisallowedProperties(Object.keys(t),Object.keys(e),r,n);for(let o in e){let i=a.includes(o)&&o!=="required",c=e[o],l=t[o],h=c.additionalProperties??!0;i&&(r=this.checkForRequiredKeysErrors(c.required||[],l,r)),this.isDefined(l)&&(this.handleValidation(o,l,c,s),r=this.checkForDisallowedProperties(Object.keys(l),Object.keys(c),r,h),this.handleNestedObject(l,c,s,r))}return{results:s,errors:r}}updatePropertyPath(e,t=""){if(!e){this.propertyPath="";return}t&&(this.propertyPath=t),this.propertyPath=`${this.propertyPath}.${e}`,this.propertyPath.startsWith(".")&&(this.propertyPath=this.propertyPath.substring(1,this.propertyPath.length))}isDefined(e){return!!(typeof e=="number"&&e===0||e||e===""||typeof e=="boolean")}checkForRequiredKeysErrors(e,t,s){if(!this.areRequiredKeysPresent(e,t)){let r=t?Object.keys(t):[],n=this.findNonOverlappingElements(e,r),a=n.length>0?`Missing the required key: '${n.join(", ")}'!`:`Missing values for required keys: '${r.filter(o=>!t[o]).join(", ")}'!`;s.push({key:"",value:t,success:!1,error:a})}return s}checkForDisallowedProperties(e,t,s,r){if(!r){let n=this.findNonOverlappingElements(e,t);n.length>0&&s.push({key:`${t}`,value:e,success:!1,error:`Has additional (disallowed) properties: '${n.join(", ")}'!`})}return s}handleValidation(e,t,s,r){this.updatePropertyPath(e);let n=this.validateProperty(this.propertyPath,s,t);r.push(...n);let a=(i,c)=>{i.forEach(l=>{let h=this.validateProperty(this.propertyPath,c.items,l);r.push(...h)}),this.updatePropertyPath()},o=i=>{let c=Object.keys(i),l=this.propertyPath;c.forEach(h=>{if(this.updatePropertyPath(h,l),this.isArray(i[h])&&s[h]?.items!=null)a(i[h],s[h]);else{let u=this.validateProperty(this.propertyPath,s[h],i[h]);r.push(...u)}})};this.isArray(t)&&s.items!=null?a(t,s):this.isObject(t)?o(t):this.updatePropertyPath()}handleNestedObject(e,t,s,r){if(this.isObject(e)){let n=this.getNestedObjects(e);for(let a of n){let o=t[a],i=e[a];o&&typeof i=="object"&&this.validate(o,i,s,r)}}}getNestedObjects(e){return Object.keys(e).filter(t=>{if(this.isObject(e))return t})}findNonOverlappingElements(e,t){return e.filter(s=>!t.includes(s))}areRequiredKeysPresent(e,t=[]){return e.every(s=>Object.keys(t).includes(s)?this.isDefined(t[s]):!1)}validateProperty(e,t,s){return this.validateInput(t,s).map(n=>{let{success:a,error:o}=n;return{key:e,value:s,success:a,error:o??""}})}validateInput(e,t){if(e){let s=[{condition:()=>e.type,validator:()=>this.isCorrectType(e.type,t),error:"Invalid type"},{condition:()=>e.format,validator:()=>this.isCorrectFormat(e.format,t),error:"Invalid format"},{condition:()=>e.minLength,validator:()=>this.isMinimumLength(e.minLength,t),error:"Length too short"},{condition:()=>e.maxLength,validator:()=>this.isMaximumLength(e.maxLength,t),error:"Length too long"},{condition:()=>e.minValue,validator:()=>this.isMinimumValue(e.minValue,t),error:"Value too small"},{condition:()=>e.maxValue,validator:()=>this.isMaximumValue(e.maxValue,t),error:"Value too large"},{condition:()=>e.matchesPattern,validator:()=>this.matchesPattern(e.matchesPattern,t),error:"Pattern does not match"}],r=[];for(let n of s)n.condition()&&!n.validator()&&r.push({success:!1,error:n.error});return r}else this.isSilent||console.warn(`Missing property '${e}' for match '${t}'. Skipping...`);return[{success:!0}]}isCorrectType(e,t){return Array.isArray(e)||(e=[e]),e.some(s=>{switch(s){case"string":return typeof t=="string";case"number":return typeof t=="number"&&!isNaN(t);case"boolean":return typeof t=="boolean";case"object":return this.isObject(t);case"array":return this.isArray(t)}})}isObject(e){return e!==null&&!this.isArray(e)&&typeof e=="object"&&e instanceof Object&&Object.prototype.toString.call(e)==="[object Object]"}isArray(e){return Array.isArray(e)}isCorrectFormat(e,t){switch(e){case"alphanumeric":return new RegExp(/^[a-zA-Z0-9]+$/).test(t);case"numeric":return new RegExp(/^-?\d+(\.\d+)?$/).test(t);case"email":return new RegExp(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/).test(t);case"date":return new RegExp(/^\d{4}-\d{2}-\d{2}$/).test(t);case"url":return new RegExp(/^(https?):\/\/[^\s$.?#].[^\s]*$/).test(t);case"hexColor":return new RegExp(/^#?([a-f0-9]{6}|[a-f0-9]{3})$/i).test(t)}}isMinimumLength(e,t){return Array.isArray(t)?t.length>=e:t?.toString().length>=e}isMaximumLength(e,t){return Array.isArray(t)?t.length<=e:t.toString().length<=e}isMinimumValue(e,t){return t>=e}isMaximumValue(e,t){return t<=e}matchesPattern(e,t){return new RegExp(e).test(t)}schemaFrom(e){let t={properties:{additionalProperties:!1,required:[]}};for(let s in e){let r=e[s];t.properties.required.push(s),Array.isArray(r)?t.properties[s]=this.generateArraySchema(r):typeof r=="object"&&r!==null?t.properties[s]=this.generateNestedObjectSchema(r):t.properties[s]=this.generatePropertySchema(r)}return t}generateArraySchema(e){let t={type:"array"},s=e.filter(r=>r);if(s.length>0){let r=s[0];s.every(a=>typeof a==typeof r)?typeof r=="object"&&!Array.isArray(r)?t.items=this.generateNestedObjectSchema(r):t.items=this.generatePropertySchema(r):console.warn("All elements in array are not of the same type. Unable to generate a schema for these elements.")}return t}generateNestedObjectSchema(e){let t={type:"object",additionalProperties:!1,required:[]};for(let s in e){let r=e[s];t.required.push(s),typeof r=="object"&&!Array.isArray(r)&&r!==null?t[s]=this.generateNestedObjectSchema(r):t[s]=this.generatePropertySchema(r)}return t}generatePropertySchema(e){let t=typeof e,s={type:t};return t==="string"&&(s.minLength=1),s}};async function ne(e){try{return await e.req.json()}catch{return{}}}function y(e,t="An error occurred"){let s=e?.message||e||t,r=e?.cause?.statusCode||e?.statusCode||400;return{message:s,status:r}}function ct(e,t,s={}){let r=Array.isArray(t)?t:[t];if(!e||!e.roles||!Array.isArray(e.roles)){let o=new Error("Unauthorized: User or roles missing");throw o.cause={statusCode:403},o}let n=e.roles.flatMap(o=>o?.policies?.flatMap(i=>(i?.permissions||[]).flatMap(l=>typeof l=="string"?l:l&&typeof l=="object"&&l.actions?l.actions:[]))||[]);if(!r.every(o=>n.includes(o)||n.includes("*")?!0:n.some(i=>{if(i.endsWith(".*")){let c=i.slice(0,-2);return o.startsWith(`${c}.`)}return!1}))){let o=new Error("Unauthorized");throw o.cause={statusCode:403},o}return!0}function lt(e,t,s,r,n){let a=e.find(c=>c.service===t);if(!a){let c=new Error(`Function bindings do not include access to service: ${t}`);throw c.cause={statusCode:403},c}if(!a.permissions||a.permissions.length===0)return;for(let c of a.permissions)if(!(c.resource&&c.resource!==s)){if(!c.resource||!c.actions||c.actions.length===0)return;if(c.actions.includes(r)){if(c.targets&&c.targets.length>0){if(!n)return;if(!c.targets.includes(n))continue}return}}let o=n?`:${n}`:"",i=new Error(`Function bindings do not allow: ${t}.${s}.${r}${o}`);throw i.cause={statusCode:403},i}async function b(e,t,s,r,n,a,o){if(!t)return null;let i=e.get("user");if(!i){let l=e.req.header("authorization");if(!l){let u=new Error("Unauthorized: No authentication provided");throw u.cause={statusCode:401},u}let h=l.replace(/^Bearer\s+/i,"");if(i=await t.getUserFromToken(h),!i){let u=new Error("Unauthorized: Invalid token");throw u.cause={statusCode:401},u}}ct(i,s,{});let c=e.req.header("x-function-bindings");if(c)try{let l=JSON.parse(c);lt(l,r,n,a,o)}catch(l){if(l.cause?.statusCode===403)throw l;let h=new Error("Invalid function bindings header");throw h.cause={statusCode:400},h}return i}var ht={properties:{tableName:{type:"string",minLength:1},key:{type:"string"}},required:["tableName"],additionalProperties:!1};var xr=new w;async function ut(e,t,s){try{let r=await ne(e),n=xr.test(ht,r);if(!n.success)return e.json({error:"Invalid input",details:n.errors},400);let{tableName:a,key:o}=r;if(!a)return e.json("tableName is required",400);await b(e,s,"databases.table.get","databases","table","read",a);let i=await t.get(a,o);return i?e.json(i,200):e.json(null,404)}catch(r){let{message:n,status:a}=y(r,"Error getting table data");return e.text(n,a)}}var ft={properties:{tableName:{type:"string",minLength:1},key:{type:"string"},value:{},expiration:{type:"number"},dictionaryName:{type:"string"}},required:["tableName"],additionalProperties:!1};var Pr=new w;async function dt(e,t,s){try{let r=await ne(e),n=Pr.test(ft,r);if(!n.success)return e.json({error:"Invalid input",details:n.errors},400);let{tableName:a,key:o,value:i,expiration:c,dictionaryName:l}=r;if(!a||i===void 0)return e.json("tableName and value are required",400);await b(e,s,"databases.table.update","databases","table","write",a);let h=await t.write(a,o,i,c,l);return e.json(h,200)}catch(r){let{message:n,status:a}=y(r,"Error writing table data");return e.text(n,a)}}var pt={properties:{tableName:{type:"string",minLength:1},key:{type:"string",minLength:1}},required:["tableName","key"],additionalProperties:!1};var jr=new w;async function mt(e,t,s){try{let r=e.req.query(),n=jr.test(pt,r);if(!n.success)return e.json({error:"Invalid input",details:n.errors},400);let{tableName:a,key:o}=r;if(!a||!o)return e.json("tableName and key are required",400);await b(e,s,"databases.table.delete","databases","table","delete",a);let i=await t.delete(a,o);return e.json(i,200)}catch(r){let{message:n,status:a}=y(r,"Error deleting table item");return e.text(n,a)}}async function yt(e,t,s,r,n,a){try{await b(e,s,"databases.table.get","databases","table","read");let o=t.listTables(),i=await Promise.all(o.map(async c=>{let l=await t.getTableSize(c),h=n(r,c);return{name:c,items:l,size:a(h)}}));return e.json({tables:i},200)}catch(o){let{message:i,status:c}=y(o,"Error listing tables");return e.text(i,c)}}var P={properties:{tableName:{type:"string",minLength:1}},required:["tableName"],additionalProperties:!1};var Tr=new w;async function bt(e,t,s){try{let{tableName:r}=e.req.param();if(!r)return e.json({error:"tableName is required"},400);let n=Tr.test(P,{tableName:r});return n.success?(await b(e,s,"databases.table.create","databases","table","create",r),t.listTables().includes(r)?e.json({error:"Table already exists"},409):(await t.write(r,"__init__",null),await t.delete(r,"__init__"),e.json({success:!0,name:r,message:"Table created successfully"},201))):e.json({error:"Invalid input",details:n.errors},400)}catch(r){let{message:n,status:a}=y(r,"Error creating table");return e.text(n,a)}}var Ar=new w;async function gt(e,t,s){try{let{tableName:r}=e.req.param();if(!r)return e.json({error:"tableName is required"},400);let n=Ar.test(P,{tableName:r});if(!n.success)return e.json({error:"Invalid input",details:n.errors},400);if(await b(e,s,"databases.table.delete","databases","table","delete",r),!t.listTables().includes(r))return e.json({error:"Table not found"},404);let o=await t.deleteTable(r);return e.json({success:o,name:r,message:"Table deleted successfully"},200)}catch(r){let{message:n,status:a}=y(r,"Error deleting table");return e.text(n,a)}}var Mr=new w;async function wt(e,t,s,r,n,a){try{let{tableName:o}=e.req.param();if(!o)return e.json({error:"tableName is required"},400);let i=Mr.test(P,{tableName:o});if(!i.success)return e.json({error:"Invalid input",details:i.errors},400);if(await b(e,s,"databases.table.get","databases","table","read",o),!t.listTables().includes(o))return e.json({error:"Table not found"},404);let l=await t.getTableSize(o),h=n(r,o);return e.json({name:o,items:l,size:a(h)},200)}catch(o){let{message:i,status:c}=y(o,"Error getting table info");return e.text(i,c)}}async function vt(e,t,s){try{let r=e.req.query();if(!r.tableName)return e.json({error:"tableName is required"},400);let{tableName:n}=r;await b(e,s,"databases.table.get","databases","table","read",n);let a=await t.get(n),o=a?a.length:0;return e.json(o,200)}catch(r){let{message:n,status:a}=y(r,"Error getting table size");return e.text(n,a)}}var Dr=new w;async function Et(e,t,s){try{let{tableName:r}=e.req.param();if(!r)return e.json({error:"tableName is required"},400);let n=Dr.test(P,{tableName:r});if(!n.success)return e.json({error:"Invalid input",details:n.errors},400);if(await b(e,s,"databases.table.get","databases","table","read",r),!t.listTables().includes(r))return e.json({error:"Table not found"},404);let o=await t.get(r),i=o?Object.entries(o).map(([c,l])=>Array.isArray(l)&&l.length===2?{key:l[0],value:l[1]}:{key:c,value:l}):[];return e.json({items:i},200)}catch(r){let{message:n,status:a}=y(r,"Error getting table items");return e.text(n,a)}}function Rt(e){if(e===0)return"0 B";let t=["B","KB","MB","GB"],s=Math.floor(Math.log(e)/Math.log(1024));return`${(e/1024**s).toFixed(1)} ${t[s]}`}function xt(e,t){try{let s=Ct(e,t);return Hr(s).size}catch{return 0}}async function kr(e){let t=e.dataPath||"data",s=Ct(t,"databases"),r=new we({databaseDirectory:e.db?.databaseDirectory||s});await r.start();let n=e.identityService||null,a=new ye;return a.get("/table",async o=>vt(o,r,n)),a.post("/get",async o=>ut(o,r,n)),a.post("/write",async o=>dt(o,r,n)),a.delete("/delete",async o=>mt(o,r,n)),a.get("/tables",async o=>yt(o,r,n,s,xt,Rt)),a.post("/tables/:tableName",async o=>bt(o,r,n)),a.delete("/tables/:tableName",async o=>gt(o,r,n)),a.get("/tables/:tableName",async o=>wt(o,r,n,s,xt,Rt)),a.get("/tables/:tableName/items",async o=>Et(o,r,n)),ot({fetch:a.fetch,port:e.server.port||3004,hostname:e.server.host||"localhost"}),console.log(`Database server started on ${e.server.host||"localhost"}:${e.server.port||3004}`),a}var $r=process.argv.slice(2),St=$r.find(e=>e.startsWith("--port=")),Lr=St?parseInt(St.split("=")[1],10):3004,Pt=it(),Ir={molnos:{dataPath:Pt.molnos.dataPath},db:{},server:{port:Lr,host:Pt.server.host}};kr(Ir);export{kr as startServer};
2
+ var N=class{requests=new Map;limit;windowMs;constructor(e=100,t=60){this.limit=e,this.windowMs=t*1e3,setInterval(()=>this.cleanup(),this.windowMs)}getLimit(){return this.limit}isAllowed(e){let t=Date.now(),s=e||"unknown",r=this.requests.get(s);return(!r||r.resetTime<t)&&(r={count:0,resetTime:t+this.windowMs},this.requests.set(s,r)),r.count++,r.count<=this.limit}getRemainingRequests(e){let t=Date.now(),s=e||"unknown",r=this.requests.get(s);return!r||r.resetTime<t?this.limit:Math.max(0,this.limit-r.count)}getResetTime(e){let t=Date.now(),s=e||"unknown",r=this.requests.get(s);return!r||r.resetTime<t?Math.floor((t+this.windowMs)/1e3):Math.floor(r.resetTime/1e3)}cleanup(){let e=Date.now();for(let[t,s]of this.requests.entries())s.resetTime<e&&this.requests.delete(t)}};import{URL as ue}from"url";var D=class{routes=[];globalMiddlewares=[];pathPatterns=new Map;use(e){return this.globalMiddlewares.push(e),this}get(e,...t){let s=t.pop();return this.register("GET",e,s,t)}post(e,...t){let s=t.pop();return this.register("POST",e,s,t)}put(e,...t){let s=t.pop();return this.register("PUT",e,s,t)}delete(e,...t){let s=t.pop();return this.register("DELETE",e,s,t)}patch(e,...t){let s=t.pop();return this.register("PATCH",e,s,t)}any(e,...t){let s=t.pop(),r=t;return this.register("GET",e,s,r),this.register("POST",e,s,r),this.register("PUT",e,s,r),this.register("DELETE",e,s,r),this.register("PATCH",e,s,r),this.register("OPTIONS",e,s,r),this}options(e,...t){let s=t.pop();return this.register("OPTIONS",e,s,t)}match(e,t){for(let s of this.routes){if(s.method!==e)continue;let r=this.pathPatterns.get(s.path);if(!r)continue;let i=r.pattern.exec(t);if(!i)continue;let n={};return r.paramNames.forEach((o,a)=>{n[o]=i[a+1]||""}),{route:s,params:n}}return null}async handle(e,t){let s=e.method||"GET",r=new ue(e.url||"/",`http://${e.headers.host}`),i=r.pathname,n=this.match(s,i);if(!n)return null;let{route:o,params:a}=n,l={};r.searchParams.forEach((c,u)=>{l[u]=c});let d={req:e,res:t,params:a,query:l,body:e.body||{},headers:e.headers,path:i,state:{},raw:()=>t,binary:(c,u="application/octet-stream",y=200)=>({statusCode:y,body:c,headers:{"Content-Type":u,"Content-Length":c.length.toString()},isRaw:!0}),text:(c,u=200)=>({statusCode:u,body:c,headers:{"Content-Type":"text/plain"}}),form:(c,u=200)=>({statusCode:u,body:c,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),json:(c,u=200)=>({statusCode:u,body:c,headers:{"Content-Type":"application/json"}}),html:(c,u=200)=>({statusCode:u,body:c,headers:{"Content-Type":"text/html"}}),redirect:(c,u=302)=>({statusCode:u,body:null,headers:{Location:c}}),status:function(c){return{raw:()=>t,binary:(u,y="application/octet-stream")=>({statusCode:c,body:u,headers:{"Content-Type":y,"Content-Length":u.length.toString()},isRaw:!0}),text:u=>({statusCode:c,body:u,headers:{"Content-Type":"text/plain"}}),json:u=>({statusCode:c,body:u,headers:{"Content-Type":"application/json"}}),html:u=>({statusCode:c,body:u,headers:{"Content-Type":"text/html"}}),form:u=>({statusCode:c,body:u,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),redirect:(u,y=302)=>({statusCode:y,body:null,headers:{Location:u}}),status:u=>this.status(u)}}},f=[...this.globalMiddlewares,...o.middlewares];return this.executeMiddlewareChain(d,f,o.handler)}register(e,t,s,r=[]){return this.routes.push({method:e,path:t,handler:s,middlewares:r}),this.pathPatterns.set(t,this.createPathPattern(t)),this}createPathPattern(e){let t=[],s=e.replace(/\/:[^/]+/g,r=>{let i=r.slice(2);return t.push(i),"/([^/]+)"});return s.endsWith("/*")?(s=`${s.slice(0,-2)}(?:/(.*))?`,t.push("wildcard")):s=s.replace(/\/$/,"/?"),{pattern:new RegExp(`^${s}$`),paramNames:t}}async executeMiddlewareChain(e,t,s){let r=0,i=async()=>{if(r<t.length){let n=t[r++];return n(e,i)}return s(e)};return i()}};var E=()=>({port:Number(process.env.PORT)||3e3,host:process.env.HOST||"0.0.0.0",useHttps:!1,useHttp2:!1,sslCert:"",sslKey:"",sslCa:"",debug:fe(process.env.DEBUG)||!1,maxBodySize:1048576,requestTimeout:3e4,rateLimit:{enabled:!0,requestsPerMinute:100},allowedDomains:["*"]});function fe(e){return e==="true"||e===!0}var A=class extends Error{constructor(e){super(e),this.name="ValidationError",this.message=e||"Validation did not pass",this.cause={statusCode:400}}};import{existsSync as he,readFileSync as pe}from"node:fs";var O=class{config={};options=[];validators=[];autoValidate=!0;constructor(e){let t=e?.configFilePath,s=e?.args||[],r=e?.config||{};this.options=e?.options||[],this.validators=e?.validators||[],e?.autoValidate!==void 0&&(this.autoValidate=e.autoValidate),this.config=this.createConfig(t,s,r)}deepMerge(e,t){let s={...e};for(let r in t)t[r]!==void 0&&(t[r]!==null&&typeof t[r]=="object"&&!Array.isArray(t[r])&&r in e&&e[r]!==null&&typeof e[r]=="object"&&!Array.isArray(e[r])?s[r]=this.deepMerge(e[r],t[r]):t[r]!==void 0&&(s[r]=t[r]));return s}setValueAtPath(e,t,s){let r=t.split("."),i=e;for(let o=0;o<r.length-1;o++){let a=r[o];!(a in i)||i[a]===null?i[a]={}:typeof i[a]!="object"&&(i[a]={}),i=i[a]}let n=r[r.length-1];i[n]=s}getValueAtPath(e,t){let s=t.split("."),r=e;for(let i of s){if(r==null)return;r=r[i]}return r}createConfig(e,t=[],s={}){let r={};for(let a of this.options)a.defaultValue!==void 0&&this.setValueAtPath(r,a.path,a.defaultValue);let i={};if(e&&he(e))try{let a=pe(e,"utf8");i=JSON.parse(a),console.log(`Loaded configuration from ${e}`)}catch(a){console.error(`Error reading config file: ${a instanceof Error?a.message:String(a)}`)}let n=this.parseCliArgs(t),o=this.deepMerge({},r);return o=this.deepMerge(o,i),o=this.deepMerge(o,s),o=this.deepMerge(o,n),o}parseCliArgs(e){let t={},s=e[0]?.endsWith("node")||e[0]?.endsWith("node.exe")?2:0;for(;s<e.length;){let r=e[s++],i=this.options.find(n=>n.flag===r);if(i)if(i.isFlag)this.setValueAtPath(t,i.path,!0);else if(s<e.length&&!e[s].startsWith("-")){let n=e[s++];if(i.parser)try{n=i.parser(n)}catch(o){console.error(`Error parsing value for ${i.flag}: ${o instanceof Error?o.message:String(o)}`);continue}if(i.validator){let o=i.validator(n);if(o!==!0&&typeof o=="string"){console.error(`Invalid value for ${i.flag}: ${o}`);continue}if(o===!1){console.error(`Invalid value for ${i.flag}`);continue}}this.setValueAtPath(t,i.path,n)}else console.error(`Missing value for option ${r}`)}return t}validate(){for(let e of this.validators){let t=this.getValueAtPath(this.config,e.path),s=e.validator(t,this.config);if(s===!1)throw new A(e.message);if(typeof s=="string")throw new A(s)}}get(){return this.autoValidate&&this.validate(),this.config}getValue(e,t){let s=this.getValueAtPath(this.config,e);return s!==void 0?s:t}setValue(e,t){if(typeof t=="object"&&t!==null&&!Array.isArray(t)){let s=this.getValueAtPath(this.config,e)||{};if(typeof s=="object"&&!Array.isArray(s)){let r=this.deepMerge(s,t);this.setValueAtPath(this.config,e,r);return}}this.setValueAtPath(this.config,e,t)}getHelpText(){let e=`Available configuration options:
3
+
4
+ `;for(let t of this.options)e+=`${t.flag}${t.isFlag?"":" <value>"}
5
+ `,t.description&&(e+=` ${t.description}
6
+ `),t.defaultValue!==void 0&&(e+=` Default: ${JSON.stringify(t.defaultValue)}
7
+ `),e+=`
8
+ `;return e}};var I={int:e=>{let t=e.trim();if(!/^[+-]?\d+$/.test(t))throw new Error(`Cannot parse "${e}" as an integer`);let s=Number.parseInt(t,10);if(Number.isNaN(s))throw new Error(`Cannot parse "${e}" as an integer`);return s},float:e=>{let t=e.trim();if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(t)){if(t==="Infinity"||t==="-Infinity")return t==="Infinity"?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY;throw new Error(`Cannot parse "${e}" as a number`)}let s=Number.parseFloat(t);if(Number.isNaN(s))throw new Error(`Cannot parse "${e}" as a number`);return s},boolean:e=>{let t=e.trim().toLowerCase();if(["true","yes","1","y"].includes(t))return!0;if(["false","no","0","n"].includes(t))return!1;throw new Error(`Cannot parse "${e}" as a boolean`)},array:e=>e.split(",").map(t=>t.trim()),json:e=>{try{return JSON.parse(e)}catch{throw new Error(`Cannot parse "${e}" as JSON`)}}};var g=E(),q=e=>({configFilePath:"mikroserve.config.json",args:process.argv,options:[{flag:"--port",path:"port",defaultValue:g.port},{flag:"--host",path:"host",defaultValue:g.host},{flag:"--https",path:"useHttps",defaultValue:g.useHttps,isFlag:!0},{flag:"--http2",path:"useHttp2",defaultValue:g.useHttp2,isFlag:!0},{flag:"--cert",path:"sslCert",defaultValue:g.sslCert},{flag:"--key",path:"sslKey",defaultValue:g.sslKey},{flag:"--ca",path:"sslCa",defaultValue:g.sslCa},{flag:"--ratelimit",path:"rateLimit.enabled",defaultValue:g.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"rateLimit.requestsPerMinute",defaultValue:g.rateLimit.requestsPerMinute},{flag:"--allowed",path:"allowedDomains",defaultValue:g.allowedDomains,parser:I.array},{flag:"--debug",path:"debug",defaultValue:g.debug,isFlag:!0},{flag:"--max-body-size",path:"maxBodySize",defaultValue:g.maxBodySize},{flag:"--request-timeout",path:"requestTimeout",defaultValue:g.requestTimeout}],config:e});function z(e,t){let s=t.match(/boundary=(?:"([^"]+)"|([^;]+))/i);if(!s)throw new Error("Invalid multipart/form-data: missing boundary");let r=s[1]||s[2],i=Buffer.from(`--${r}`),n=Buffer.from(`--${r}--`),o={},a={},l=me(e,i);for(let d of l){if(d.length===0||d.equals(n.subarray(i.length)))continue;let f=ye(d);if(!f)continue;let{name:c,filename:u,contentType:y,data:w}=f;if(u){let b={filename:u,contentType:y||"application/octet-stream",data:w,size:w.length};a[c]?Array.isArray(a[c])?a[c].push(b):a[c]=[a[c],b]:a[c]=b}else{let b=w.toString("utf8");o[c]?Array.isArray(o[c])?o[c].push(b):o[c]=[o[c],b]:o[c]=b}}return{fields:o,files:a}}function me(e,t){let s=[],r=0;for(;r<e.length;){let i=e.indexOf(t,r);if(i===-1)break;r!==i&&s.push(e.subarray(r,i)),r=i+t.length,r<e.length&&e[r]===13&&e[r+1]===10&&(r+=2)}return s}function ye(e){let t=Buffer.from(`\r
9
+ \r
10
+ `),s=e.indexOf(t);if(s===-1)return null;let r=e.subarray(0,s),i=e.subarray(s+4),o=r.toString("utf8").split(`\r
11
+ `),a="",l="",d,f;for(let u of o){let y=u.toLowerCase();if(y.startsWith("content-disposition:")){a=u.substring(20).trim();let w=a.match(/name="([^"]+)"/);w&&(l=w[1]);let b=a.match(/filename="([^"]+)"/);b&&(d=b[1])}else y.startsWith("content-type:")&&(f=u.substring(13).trim())}if(!l)return null;let c=i;return c.length>=2&&c[c.length-2]===13&&c[c.length-1]===10&&(c=c.subarray(0,c.length-2)),{disposition:a,name:l,filename:d,contentType:f,data:c}}import{readFileSync as S}from"fs";import $ from"http";import ge from"http2";import be from"https";var k=class{config;rateLimiter;router;shutdownHandlers=[];constructor(e){let t=new O(q(e||{})).get();t.debug&&console.log("Using configuration:",t),this.config=t,this.router=new D;let s=t.rateLimit.requestsPerMinute||E().rateLimit.requestsPerMinute;this.rateLimiter=new N(s,60),t.rateLimit.enabled===!0&&this.use(this.rateLimitMiddleware.bind(this))}use(e){return this.router.use(e),this}get(e,...t){return this.router.get(e,...t),this}post(e,...t){return this.router.post(e,...t),this}put(e,...t){return this.router.put(e,...t),this}delete(e,...t){return this.router.delete(e,...t),this}patch(e,...t){return this.router.patch(e,...t),this}any(e,...t){return this.router.any(e,...t),this}options(e,...t){return this.router.options(e,...t),this}start(){let e=this.createServer(),{port:t,host:s}=this.config;return this.setupGracefulShutdown(e),e.listen(t,s,()=>{let r=e.address(),i=this.config.useHttps||this.config.useHttp2?"https":"http";console.log(`MikroServe running at ${i}://${r.address!=="::"?r.address:"localhost"}:${r.port}`)}),e}createServer(){let e=this.requestHandler.bind(this);if(this.config.useHttp2){if(!this.config.sslCert||!this.config.sslKey)throw new Error("SSL certificate and key paths are required when useHttp2 is true");try{let t={key:S(this.config.sslKey),cert:S(this.config.sslCert),...this.config.sslCa?{ca:S(this.config.sslCa)}:{}};return ge.createSecureServer(t,e)}catch(t){throw t.message.includes("key values mismatch")?new Error(`SSL certificate and key do not match: ${t.message}`):t}}else if(this.config.useHttps){if(!this.config.sslCert||!this.config.sslKey)throw new Error("SSL certificate and key paths are required when useHttps is true");try{let t={key:S(this.config.sslKey),cert:S(this.config.sslCert),...this.config.sslCa?{ca:S(this.config.sslCa)}:{}};return be.createServer(t,e)}catch(t){throw t.message.includes("key values mismatch")?new Error(`SSL certificate and key do not match: ${t.message}`):t}}return $.createServer(e)}async rateLimitMiddleware(e,t){let s=e.req.socket.remoteAddress||"unknown";return e.res.setHeader("X-RateLimit-Limit",this.rateLimiter.getLimit().toString()),e.res.setHeader("X-RateLimit-Remaining",this.rateLimiter.getRemainingRequests(s).toString()),e.res.setHeader("X-RateLimit-Reset",this.rateLimiter.getResetTime(s).toString()),this.rateLimiter.isAllowed(s)?t():{statusCode:429,body:{error:"Too Many Requests",message:"Rate limit exceeded, please try again later"},headers:{"Content-Type":"application/json"}}}async requestHandler(e,t){let s=Date.now(),r=e.method||"UNKNOWN",i=e.url||"/unknown",n=this.config.debug;try{if(this.setCorsHeaders(t,e),this.setSecurityHeaders(t,this.config.useHttps),n&&console.log(`${r} ${i}`),e.method==="OPTIONS"){if(t instanceof $.ServerResponse)t.statusCode=204,t.end();else{let a=t;a.writeHead(204),a.end()}return}try{e.body=await this.parseBody(e)}catch(a){return n&&console.error("Body parsing error:",a.message),this.respond(t,{statusCode:400,body:{error:"Bad Request",message:a.message}})}let o=await this.router.handle(e,t);return o?o._handled?void 0:this.respond(t,o):this.respond(t,{statusCode:404,body:{error:"Not Found",message:"The requested endpoint does not exist"}})}catch(o){return console.error("Server error:",o),this.respond(t,{statusCode:500,body:{error:"Internal Server Error",message:n?o.message:"An unexpected error occurred"}})}finally{n&&this.logDuration(s,r,i)}}logDuration(e,t,s){let r=Date.now()-e;console.log(`${t} ${s} completed in ${r}ms`)}async parseBody(e){return new Promise((t,s)=>{let r=[],i=0,n=this.config.maxBodySize,o=!1,a=null,l=this.config.debug,d=e.headers["content-type"]||"";l&&console.log("Content-Type:",d),this.config.requestTimeout>0&&(a=setTimeout(()=>{o||(o=!0,l&&console.log("Request timeout exceeded"),s(new Error("Request timeout")))},this.config.requestTimeout));let f=()=>{a&&(clearTimeout(a),a=null)};e.on("data",c=>{if(!o){if(i+=c.length,l&&console.log(`Received chunk: ${c.length} bytes, total size: ${i}`),i>n){o=!0,f(),l&&console.log(`Body size exceeded limit: ${i} > ${n}`),s(new Error("Request body too large"));return}r.push(c)}}),e.on("end",()=>{if(!o){o=!0,f(),l&&console.log(`Request body complete: ${i} bytes`);try{if(r.length>0){let c=Buffer.concat(r);if(d.includes("application/json"))try{let u=c.toString("utf8");t(JSON.parse(u))}catch(u){s(new Error(`Invalid JSON in request body: ${u.message}`))}else if(d.includes("application/x-www-form-urlencoded")){let u=c.toString("utf8"),y={};new URLSearchParams(u).forEach((w,b)=>{y[b]=w}),t(y)}else if(d.includes("multipart/form-data"))try{let u=z(c,d);t(u)}catch(u){s(new Error(`Invalid multipart form data: ${u.message}`))}else this.isBinaryContentType(d)?t(c):t(c.toString("utf8"))}else t({})}catch(c){s(new Error(`Invalid request body: ${c}`))}}}),e.on("error",c=>{o||(o=!0,f(),s(new Error(`Error reading request body: ${c.message}`)))}),e.on("close",()=>{f()})})}isBinaryContentType(e){return["application/octet-stream","application/pdf","application/zip","application/gzip","application/x-tar","application/x-rar-compressed","application/x-7z-compressed","image/","video/","audio/","application/vnd.ms-excel","application/vnd.openxmlformats-officedocument","application/msword","application/vnd.ms-powerpoint"].some(s=>e.includes(s))}setCorsHeaders(e,t){let s=t.headers.origin,{allowedDomains:r=["*"]}=this.config;!s||r.length===0||r.includes("*")?e.setHeader("Access-Control-Allow-Origin","*"):r.includes(s)&&(e.setHeader("Access-Control-Allow-Origin",s),e.setHeader("Vary","Origin")),e.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, PATCH, OPTIONS"),e.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),e.setHeader("Access-Control-Max-Age","86400")}setSecurityHeaders(e,t=!1){let s={"X-Content-Type-Options":"nosniff","X-Frame-Options":"DENY","Content-Security-Policy":"default-src 'self'; script-src 'self'; object-src 'none'","X-XSS-Protection":"1; mode=block"};if((t||this.config.useHttp2)&&(s["Strict-Transport-Security"]="max-age=31536000; includeSubDomains"),e instanceof $.ServerResponse)Object.entries(s).forEach(([r,i])=>{e.setHeader(r,i)});else{let r=e;Object.entries(s).forEach(([i,n])=>{r.setHeader(i,n)})}}respond(e,t){let s={...t.headers||{}};(i=>typeof i.writeHead=="function"&&typeof i.end=="function")(e)?(e.writeHead(t.statusCode,s),t.body===null||t.body===void 0?e.end():t.isRaw||typeof t.body=="string"?e.end(t.body):e.end(JSON.stringify(t.body))):(console.warn("Unexpected response object type without writeHead/end methods"),e.writeHead?.(t.statusCode,s),t.body===null||t.body===void 0?e.end?.():t.isRaw||typeof t.body=="string"?e.end?.(t.body):e.end?.(JSON.stringify(t.body)))}setupGracefulShutdown(e){let t=o=>{console.log("Shutting down MikroServe server..."),o&&console.error("Error:",o),this.cleanupShutdownHandlers(),e.close(()=>{console.log("Server closed successfully"),process.env.NODE_ENV!=="test"&&process.env.VITEST!=="true"&&setImmediate(()=>process.exit(o?1:0))})},s=()=>t(),r=()=>t(),i=o=>t(o),n=o=>t(o);this.shutdownHandlers=[s,r,i,n],process.on("SIGINT",s),process.on("SIGTERM",r),process.on("uncaughtException",i),process.on("unhandledRejection",n)}cleanupShutdownHandlers(){if(this.shutdownHandlers.length>0){let[e,t,s,r]=this.shutdownHandlers;process.removeListener("SIGINT",e),process.removeListener("SIGTERM",t),process.removeListener("uncaughtException",s),process.removeListener("unhandledRejection",r),this.shutdownHandlers=[]}}};function P(e){if(!e.deflate&&!e.inflate)throw new Error("Dictionary must provide either deflate or inflate mapping");if(e.deflate&&e.inflate)throw new Error("Dictionary should provide only one of deflate or inflate (not both). The inverse will be auto-generated.");return e.deflate?{deflate:e.deflate,inflate:F(e.deflate)}:{deflate:F(e.inflate),inflate:e.inflate}}function F(e){let t={};for(let[s,r]of Object.entries(e))t[r]=s;return t}function T(e,t){if(e==null||typeof e!="object")return e;if(Array.isArray(e))return e.map(r=>T(r,t));let s={};for(let[r,i]of Object.entries(e)){let n=t[r]||r;s[n]=T(i,t)}return s}function C(e){if(!e||typeof e!="string")throw new Error("Table name must be a non-empty string");if(e.length>255)throw new Error("Table name must not exceed 255 characters");if(e.includes("/")||e.includes("\\"))throw new Error("Table name must not contain path separators");if(e.includes(".."))throw new Error('Table name must not contain ".."');if(e.startsWith("."))throw new Error('Table name must not start with "."');if(e.includes("\0"))throw new Error("Table name must not contain null bytes");if(["CON","PRN","AUX","NUL","COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9"].includes(e.toUpperCase()))throw new Error(`Table name "${e}" is reserved by the filesystem`)}function R(e){if(e==null)throw new Error("Key must be defined");if(typeof e!="string")throw new Error("Key must be a string");if(e.length===0)throw new Error("Key must not be empty");if(e.length>1024)throw new Error("Key must not exceed 1024 characters");if(e.includes("\0"))throw new Error("Key must not contain null bytes")}function B(e){if(e===void 0)throw new Error("Value must not be undefined (use null instead)");let t=typeof e;if(t==="function")throw new Error("Value must be JSON-serializable: functions are not supported");if(t==="symbol")throw new Error("Value must be JSON-serializable: symbols are not supported");try{if(JSON.stringify(e)===void 0)throw new Error("Value must be JSON-serializable: value cannot be serialized")}catch(s){throw new Error(`Value must be JSON-serializable: ${s instanceof Error?s.message:String(s)}`)}}import{existsSync as L,mkdirSync as we,readdirSync as ve,openSync as Ce,closeSync as Se}from"fs";import{readFile as Te,writeFile as xe,rename as Ee,unlink as U,open as Pe}from"fs/promises";import{join as H,dirname as Re}from"path";var V=class{data=new Map;databaseDirectory;dictionaries=new Map;useFsync;constructor(e){this.databaseDirectory=e.databaseDirectory,this.useFsync=e.durableWrites??!1,e.dictionaries&&Object.entries(e.dictionaries).forEach(([t,s])=>{let r=P(s);this.dictionaries.set(t,r)}),L(this.databaseDirectory)||we(this.databaseDirectory,{recursive:!0})}async start(){try{let e=ve(this.databaseDirectory);for(let t of e)!t.endsWith(".tmp")&&!t.startsWith(".")&&await this.loadTable(t)}catch(e){throw console.error("Failed to start database:",e),e}}async write(e,t,s,r,i){if(C(e),R(t),B(s),i&&!this.dictionaries.has(i))throw new Error(`Dictionary "${i}" not found. Available dictionaries: ${Array.from(this.dictionaries.keys()).join(", ")||"none"}`);try{this.data.has(e)||this.data.set(e,new Map);let n=this.data.get(e),a=(n.get(t)?.version||0)+1,l={value:s,version:a,timestamp:Date.now(),expiration:r||null,dictionaryName:i||void 0};return n.set(t,l),await this.persistTable(e),!0}catch(n){return console.error(`Write failed for ${e}:${t}:`,n),!1}}async get(e,t){C(e),t!==void 0&&R(t);try{this.data.has(e)||await this.loadTable(e);let s=this.data.get(e);if(!s)return t?void 0:[];if(t!==void 0){let n=s.get(t);if(!n)return;if(this.isExpired(n)){s.delete(t),await this.persistTable(e);return}return n.value}let r=[],i=[];for(let[n,o]of s.entries())this.isExpired(o)?i.push(n):r.push([n,o.value]);if(i.length>0){for(let n of i)s.delete(n);await this.persistTable(e)}return r}catch(s){return console.error(`Read failed for ${e}:${t}:`,s),t?void 0:[]}}async delete(e,t){C(e),R(t);try{this.data.has(e)||await this.loadTable(e);let s=this.data.get(e);if(!s||!s.has(t))return!1;let r=s.get(t);return r?this.isExpired(r)?(s.delete(t),await this.persistTable(e),!1):(s.delete(t),await this.persistTable(e),!0):!1}catch(s){return console.error(`Delete failed for ${e}:${t}:`,s),!1}}async getTableSize(e){C(e);try{this.data.has(e)||await this.loadTable(e);let t=this.data.get(e);if(!t)return 0;let s=0,r=[];for(let[i,n]of t.entries())this.isExpired(n)?r.push(i):s++;if(r.length>0){for(let i of r)t.delete(i);await this.persistTable(e)}return s}catch(t){return console.error(`Get table size failed for ${e}:`,t),0}}isExpired(e){return e.expiration===null?!1:Date.now()>e.expiration}async cleanupExpired(e){C(e);try{this.data.has(e)||await this.loadTable(e);let t=this.data.get(e);if(!t)return 0;let s=[];for(let[r,i]of t.entries())this.isExpired(i)&&s.push(r);for(let r of s)t.delete(r);return s.length>0&&await this.persistTable(e),s.length}catch(t){return console.error(`Cleanup failed for ${e}:`,t),0}}async cleanupAllExpired(){let e=0;for(let t of this.data.keys())e+=await this.cleanupExpired(t);return e}async deleteTable(e){C(e);try{this.data.delete(e);let t=H(this.databaseDirectory,e);return L(t)&&await U(t),!0}catch(t){return console.error(`Delete table failed for ${e}:`,t),!1}}listTables(){return Array.from(this.data.keys())}async flush(){try{let e=Array.from(this.data.keys()).map(t=>this.persistTable(t));await Promise.all(e)}catch(e){throw console.error("Flush failed:",e),e}}async close(){await this.flush()}addDictionary(e,t){let s=P(t);this.dictionaries.set(e,s)}removeDictionary(e){return this.dictionaries.delete(e)}listDictionaries(){return Array.from(this.dictionaries.keys())}async loadTable(e){let t=H(this.databaseDirectory,e);if(!L(t)){this.data.set(e,new Map);return}try{let s=await Te(t);if(s.length===0){this.data.set(e,new Map);return}let r=this.deserializeTable(s);this.data.set(e,r)}catch(s){console.error(`Failed to load table ${e}:`,s),this.data.set(e,new Map)}}async persistTable(e){let t=this.data.get(e);if(!t)return;let s=this.serializeTable(t),r=H(this.databaseDirectory,e),i=`${r}.tmp.${Date.now()}.${Math.random().toString(36).substring(7)}`;try{if(await xe(i,s),this.useFsync){let n=await Pe(i,"r+");try{await n.sync()}finally{await n.close()}}if(await Ee(i,r),this.useFsync){let n=Re(r),o=Ce(n,"r");try{Se(o)}catch{}}}catch(n){try{await U(i)}catch{}throw n}}serializeTable(e){let t=Array.from(e.entries()).map(([s,r])=>{let i=r.dictionaryName?this.dictionaries.get(r.dictionaryName):void 0,n={d:i?T(r.value,i.deflate):r.value,v:r.version,t:r.timestamp,x:r.expiration};return r.dictionaryName&&(n.n=r.dictionaryName),[s,n]});return Buffer.from(JSON.stringify(t),"utf8")}deserializeTable(e){let s=JSON.parse(e.toString("utf8")).map(([r,i])=>{let n=i.n,o=n?this.dictionaries.get(n):void 0;return[r,{value:o?T(i.d,o.inflate):i.d,version:i.v,timestamp:i.t,expiration:i.x,dictionaryName:n||void 0}]});return new Map(s)}};import{join as de}from"node:path";import{statSync as ze}from"node:fs";var m=class{isSilent;propertyPath="";constructor(e=!1){this.isSilent=e}test(e,t){if(!t)throw new Error("Missing input!");this.updatePropertyPath();let{results:s,errors:r}=this.validate(e.properties,t),i=this.compileErrors(s,r),n=this.isSuccessful(s,i);return{errors:i,success:n}}compileErrors(e,t){let s=e.filter(r=>r.success===!1);return[...t,...s].flatMap(r=>r)}isSuccessful(e,t){return e.every(s=>s.success===!0)&&t.length===0}validate(e,t,s=[],r=[]){let i=e?.additionalProperties??!0,n=e?.required||[];r=this.checkForRequiredKeysErrors(n,t,r),r=this.checkForDisallowedProperties(Object.keys(t),Object.keys(e),r,i);for(let o in e){let a=n.includes(o)&&o!=="required",l=e[o],d=t[o],f=l.additionalProperties??!0;a&&(r=this.checkForRequiredKeysErrors(l.required||[],d,r)),this.isDefined(d)&&(this.handleValidation(o,d,l,s),r=this.checkForDisallowedProperties(Object.keys(d),Object.keys(l),r,f),this.handleNestedObject(d,l,s,r))}return{results:s,errors:r}}updatePropertyPath(e,t=""){if(!e){this.propertyPath="";return}t&&(this.propertyPath=t),this.propertyPath=`${this.propertyPath}.${e}`,this.propertyPath.startsWith(".")&&(this.propertyPath=this.propertyPath.substring(1,this.propertyPath.length))}isDefined(e){return!!(typeof e=="number"&&e===0||e||e===""||typeof e=="boolean")}checkForRequiredKeysErrors(e,t,s){if(!this.areRequiredKeysPresent(e,t)){let r=t?Object.keys(t):[],i=this.findNonOverlappingElements(e,r),n=i.length>0?`Missing the required key: '${i.join(", ")}'!`:`Missing values for required keys: '${r.filter(o=>!t[o]).join(", ")}'!`;s.push({key:"",value:t,success:!1,error:n})}return s}checkForDisallowedProperties(e,t,s,r){if(!r){let i=this.findNonOverlappingElements(e,t);i.length>0&&s.push({key:`${t}`,value:e,success:!1,error:`Has additional (disallowed) properties: '${i.join(", ")}'!`})}return s}handleValidation(e,t,s,r){this.updatePropertyPath(e);let i=this.validateProperty(this.propertyPath,s,t);r.push(...i);let n=(a,l)=>{a.forEach(d=>{let f=this.validateProperty(this.propertyPath,l.items,d);r.push(...f)}),this.updatePropertyPath()},o=a=>{let l=Object.keys(a),d=this.propertyPath;l.forEach(f=>{if(this.updatePropertyPath(f,d),this.isArray(a[f])&&s[f]?.items!=null)n(a[f],s[f]);else{let c=this.validateProperty(this.propertyPath,s[f],a[f]);r.push(...c)}})};this.isArray(t)&&s.items!=null?n(t,s):this.isObject(t)?o(t):this.updatePropertyPath()}handleNestedObject(e,t,s,r){if(this.isObject(e)){let i=this.getNestedObjects(e);for(let n of i){let o=t[n],a=e[n];o&&typeof a=="object"&&this.validate(o,a,s,r)}}}getNestedObjects(e){return Object.keys(e).filter(t=>{if(this.isObject(e))return t})}findNonOverlappingElements(e,t){return e.filter(s=>!t.includes(s))}areRequiredKeysPresent(e,t=[]){return e.every(s=>Object.keys(t).includes(s)?this.isDefined(t[s]):!1)}validateProperty(e,t,s){return this.validateInput(t,s).map(i=>{let{success:n,error:o}=i;return{key:e,value:s,success:n,error:o??""}})}validateInput(e,t){if(e){let s=[{condition:()=>e.type,validator:()=>this.isCorrectType(e.type,t),error:"Invalid type"},{condition:()=>e.format,validator:()=>this.isCorrectFormat(e.format,t),error:"Invalid format"},{condition:()=>e.minLength,validator:()=>this.isMinimumLength(e.minLength,t),error:"Length too short"},{condition:()=>e.maxLength,validator:()=>this.isMaximumLength(e.maxLength,t),error:"Length too long"},{condition:()=>e.minValue,validator:()=>this.isMinimumValue(e.minValue,t),error:"Value too small"},{condition:()=>e.maxValue,validator:()=>this.isMaximumValue(e.maxValue,t),error:"Value too large"},{condition:()=>e.matchesPattern,validator:()=>this.matchesPattern(e.matchesPattern,t),error:"Pattern does not match"}],r=[];for(let i of s)i.condition()&&!i.validator()&&r.push({success:!1,error:i.error});return r}else this.isSilent||console.warn(`Missing property '${e}' for match '${t}'. Skipping...`);return[{success:!0}]}isCorrectType(e,t){return Array.isArray(e)||(e=[e]),e.some(s=>{switch(s){case"string":return typeof t=="string";case"number":return typeof t=="number"&&!isNaN(t);case"boolean":return typeof t=="boolean";case"object":return this.isObject(t);case"array":return this.isArray(t)}})}isObject(e){return e!==null&&!this.isArray(e)&&typeof e=="object"&&e instanceof Object&&Object.prototype.toString.call(e)==="[object Object]"}isArray(e){return Array.isArray(e)}isCorrectFormat(e,t){switch(e){case"alphanumeric":return new RegExp(/^[a-zA-Z0-9]+$/).test(t);case"numeric":return new RegExp(/^-?\d+(\.\d+)?$/).test(t);case"email":return new RegExp(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/).test(t);case"date":return new RegExp(/^\d{4}-\d{2}-\d{2}$/).test(t);case"url":return new RegExp(/^(https?):\/\/[^\s$.?#].[^\s]*$/).test(t);case"hexColor":return new RegExp(/^#?([a-f0-9]{6}|[a-f0-9]{3})$/i).test(t)}}isMinimumLength(e,t){return Array.isArray(t)?t.length>=e:t?.toString().length>=e}isMaximumLength(e,t){return Array.isArray(t)?t.length<=e:t.toString().length<=e}isMinimumValue(e,t){return t>=e}isMaximumValue(e,t){return t<=e}matchesPattern(e,t){return new RegExp(e).test(t)}schemaFrom(e){let t={properties:{additionalProperties:!1,required:[]}};for(let s in e){let r=e[s];t.properties.required.push(s),Array.isArray(r)?t.properties[s]=this.generateArraySchema(r):typeof r=="object"&&r!==null?t.properties[s]=this.generateNestedObjectSchema(r):t.properties[s]=this.generatePropertySchema(r)}return t}generateArraySchema(e){let t={type:"array"},s=e.filter(r=>r);if(s.length>0){let r=s[0];s.every(n=>typeof n==typeof r)?typeof r=="object"&&!Array.isArray(r)?t.items=this.generateNestedObjectSchema(r):t.items=this.generatePropertySchema(r):console.warn("All elements in array are not of the same type. Unable to generate a schema for these elements.")}return t}generateNestedObjectSchema(e){let t={type:"object",additionalProperties:!1,required:[]};for(let s in e){let r=e[s];t.required.push(s),typeof r=="object"&&!Array.isArray(r)&&r!==null?t[s]=this.generateNestedObjectSchema(r):t[s]=this.generatePropertySchema(r)}return t}generatePropertySchema(e){let t=typeof e,s={type:t};return t==="string"&&(s.minLength=1),s}};async function j(e){return e.body||{}}function h(e,t="An error occurred"){let s=e?.message||e||t,r=e?.cause?.statusCode||e?.statusCode||400;return{message:s,status:r}}function G(e,t,s={}){let r=Array.isArray(t)?t:[t];if(!e||!e.roles||!Array.isArray(e.roles)){let o=new Error("Unauthorized: User or roles missing");throw o.cause={statusCode:403},o}let i=e.roles.flatMap(o=>o?.policies?.flatMap(a=>(a?.permissions||[]).flatMap(d=>typeof d=="string"?d:d&&typeof d=="object"&&d.actions?d.actions:[]))||[]);if(!r.every(o=>i.includes(o)||i.includes("*")?!0:i.some(a=>{if(a.endsWith(".*")){let l=a.slice(0,-2);return o.startsWith(`${l}.`)}return!1}))){let o=new Error("Unauthorized");throw o.cause={statusCode:403},o}return!0}function W(e,t,s,r,i){let n=e.find(l=>l.service===t);if(!n){let l=new Error(`Function bindings do not include access to service: ${t}`);throw l.cause={statusCode:403},l}if(!n.permissions||n.permissions.length===0)return;for(let l of n.permissions)if(!(l.resource&&l.resource!==s)){if(!l.resource||!l.actions||l.actions.length===0)return;if(l.actions.includes(r)){if(l.targets&&l.targets.length>0){if(!i)return;if(!l.targets.includes(i))continue}return}}let o=i?`:${i}`:"",a=new Error(`Function bindings do not allow: ${t}.${s}.${r}${o}`);throw a.cause={statusCode:403},a}async function p(e,t,s,r,i,n,o){if(!t)return null;let a=e.state.user;if(!a){let d=e.headers.authorization;if(!d){let c=new Error("Unauthorized: No authentication provided");throw c.cause={statusCode:401},c}let f=d.replace(/^Bearer\s+/i,"");if(a=await t.getUserFromToken(f),!a){let c=new Error("Unauthorized: Invalid token");throw c.cause={statusCode:401},c}}G(a,s,{});let l=e.headers["x-function-bindings"];if(l)try{let d=Array.isArray(l)?l[0]:l,f=JSON.parse(d);W(f,r,i,n,o)}catch(d){if(d.cause?.statusCode===403)throw d;let f=new Error("Invalid function bindings header");throw f.cause={statusCode:400},f}return a}var J={properties:{tableName:{type:"string",minLength:1},key:{type:"string"}},required:["tableName"],additionalProperties:!1};var Me=new m;async function _(e,t,s){try{let r=await j(e),i=Me.test(J,r);if(!i.success)return e.json({error:"Invalid input",details:i.errors},400);let{tableName:n,key:o}=r;if(!n)return e.json("tableName is required",400);await p(e,s,"databases.table.get","databases","table","read",n);let a=await t.get(n,o);return a===void 0?e.json(null,404):e.json(a,200)}catch(r){let{message:i,status:n}=h(r,"Error getting table data");return e.json({error:i},n)}}var K={properties:{tableName:{type:"string",minLength:1},key:{type:"string"},value:{},expiration:{type:"number"},dictionaryName:{type:"string"}},required:["tableName"],additionalProperties:!1};var Oe=new m;async function X(e,t,s){try{let r=await j(e),i=Oe.test(K,r);if(!i.success)return e.json({error:"Invalid input",details:i.errors},400);let{tableName:n,key:o,value:a,expiration:l,dictionaryName:d}=r;if(!n||a===void 0)return e.json("tableName and value are required",400);await p(e,s,"databases.table.update","databases","table","write",n);let f=await t.write(n,o,a,l,d);return e.json(f,200)}catch(r){let{message:i,status:n}=h(r,"Error writing table data");return e.json({error:i},n)}}var Z={properties:{tableName:{type:"string",minLength:1},key:{type:"string",minLength:1}},required:["tableName","key"],additionalProperties:!1};var $e=new m;async function Y(e,t,s){try{let r=$e.test(Z,e.query);if(!r.success)return e.json({error:"Invalid input",details:r.errors},400);let{tableName:i,key:n}=e.query;if(!i||!n)return e.json("tableName and key are required",400);await p(e,s,"databases.table.delete","databases","table","delete",i);let o=await t.delete(i,n);return e.json(o,200)}catch(r){let{message:i,status:n}=h(r,"Error deleting table item");return e.json({error:i},n)}}async function Q(e,t,s,r,i,n){try{await p(e,s,"databases.table.get","databases","table","read");let o=t.listTables(),a=await Promise.all(o.map(async l=>{let d=await t.getTableSize(l),f=i(r,l);return{name:l,items:d,size:n(f)}}));return e.json({tables:a},200)}catch(o){let{message:a,status:l}=h(o,"Error listing tables");return e.json({error:a},l)}}var v={properties:{tableName:{type:"string",minLength:1}},required:["tableName"],additionalProperties:!1};var Le=new m;async function ee(e,t,s){try{let r=e.params.tableName;if(!r)return e.json({error:"tableName is required"},400);let i=Le.test(v,{tableName:r});return i.success?(await p(e,s,"databases.table.create","databases","table","create",r),t.listTables().includes(r)?e.json({error:"Table already exists"},409):(await t.write(r,"__init__",null),await t.delete(r,"__init__"),e.json({success:!0,name:r,message:"Table created successfully"},201))):e.json({error:"Invalid input",details:i.errors},400)}catch(r){let{message:i,status:n}=h(r,"Error creating table");return e.json({error:i},n)}}var He=new m;async function te(e,t,s){try{let r=e.params.tableName;if(!r)return e.json({error:"tableName is required"},400);let i=He.test(v,{tableName:r});if(!i.success)return e.json({error:"Invalid input",details:i.errors},400);if(await p(e,s,"databases.table.delete","databases","table","delete",r),!t.listTables().includes(r))return e.json({error:"Table not found"},404);let o=await t.deleteTable(r);return e.json({success:o,name:r,message:"Table deleted successfully"},200)}catch(r){let{message:i,status:n}=h(r,"Error deleting table");return e.json({error:i},n)}}var Ve=new m;async function re(e,t,s,r,i,n){try{let o=e.params.tableName;if(!o)return e.json({error:"tableName is required"},400);let a=Ve.test(v,{tableName:o});if(!a.success)return e.json({error:"Invalid input",details:a.errors},400);if(await p(e,s,"databases.table.get","databases","table","read",o),!t.listTables().includes(o))return e.json({error:"Table not found"},404);let d=await t.getTableSize(o),f=i(r,o);return e.json({name:o,items:d,size:n(f)},200)}catch(o){let{message:a,status:l}=h(o,"Error getting table info");return e.json({error:a},l)}}async function se(e,t,s){try{if(!e.query.tableName)return e.json({error:"tableName is required"},400);let{tableName:r}=e.query;await p(e,s,"databases.table.get","databases","table","read",r);let i=await t.get(r),n=i?i.length:0;return e.json(n,200)}catch(r){let{message:i,status:n}=h(r,"Error getting table size");return e.json({error:i},n)}}var Ne=new m;async function ie(e,t,s){try{let r=e.params.tableName;if(!r)return e.json({error:"tableName is required"},400);let i=Ne.test(v,{tableName:r});if(!i.success)return e.json({error:"Invalid input",details:i.errors},400);if(await p(e,s,"databases.table.get","databases","table","read",r),!t.listTables().includes(r))return e.json({error:"Table not found"},404);let o=await t.get(r),a=o?Object.entries(o).map(([l,d])=>Array.isArray(d)&&d.length===2?{key:d[0],value:d[1]}:{key:l,value:d}):[];return e.json({items:a},200)}catch(r){let{message:i,status:n}=h(r,"Error getting table items");return e.json({error:i},n)}}import{readFileSync as De,existsSync as qe}from"node:fs";function x(){let e=process.env.MOLNOS_RUNTIME_CONFIG,t={molnos:{dataPath:"data",rateLimit:{global:{enabled:!1,requestsPerMinute:0}},signedUrlSecret:"molnos-default-signed-url-secret"},server:{host:"127.0.0.1",port:3e3},identity:{apiUrl:""},services:{storage:{host:"127.0.0.1",port:3001,url:"http://127.0.0.1:3001"},functions:{host:"127.0.0.1",port:3002,url:"http://127.0.0.1:3002"},sites:{host:"127.0.0.1",port:3003,url:"http://127.0.0.1:3003"},databases:{host:"127.0.0.1",port:3004,url:"http://127.0.0.1:3004"},observability:{host:"127.0.0.1",port:3005,url:"http://127.0.0.1:3005"}}};if(!e||!qe(e))return t;try{let s=De(e,"utf-8");return JSON.parse(s)}catch(s){return console.error("[loadRuntimeConfig] Failed to load runtime config:",s),t}}function oe(e,t){let s={enabled:!1,requestsPerMinute:0};if(!t)return s;let r=t.services?.[e];return r||(t.global?t.global:s)}function ne(e,t){let s=e?.api?.port;if(!s)throw new Error('Missing "port" input when create API service!');let r=x(),i=e?.dataPath||r.molnos.dataPath,n=e?.api?.host||r.server.host,o=e?.identityApiUrl!==void 0?e.identityApiUrl:r.identity.apiUrl,a=e?.debug||!1,l;return t&&(l=oe(t,r.molnos.rateLimit)),{dataPath:i,api:{port:s,host:n},...o?{identityApiUrl:o}:{},...l?{rateLimit:l}:{},debug:a}}var M=class{baseUrl;authToken;constructor(t,s){this.baseUrl=t.replace(/\/$/,""),this.authToken=s}async createCustomRole(t,s,r,i){let n=await fetch(`${this.baseUrl}/identity/roles`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({roleId:t,name:s,description:r,permissions:i})});if(!n.ok){let o=`Failed to create role: ${n.statusText}`;try{o=(await n.json()).error||o}catch{o=await n.text().catch(()=>n.statusText)||o}throw new Error(o)}}async updateRole(t,s){let r=await fetch(`${this.baseUrl}/identity/roles/${t}`,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify(s)});if(!r.ok){let i=await r.json();throw new Error(i.error||`Failed to update role: ${r.statusText}`)}}async deleteRole(t){let s=await fetch(`${this.baseUrl}/identity/roles/${t}`,{method:"DELETE",headers:this.getHeaders()});if(!s.ok){let r=await s.json();throw new Error(r.error||`Failed to delete role: ${s.statusText}`)}}async addServiceAccount(t,s,r){let i=await fetch(`${this.baseUrl}/identity/service-accounts`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({name:t,description:s,roles:r})});if(!i.ok){let o=`Failed to create service account: ${i.statusText}`;try{o=(await i.json()).error||o}catch{o=await i.text().catch(()=>i.statusText)||o}throw new Error(o)}let n=await i.json();return{id:n.id,apiKey:n.apiKey}}async deleteIdentity(t){let s=await fetch(`${this.baseUrl}/identity/service-accounts/${t}`,{method:"DELETE",headers:this.getHeaders()});if(!s.ok){let r=await s.json();throw new Error(r.error||`Failed to delete service account: ${s.statusText}`)}}async getUserFromToken(t){try{let s=await fetch(`${this.baseUrl}/identity/whoami`,{method:"GET",headers:{Authorization:`Bearer ${t}`}});return s.ok?await s.json():null}catch{return null}}getHeaders(){let t={"Content-Type":"application/json"};return this.authToken&&(t.Authorization=`Bearer ${this.authToken}`),t}};function ae(e){return e?new M(e):null}function le(e){if(e===0)return"0 B";let t=["B","KB","MB","GB"],s=Math.floor(Math.log(e)/Math.log(1024));return`${(e/1024**s).toFixed(1)} ${t[s]}`}function ce(e,t){try{let s=de(e,t);return ze(s).size}catch{return 0}}async function Fe(e){let t=e.dataPath||"data",s=de(t,"databases"),r=new V({databaseDirectory:s});await r.start();let i=ae(e.identityApiUrl),n=x(),o=new k({port:e.api.port||n.services.databases.port,host:e.api.host||n.services.databases.host,rateLimit:e.rateLimit||n.molnos.rateLimit.global});return o.get("/table",async l=>se(l,r,i)),o.post("/get",async l=>_(l,r,i)),o.post("/write",async l=>X(l,r,i)),o.delete("/delete",async l=>Y(l,r,i)),o.get("/tables",async l=>Q(l,r,i,s,ce,le)),o.post("/tables/:tableName",async l=>ee(l,r,i)),o.delete("/tables/:tableName",async l=>te(l,r,i)),o.get("/tables/:tableName",async l=>re(l,r,i,s,ce,le)),o.get("/tables/:tableName/items",async l=>ie(l,r,i)),o.start()}if(import.meta.url===`file://${process.argv[1]}`){let e=x(),s=process.argv.slice(2).find(n=>n.startsWith("--port=")),r=s?parseInt(s.split("=")[1],10):e.services.databases.port,i=ne({api:{port:r}},"databases");Fe(i)}export{Fe as startServer};